//
  // FindOrigin
  //
  // Returns the lower left corner in terrain space
  //
  void Placement::FindOrigin(const Matrix &location, WorldCtrl::CompassDir d, Point<S32> &o)
  {
    ASSERT(IsSetup());

    S32 x = 0, z = 0;
    Vector pos;

    // Which vert is bottom left in terrain space
    switch (d)
    {
      case WorldCtrl::EAST:
        x = type->Size().x;
        break;

      case WorldCtrl::SOUTH:
        x = type->Size().x;
        z = type->Size().z;
        break;

      case WorldCtrl::WEST:
        z = type->Size().z;
        break;
    }     

    // Get the world position of the first shadow vertex
    type->GetVertexPosition(pos, location, x, z);

    // Get the closest cell point is within
    Terrain::CellCoords
    (
      pos.x + WorldCtrl::CellSize() / 2, pos.z + WorldCtrl::CellSize() / 2, o.x, o.z
    );
  }
  //
  // Reset
  //
  // Set default values in all cells
  //
  void Placement::Reset()
  {
    ASSERT(IsSetup());

    for (S32 z = 0; z < size.z; z++)
    {
      for (S32 x = 0; x < size.x; x++)
      {
        // Get the required cell
        Cell &cell = GetCell(x, z);

        // Does this cell lie on the footprint
        cell.onFoot = ((x > 0) && (x < size.x - 1) && (z > 0) && (z < size.z - 1));

        // Set default data
        cell.result = PR_NONE;
        cell.map.Set(0, 0);
        cell.zip.Set(-1, -1);
        cell.type.Set(x - 1, z - 1);
      }
    }   

    // Reset best height
    thumpHeight = 0.0F;
  }
  //
  // AdjustLocation
  //
  // Adjust the given origin location to be correct for this footprint
  //
  void Placement::AdjustLocation(Matrix &location)
  {
    ASSERT(IsSetup());

    Vector pos;
    S32 cellX, cellZ;

    // Snap rotation
    WorldCtrl::SnapRotation(location);

    // Get the world position of the first shadow vertex
    type->GetVertexPosition(pos, location, 0, 0);
    
    // Get the closest cell point is within
    Terrain::CellCoords
    (
      pos.x + WorldCtrl::CellSize() / 2,
      pos.z + WorldCtrl::CellSize() / 2,
      cellX, cellZ
    );

    // Adjust the object matrix using the delta from shadow vertex
    location.posit.x += (F32)(cellX * WC_CELLSIZE) - pos.x;
    location.posit.z += (F32)(cellZ * WC_CELLSIZE) - pos.z;
  }
// Load a sample into the cache for a specific move event
SampleID SokobanSoundManager::CacheSampleFromFile(MoveEvent EventType, string FileName)
{
	// error check
	if(!IsSetup()) return false;

	// Create an AL buffer from the given sound file
	ALuint buffer = _CacheSampleFromFile(FileName);

	// Add it to the cache
	m_MoveEventSounds.push_back(SoundEvent(EventType.Type, buffer));

	// Return the reference to the caller
	return buffer;
}
  //
  // Done
  //
  // Shutdown if setup (called from destructor)
  //
  void Placement::Done()
  {
    // Reset last check result
    result = PR_NONE;

    // Delete data if currently setup
    if (IsSetup())
    {
      delete [] array;
      type = NULL;
    }

    // Release thumped data
    thumped.Done();
  }
// play a sample from a sound id
void SokobanSoundManager::PlaySample(SampleID _SampleID)
{
	// error check
	if(!IsSetup()) return;

	ALenum error;

	// clear errors
	alGetError();

	// if the source is in use then the new sound takes priorty
	ALint status;
	alGetSourcei (source, AL_SOURCE_STATE, &status);
	if (status == AL_PLAYING)
	{
		// stop the current sound playing
		alSourceStop(source);
	}

	// attach the buffer to it and start playing.
	alSourcei (source, AL_BUFFER, _SampleID);

	// Normally nothing should go wrong above, but one never knows...
	error = alGetError ();
	if (error != ALUT_ERROR_NO_ERROR)
	{
		// fprintf (stderr, "%s\n", alGetString (error));
		MessageBox (HWND_DESKTOP, alGetString(error), "Error Attaching Buffer", MB_OK | MB_ICONEXCLAMATION);
		alutExit ();
		exit (EXIT_FAILURE);
	}

	alSourcePlay (source);
	// Normally nothing should go wrong above, but one never knows...
	error = alGetError ();
	if (error != ALUT_ERROR_NO_ERROR)
	{
		//	fprintf (stderr, "%s\n", alGetString (error));
		MessageBox (HWND_DESKTOP, alGetString(error), "Error Playing Buffer", MB_OK | MB_ICONEXCLAMATION);
		alutExit ();
		exit (EXIT_FAILURE);
	}

	// add to list of active sounds
	//m_ActiveSounds.push_back(source);

	return;
}
  //
  // LogSource
  //
  // For debugging, logs source info
  //
  void FileSrcStream::LogSource(U32 indent)
  {
    ASSERT(IsSetup());

    // Generate the indent
    String iStr;
    iStr.Fill(indent, ' ');

    if (HaveTarget())
    {
      target->LogAllSources(indent);
    }
    else
    {
      LOG_DIAG(("%sDEAD STREAM", *iStr)); 
    }
  }
// Load a sample into the cache
SampleID SokobanSoundManager::_CacheSampleFromFile(string FileName)
{
	// error check
	if(!IsSetup()) return false;

	// Create an AL buffer from the given FileName
	ALuint buffer = m_SoundCache.LoadSample(FileName);

	// error check
	if (buffer == AL_NONE)
	{
		// error loading, no need to quit just use default sound
		return m_DefaultSoundID;
	}

	return buffer;
}
bool MythProgramInfo::HasFanart() const
{
    if (IsSetup() && (m_flags & FLAGS_HAS_FANART))
        return true;
    return false;
}
bool MythProgramInfo::HasCoverart() const
{
    if (IsSetup() && (m_flags & FLAGS_HAS_COVERART))
        return true;
    return false;
}
bool MythProgramInfo::IsLiveTV() const
{
    if (IsSetup() && (m_flags & FLAGS_IS_LIVETV))
        return true;
    return false;
}
bool MythProgramInfo::IsDeleted() const
{
    if (IsSetup() && (m_flags & FLAGS_IS_DELETED))
        return true;
    return false;
}
bool MythProgramInfo::IsVisible() const
{
    if (IsSetup() && (m_flags & FLAGS_IS_VISIBLE))
        return true;
    return false;
}
  //
  // Check
  //
  // Check if allowed to build at the given location
  //
  Placement::Result Placement::Check(const Matrix &location, U32 flags)
  {
    ASSERT(IsSetup());

    S32 xZip, zZip, xFoot, zFoot;
    S32 xMax, zMax;
    S32 x, z;

    // Reset the array
    Reset();

    // Set default result
    result = PR_OK;

    // Get direction
    dir = WorldCtrl::GetCompassDirection(location.front);

    // Get cell in bottom left corner of footprint
    FindOrigin(location, dir, min);

    // Setup extents using current direction
    SetupMaximums(xMax, zMax, size.x, size.z, dir);

    // Save max point
    max.Set(min.x + xMax - 3, min.z + zMax - 3);

    // Step over footprint in terrain space
    // This loop must occur before the thump simulation, as cell.map has to be set up
    for (z = 0; z < zMax; z++)
    {
      for (x = 0; x < xMax; x++)
      {
        // Convert the terrain offset to footprint offsets
        CalculateOffsets(dir, size.x, size.z, x, z, xZip, zZip, xFoot, zFoot);

        // Get the placement cell at this position
        Cell &cell = GetCell(xFoot, zFoot);

        // Is this a zipping location (not on a lower fringe)
        if (x > 0 && z > 0)
        {
          // Save zipping value, adjusting for fringe
          cell.zip.Set(xZip - 1, zZip - 1);

          ASSERT(cell.zip.x >= 0);
          ASSERT(cell.zip.z >= 0);
        }

        // Get actual terrain cell position
        cell.map.Set(min.x + x - 1, min.z + z - 1);
      }
    }

    // If we are doing a thumping simulation, then thumped.valid is TRUE and the
    // real TerrainData::Cell will be substituted for the thumped version when
    // performing the placement check.
    // Otherwise, the real terrain cell will be used
    if (flags & CHECK_NOTHUMPTEST)
    {
      // Thumped is no longer valid
      thumped.Invalidate();
    }
    else
    {
      // Copy terrain into thumped buffer
      if (thumped.CopyTerrain())
      {
        // Calculate the best height to build at
        thumpHeight = thumped.CalcBestHeight();

        // Thump terrain into the thumped buffer
        ThumpTerrain(thumpHeight, 0.0F, THUMP_TOBUFFER);

        // Update slopes
        thumped.UpdateCells();
      }
    }

    // UnitObjType is used inside the loop
    UnitObjType *unitObjType = Promote::Type<UnitObjType>(&type->GetMapType());

    // Step over footprint in terrain space
    for (z = 0; z < zMax; z++)
    {
      for (x = 0; x < xMax; x++)
      {
        // Default cell result to ok
        Result r = PR_OK;

        // Convert the terrain offset to footprint offsets
        CalculateOffsets(dir, size.x, size.z, x, z, xZip, zZip, xFoot, zFoot);

        // Get the placement cell at this position
        Cell &cell = GetCell(xFoot, zFoot);

        // Is this position on the map
        if (WorldCtrl::CellOnMapNoEdge(cell.map.x, cell.map.z))
        {
          // Get the map cell at this location
          TerrainData::Cell &origCell = TerrainData::GetCell(cell.map.x, cell.map.z);

          // Get the thumped cell at this location
          TerrainData::Cell *thumpCell = thumped.IsValid() ? thumped.GetCell(x, z) : NULL;

          // Is there another footprint at this location
          if (!AvailableInstanceIndex(origCell.footIndex))
          {           
            r = (cell.onFoot) ? PR_FOOTON : PR_FOOTOFF;
          }
          else

          if (!TestThumpArea(cell.map, cell.map))
          {
            r = PR_THUMPING;
          }
          else

          // Is this position on the footprint
          if (cell.onFoot)
          {
            Point<S32> g;
          
            // Convert cell to grain
            WorldCtrl::CellToFirstGrain(cell.map.x, cell.map.z, g.x, g.z);

            // Get the type cell
            Type::Cell &typeCell = GetType().GetCell(cell.type.x, cell.type.z);

            // Probe lower grains
            if (typeCell.GetFlag(Type::CLAIMLO) && ClaimBlock(g, Claim::LAYER_LOWER, flags))
            {
              r = PR_CLAIM;
            }
            else

            // Probe upper grains
            if (typeCell.GetFlag(Type::CLAIMHI) && ClaimBlock(g, Claim::LAYER_UPPER, flags))
            {
              r = PR_CLAIM;
            }
            else

            // Can this object build on this location
            if (!PathSearch::CanMoveToCell(type->GetMapType().GetTractionIndex(type->GetMapType().GetDefaultLayer()), origCell))
            {
              r = PR_CANMOVETO;
            }
            else

            if (thumpCell && !PathSearch::CanMoveToCell(type->GetMapType().GetTractionIndex(type->GetMapType().GetDefaultLayer()), *thumpCell))
            {
              r = PR_CANMOVETO;
            }
            else

            // Is this cell shrouded
            if (!(flags & CHECK_IGNORESHROUD) && team && !Sight::Seen(cell.map.x, cell.map.z, team))
            {
              r = PR_SHROUDED;
            }
          }
          else
          {
            if (unitObjType)
            {
              if (unitObjType->CanBoard())
              {
                // The pathability check is extended to the fringe cells for objects that can have a board manager
                if (!PathSearch::CanMoveToCell(type->GetMapType().GetTractionIndex(type->GetMapType().GetDefaultLayer()), origCell))
                {
                  r = PR_CANMOVETO;
                }
                else

                if (thumpCell && !PathSearch::CanMoveToCell(type->GetMapType().GetTractionIndex(type->GetMapType().GetDefaultLayer()), *thumpCell))
                {
                  r = PR_CANMOVETO;
                }
              }
              else
              {
                // Not allowed to change the pathability state from passabable to impassable
                if (PathSearch::CanMoveToCell(type->GetMapType().GetTractionIndex(type->GetMapType().GetDefaultLayer()), origCell))
                {
                  if (thumpCell && !PathSearch::CanMoveToCell(type->GetMapType().GetTractionIndex(type->GetMapType().GetDefaultLayer()), *thumpCell))
                  {
                    r = PR_CANMOVETO;
                  }
                }
              }
            }
          }
        }
        else
        {
          r = PR_OFFMAP;
        }

        // Save result in cell
        cell.result = r;

        // Save significant results
        if (!Acceptable(r) || result == PR_OK)
        {
          result = r;
        }
      }
    }

    return (result);
  }