#include <d3d8.h>

#include <sstream>

#include ".\GSPlanet.h"
#include ".\GSMenu.h"
#include ".\GSDone.h"
#include ".\GSStar.h"
#include ".\LD.h"
#include ".\random.h"



CGSPlanet::CGSPlanet( Universe::Star* pStar, Universe::Planet* pPlanet, int PlanetIndex ) :
  m_pVisitedStarSystem( pStar ),
  m_pPlanet( pPlanet ),
  m_DisplayOffsetX( 0 ),
  m_DisplayOffsetY( 0 ),
  m_PlanetIndex( PlanetIndex ),
  m_MessageDisplayTime( 0.0f ),
  m_ParticleDelay( 0.0f ),
  m_RoverActive( false ),
  m_ShotDelay( 0.0f ),
  m_pBase( NULL ),
  m_Won( false )
{

  theApp.m_Universe.FetchPlanet( pStar, PlanetIndex, m_Resources );

  random    rngEnemies( pStar->Seed + PlanetIndex );

  bool    hasEnemies = ( rngEnemies.rand( 1000 ) >= 950 );
  if ( hasEnemies )
  {
    int   numEnemies = 5 + rngEnemies.rand( 25 );

    for ( int i = 0; i < numEnemies; ++i )
    {
      Unit    turret;

      turret.m_Type     = LD::UT_ENEMY_TURRET;
      turret.m_X        = rngEnemies.rand( 200 * 40 );
      turret.m_Y        = rngEnemies.rand( 200 * 40 );
      turret.m_Texture  = LD::TEX_TURRET;
      turret.m_Life     = 5;

      if ( !theApp.m_PlayerData.HasDestroyed( pStar, PlanetIndex, turret.m_X, turret.m_Y ) )
      {
        m_Units.push_back( turret );
      }
    }
  }

  if ( theApp.m_Universe.m_pFinalPlanet == &pStar->Planets[PlanetIndex] )
  {
    // the goal!
    Unit    alienBase;

    alienBase.m_Type    = LD::UT_ALIEN_BASE;
    alienBase.m_X       = m_Resources.back().Location.x;
    alienBase.m_Y       = m_Resources.back().Location.y;
    alienBase.m_Texture = LD::TEX_ALIEN_BASE;

    m_Units.push_back( alienBase );

    m_pBase = &m_Units.back();
  }

  Unit    player;

  player.m_Type = LD::UT_PLAYER;
  player.m_X    = 320;
  player.m_Y    = 200;

  m_VehicleCanGoBack  = false;
  m_VehicleSpeed      = 1.0f;
  m_VehicleTurnSpeed  = 1.0f;

  m_Health      = 5;
  player.m_Life = 5;

  m_Shield            = 0.0f;
  m_ShieldMax         = 0.0f;
  if ( theApp.m_PlayerData.HasBought( LD::SI_MAX_SHIELD ) )
  {
    m_ShieldMax = 50;
  }
  else if ( theApp.m_PlayerData.HasBought( LD::SI_MIN_SHIELD ) )
  {
    m_ShieldMax = 8;
  }
  m_Shield = m_ShieldMax;

  m_Vehicle = theApp.m_PlayerData.SuggestVehicle( &pStar->Planets[PlanetIndex] );
  switch ( m_Vehicle )
  {
    case LD::VT_BOAT:
      player.m_Texture = LD::TEX_UNIT_SHIP;
      m_VehicleSpeed      = 150.0f;
      m_VehicleTurnSpeed  = 90.0f;
      break;
    case LD::VT_ROVER:
      player.m_Texture    = LD::TEX_UNIT_ROVER;
      m_VehicleSpeed      = 80.0f;
      m_VehicleTurnSpeed  = 90.0f;
      m_VehicleCanGoBack  = true;
      break;
    case LD::VT_JET:
      player.m_Texture = LD::TEX_UNIT_JET;
      m_VehicleSpeed      = 260.0f;
      m_VehicleTurnSpeed  = 130.0f;
      break;
  }
  m_Units.push_back( player );

  m_pPlayerUnit = &m_Units.back();

  m_OxygenSupply      = (float)theApp.m_PlayerData.m_OxygenPerExpedition;
  m_FullOxygenSupply  = m_OxygenSupply;

}



CGSPlanet::~CGSPlanet()
{

  theApp.StopSound( LD::SOUND_ROVER );
  theApp.StopSound( LD::SOUND_JET );
  theApp.StopSound( LD::SOUND_BOAT );

}



void CGSPlanet::RemoveResource( LD::Resource* pResource )
{

  std::list<LD::Resource>::iterator   it( m_Resources.begin() );
  while ( it != m_Resources.end() )
  {
    LD::Resource&   resource( *it );

    if ( ( resource.Location == pResource->Location )
    &&   ( resource.Type == pResource->Type ) )
    {
      m_Resources.erase( it );
      return;
    }
    ++it;
  }

}



float CGSPlanet::SafeDistance( int X, int Y, int X2, int Y2, float& AngleToResource )
{

  int     dispX = X2;
  int     dispY = Y2;

  if ( dispX - X >= 100 * 40 )
  {
    dispX -= 200 * 40;
  }
  if ( dispX - X <= -100 * 40 )
  {
    dispX += 200 * 40;
  }
  if ( dispY - Y >= 100 * 40 )
  {
    dispY -= 200 * 40;
  }
  if ( dispY - Y <= -100 * 40 )
  {
    dispY += 200 * 40;
  }

  AngleToResource = atan2f( (float)( dispY - Y ), (float)( dispX - X ) ) * 180.0f / 3.1415926f;

  return sqrtf( (float)( dispX - X ) * (float)( dispX - X ) + (float)( dispY - Y ) * (float)( dispY - Y ) );

}



int CGSPlanet::DetermineRadarPos( LD::ResourceType Resource, LD::Resource*& pResource, float& AngleToResource )
{

  if ( m_pPlayerUnit == NULL )
  {
    return 0;
  }

  float         longestDistance = sqrtf( 4000 * 4000 + 4000 * 4000 );
  float         closestDistance = longestDistance;

  LD::Resource* pFoundResource = NULL;

  std::list<LD::Resource>::iterator   it( m_Resources.begin() );
  while ( it != m_Resources.end() )
  {
    LD::Resource&   resource( *it );

    if ( resource.Type == Resource )
    {
      float   angleToResource = 0.0f;
      float   distance = SafeDistance( m_pPlayerUnit->m_X, m_pPlayerUnit->m_Y, resource.Location.x, resource.Location.y, angleToResource );

      if ( distance < closestDistance )
      {
        closestDistance = distance;
        pFoundResource = &resource;
        AngleToResource = angleToResource;
      }
    }

    ++it;
  }

  pResource = pFoundResource;
  if ( pFoundResource == NULL )
  {
    return 0;
  }

  if ( closestDistance < 40.0f )
  {
    // found!
    return 100;
  }
  return 1 + (int)( 99.0f * ( longestDistance - closestDistance ) / longestDistance );

}



unsigned long CGSPlanet::ResourceColor( LD::ResourceType Resource )
{

  switch ( Resource )
  {
    case LD::RT_ALIEN_TECHNOLOGY:
      return 0xffA1C700;
    case LD::RT_CRYSTITE:
      return 0xff62FCFF;
    case LD::RT_GOLD:
      return 0xffEFE000;
    case LD::RT_SPICE:
      return 0xffB76100;
    case LD::RT_UNOBTAINIUM:
      return 0xff4FD9A1;
    case LD::RT_ZINC:
      return 0xff8F8F8F;
  }

  return 0xffff00ff;

}



void CGSPlanet::RenderBar( int X, int Y, int W, int H, DWORD BackColor, DWORD BarColor, int Pos )
{

  theApp.RenderQuad2d( X, Y, W, H, BackColor );
  if ( Pos > 0 )
  {
    theApp.RenderQuad2d( X + 1, Y + 1, (int)( Pos * ( W - 2 ) / 100 ), H - 2, BarColor );
  }

}



void CGSPlanet::Display( IDirect3DDevice8* pDevice )
{

  theApp.m_Universe.DisplayPlanet( pDevice, *m_pPlanet, m_DisplayOffsetX, m_DisplayOffsetY );

  theApp.m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  theApp.m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );

  theApp.m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  theApp.m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  theApp.m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );

  theApp.m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  theApp.m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  theApp.m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );

  std::list<Unit>::iterator   itU( m_Units.begin() );
  while ( itU != m_Units.end() )
  {
    Unit&   unit( *itU );

    int     dispX = m_DisplayOffsetX;
    int     dispY = m_DisplayOffsetY;

    if ( dispX - unit.m_X > 100 * 40 )
    {
      dispX -= 200 * 40;
    }
    if ( unit.m_X - dispX > 100 * 40 )
    {
      dispX += 200 * 40;
    }
    if ( dispY - unit.m_Y > 100 * 40 )
    {
      dispY -= 200 * 40;
    }
    if ( unit.m_Y - dispY > 100 * 40 )
    {
      dispY += 200 * 40;
    }

    unit.Display( dispX, dispY );

    ++itU;
  }

  theApp.m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  theApp.m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE );
  theApp.m_pd3dDevice->SetTexture( 0, NULL );
  theApp.RenderQuad2d( 0, 400, 640, 80, 0xff23506B );

  int   radarX = 5;
  int   radarY = 405;
  int   radarH = 8;

  LD::Resource*   pResourceDummy = NULL;
  std::set<LD::ResourceType>::iterator    itR( theApp.m_PlayerData.m_Radars.begin() );
  while ( itR != theApp.m_PlayerData.m_Radars.end() )
  {
    float angleToResource = 0.0f;
    int   radarPos = DetermineRadarPos( *itR, pResourceDummy, angleToResource );

    unsigned long   resColor = ResourceColor( *itR );
    unsigned long   resColorDark = 0xff000000 
                                    + ( ( ( resColor & 0x00ff0000 ) >> 20 ) << 19 )
                                    + ( ( ( resColor & 0x0000ff00 ) >> 12 ) << 11 )
                                    + ( ( ( resColor & 0x000000ff ) >> 4 ) << 3 );

    RenderBar( radarX, radarY, 80, radarH, resColorDark, resColor, radarPos );

    if ( ( ( theApp.m_PlayerData.HasBought( LD::SI_CLOSE_RESOURCE_RADAR ) )
    &&     ( radarPos > 95 ) )
    ||   ( ( theApp.m_PlayerData.HasBought( LD::SI_MEDIUM_RESOURCE_RADAR ) )
    &&     ( radarPos > 65 ) )
    ||   ( ( theApp.m_PlayerData.HasBought( LD::SI_LONG_RESOURCE_RADAR ) )
    &&     ( radarPos > 65 ) ) )
    {
      theApp.m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
      theApp.RenderTextureSectionRotated2d( 320 + (int)( 80.0f * cosf( angleToResource * 3.1415926f / 180.0f ) ),
                                            200 + (int)( 80.0f * sinf( angleToResource * 3.1415926f / 180.0f ) ),
                                            theApp.m_TexSec[LD::TEX_ARROW],
                                            90.0f - angleToResource + 180.0f,
                                            resColor );
      theApp.m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE );
    }

    char  temp[20];
    sprintf( temp, "%d", radarPos );
    theApp.Print( radarX + 100, radarY - 3, temp );

    theApp.Print( radarX + 130, radarY - 3, Universe::ResourceName( *itR ).c_str() );

    radarY += radarH + 3;
    ++itR;
  }

  RenderBar( 240, 405, 80, 8, 0xff64979D, 0xffA7F6FF, (int)( m_OxygenSupply * 100 / m_FullOxygenSupply ) );
  if ( m_ShieldMax > 0.0f )
  {
    RenderBar( 240, 405 + 11, 80, 8, 0xff135905, 0xff24EF00, (int)( m_Shield * 100 / m_ShieldMax ) );
  }
  else
  {
    RenderBar( 240, 405 + 11, 80, 8, 0xff135905, 0xff24EF00, 0 );
  }
  if ( m_pPlayerUnit )
  {
    RenderBar( 240, 405 + 22, 80, 8, 0xff8F130C, 0xffD70D00, (int)( m_pPlayerUnit->m_Life * 100 / m_Health ) );
  }
  else
  {
    RenderBar( 240, 405 + 22, 80, 8, 0xff8F130C, 0xffD70D00, 0 );
  }

  char  temp[20];
  sprintf( temp, "%d", (int)( m_OxygenSupply * 100 / m_FullOxygenSupply ) );
  theApp.Print( 240 + 100, 405 - 3, temp );
  if ( m_ShieldMax > 0.0f )
  {
    sprintf( temp, "%d", (int)( m_Shield * 100 / m_ShieldMax ) );
    theApp.Print( 240 + 100, 405 + 11 - 3, temp );
  }
  else
  {
    theApp.Print( 240 + 100, 405 + 11 - 3, "0" );
  }
  if ( m_pPlayerUnit )
  {
    sprintf( temp, "%d", (int)( m_pPlayerUnit->m_Life * 100 / m_Health ) );
    theApp.Print( 240 + 100, 405 + 22 - 3, temp );
  }
  else
  {
    theApp.Print( 240 + 100, 405 + 22 - 3, "0" );
  }

  theApp.Print( 240 + 130, 405 - 3, "Oxygen" );
  theApp.Print( 240 + 130, 405 + 11 - 3, "Shield" );
  theApp.Print( 240 + 130, 405 + 22 - 3, "Integrity" );


  if ( !m_Messages.empty() )
  {
    theApp.m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );

    theApp.PrintCentered( 321, 130, m_Messages.front().c_str(), 0xff000000 );
    theApp.PrintCentered( 319, 130, m_Messages.front().c_str(), 0xff000000 );
    theApp.PrintCentered( 320, 129, m_Messages.front().c_str(), 0xff000000 );
    theApp.PrintCentered( 320, 131, m_Messages.front().c_str(), 0xff000000 );
    theApp.PrintCentered( 320, 130, m_Messages.front().c_str() );
  }

  if ( ( m_pPlayerUnit )
  &&   ( !m_Won )
  &&   ( m_OxygenSupply > 0.0f ) )
  {
    theApp.m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
    theApp.RenderButton( 640 - 120, 480 - 40, 120, 40, LD::TEX_BUTTON_1, LD::TEX_BUTTON_2, LD::TEX_BUTTON_3, "ORBIT" );
  }

}



void CGSPlanet::CreateMovementParticles( float ElapsedTime, bool AtFront )
{

  float     deltaX = 16.0f;
  float     deltaY = 16.0f;
  float     particleDistance = 0.2f;

  LD::TextureTypes    particleTexture = LD::TEX_PARTICLE_DIRT;

  switch ( m_Vehicle )
  {
    case LD::VT_ROVER:
      deltaX = 18.0f;
      if ( m_pPlanet->PlanetType == Universe::PT_DIRT )
      {
        particleTexture = LD::TEX_PARTICLE_DIRT;
      }
      else if ( m_pPlanet->PlanetType == Universe::PT_ICE )
      {
        particleTexture = LD::TEX_PARTICLE_ICE;
      }
      else if ( m_pPlanet->PlanetType == Universe::PT_ROCK )
      {
        particleTexture = LD::TEX_PARTICLE_ROCK;
      }
      else if ( m_pPlanet->PlanetType == Universe::PT_SAND )
      {
        particleTexture = LD::TEX_PARTICLE_SAND;
      }
      break;
    case LD::VT_BOAT:
      deltaX = 8.0f;
      particleDistance = 0.1f;
      if ( m_pPlanet->PlanetType == Universe::PT_LAVA )
      {
        particleTexture = LD::TEX_PARTICLE_LAVA;
      }
      else if ( m_pPlanet->PlanetType == Universe::PT_WATER )
      {
        particleTexture = LD::TEX_PARTICLE_WATER;
      }
      break;
    case LD::VT_JET:
      deltaX = 16.0f;
      particleDistance = 0.1f;
      particleTexture = LD::TEX_PARTICLE_ICE;
      break;
  }

  m_ParticleDelay += ElapsedTime;
  if ( m_ParticleDelay >= particleDistance )
  {
    m_ParticleDelay -= particleDistance;


    deltaX += ( rand() % 3 ) - 1.0f;

    SpawnParticle( (int)( m_pPlayerUnit->m_X
                                      - deltaX * cosf( m_pPlayerUnit->m_Angle * 3.1415926f / 180.0f )
                                      + deltaY * sinf( m_pPlayerUnit->m_Angle * 3.1415926f / 180.0f ) ),
                   (int)( m_pPlayerUnit->m_Y 
                                      + deltaX * sinf( m_pPlayerUnit->m_Angle * 3.1415926f / 180.0f )
                                      + deltaY * cosf( m_pPlayerUnit->m_Angle * 3.1415926f / 180.0f ) ),
                   particleTexture );
    SpawnParticle( (int)( m_pPlayerUnit->m_X
                                      + deltaX * cosf( m_pPlayerUnit->m_Angle * 3.1415926f / 180.0f )
                                      + deltaY * sinf( m_pPlayerUnit->m_Angle * 3.1415926f / 180.0f ) ),
                   (int)( m_pPlayerUnit->m_Y 
                                      - deltaX * sinf( m_pPlayerUnit->m_Angle * 3.1415926f / 180.0f )
                                      + deltaY * cosf( m_pPlayerUnit->m_Angle * 3.1415926f / 180.0f ) ),
                   particleTexture );
  }

}



void CGSPlanet::SpawnShot( Unit* pShooter, float DX, float DY, float Angle, LD::TextureTypes Texture, int Power, float Speed )
{

  Unit    unitShot;

  unitShot.m_Angle    = Angle;
  unitShot.m_Texture  = Texture;
  if ( pShooter == m_pPlayerUnit )
  {
    unitShot.m_Type     = LD::UT_PLAYER_SHOT;
  }
  else
  {
    unitShot.m_Type = LD::UT_ENEMY_SHOT;
  }
  unitShot.m_LifeTime = 10.0f;
  unitShot.m_Speed    = Speed;  
  unitShot.m_Life     = Power;

  float   deltaX = 0.0f;
  float   deltaY = -20.0f;

  unitShot.m_X        = (int)( pShooter->m_X
                                    - deltaX * cosf( Angle * 3.1415926f / 180.0f )
                                    + deltaY * sinf( Angle * 3.1415926f / 180.0f ) );
  unitShot.m_Y        = (int)( pShooter->m_Y 
                                    + deltaX * sinf( Angle * 3.1415926f / 180.0f )
                                    + deltaY * cosf( Angle * 3.1415926f / 180.0f ) );

  m_Units.push_back( unitShot );

}



void CGSPlanet::UpdateFrame( const float ElapsedTime )
{

  if ( m_pPlayerUnit )
  {
    if ( !m_Won )
    {
      m_OxygenSupply -= ElapsedTime * 0.25f;
    }
  }
  else
  {
    m_Messages.clear();
    m_Messages.push_back( "YOU HAVE BEEN KILLED" );
    m_MessageDisplayTime = 5.0f;
  }
  if ( m_OxygenSupply <= 0.0f )
  {
    m_OxygenSupply = 0.0;
    m_Messages.clear();
    m_Messages.push_back( "OUT OF OXYGEN, YOU DIED" );
    m_MessageDisplayTime = 5.0f;
    return;
  }

  if ( m_ShotDelay > 0.0f )
  {
    m_ShotDelay -= ElapsedTime;
    if ( m_ShotDelay <= 0.0f )
    {
      m_ShotDelay = 0.0f;
    }
  }

  if ( !m_Messages.empty() )
  {
    m_MessageDisplayTime -= ElapsedTime;
    if ( m_MessageDisplayTime <= 0.0f )
    {
      m_MessageDisplayTime = 0.0f;
      m_Messages.pop_front();
    }
  }

  if ( ( m_pPlayerUnit )
  &&   ( !m_Won ) )
  {
    bool    roverActive = false;
    if ( theApp.m_bKeyPressed[VK_UP] )
    {
      m_pPlayerUnit->Advance( m_VehicleSpeed * ElapsedTime );
      CreateMovementParticles( ElapsedTime );
      roverActive = true;
    }
    if ( ( m_VehicleCanGoBack )
    &&   ( theApp.m_bKeyPressed[VK_DOWN] ) )
    {
      m_pPlayerUnit->Advance( m_VehicleSpeed * ElapsedTime );
      CreateMovementParticles( ElapsedTime, true );
      roverActive = true;
    }
    if ( roverActive != m_RoverActive )
    {
      m_RoverActive = roverActive;
      if ( m_RoverActive )
      {
        switch ( m_Vehicle )
        {
          case LD::VT_ROVER:
            theApp.LoopSound( LD::SOUND_ROVER );
            break;
          case LD::VT_JET:
            theApp.LoopSound( LD::SOUND_JET );
            break;
          case LD::VT_BOAT:
            theApp.LoopSound( LD::SOUND_BOAT );
            break;
        }
      }
      else
      {
        theApp.StopSound( LD::SOUND_ROVER );
        theApp.StopSound( LD::SOUND_JET );
        theApp.StopSound( LD::SOUND_BOAT );
      }
    }
    if ( theApp.m_bKeyPressed[VK_LEFT] )
    {
      m_pPlayerUnit->m_Angle += m_VehicleTurnSpeed * ElapsedTime;
    }
    if ( theApp.m_bKeyPressed[VK_RIGHT] )
    {
      m_pPlayerUnit->m_Angle -= m_VehicleTurnSpeed * ElapsedTime;
    }
    if ( ( theApp.m_bKeyPressed['Q'] )
    ||   ( theApp.m_bKeyPressed['A'] ) )
    {
      if ( ( theApp.m_PlayerData.HasBought( LD::SI_SMALL_GUN ) )
      ||   ( theApp.m_PlayerData.HasBought( LD::SI_MEDIUM_GUN ) )
      ||   ( theApp.m_PlayerData.HasBought( LD::SI_MAX_GUN ) ) )
      {
        if ( m_ShotDelay == 0.0f )
        {
          LD::TextureTypes    shotTex = LD::TEX_PLAYER_MIN_SHOT;
          int                 shotPower = 1;
          float               shotSpeed = 240.0f;

          m_ShotDelay = 0.3f;

          if ( theApp.m_PlayerData.HasBought( LD::SI_MAX_GUN ) )
          {
            shotTex     = LD::TEX_PLAYER_MAX_SHOT;
            shotPower   = 5;
            shotSpeed   = 420.0f;
            m_ShotDelay = 0.1f;

            theApp.PlaySound( LD::SOUND_MAX_GUN );
          }
          else if ( theApp.m_PlayerData.HasBought( LD::SI_MEDIUM_GUN ) )
          {
            shotTex     = LD::TEX_PLAYER_MED_SHOT;
            shotPower   = 3;
            shotSpeed   = 380.0f;
            m_ShotDelay = 0.2f;

            theApp.PlaySound( LD::SOUND_MED_GUN );
          }
          else if ( theApp.m_PlayerData.HasBought( LD::SI_SMALL_GUN ) )
          {
            shotTex     = LD::TEX_PLAYER_MIN_SHOT;
            shotPower   = 1;
            shotSpeed   = 340.0f;
            m_ShotDelay = 0.3f;

            theApp.PlaySound( LD::SOUND_MIN_GUN );
          }

          SpawnShot( m_pPlayerUnit, 0.0f, -20.0f, m_pPlayerUnit->m_Angle, shotTex, shotPower, shotSpeed );
        }
      }
    }
    m_DisplayOffsetX = m_pPlayerUnit->m_X - 320;
    if ( m_DisplayOffsetX < 0 )
    {
      m_DisplayOffsetX += 200 * 40;
    }
    if ( m_DisplayOffsetX >= 200 * 40 )
    {
      m_DisplayOffsetX -= 200 * 40;
    }
    m_DisplayOffsetY = m_pPlayerUnit->m_Y - 200;
    if ( m_DisplayOffsetY < 0 )
    {
      m_DisplayOffsetY += 200 * 40;
    }
    if ( m_DisplayOffsetY >= 200 * 40 )
    {
      m_DisplayOffsetY -= 200 * 40;
    }
  }

  LD::Resource*   pResource = NULL;

  std::set<LD::ResourceType>::iterator    itR( theApp.m_PlayerData.m_Radars.begin() );
  while ( itR != theApp.m_PlayerData.m_Radars.end() )
  {
    float   angleDummy = 0.0f;

    int   radarPos = DetermineRadarPos( *itR, pResource, angleDummy );

    if ( radarPos == 100 )
    {
      // found resource!
      if ( ( theApp.m_Universe.m_pFinalPlanet == &m_pVisitedStarSystem->Planets[m_PlanetIndex] )
      &&   ( m_pBase )
      &&   ( pResource->Location == tPoint( m_pBase->m_X, m_pBase->m_Y ) ) )
      {
        // collected final item!
        m_Messages.push_back( "You found the alien base! You have done it!" );
        m_MessageDisplayTime = 5.0f;
        m_Won = true;
        theApp.StopSound( LD::SOUND_ROVER );
        theApp.StopSound( LD::SOUND_JET );
        theApp.StopSound( LD::SOUND_BOAT );
      }
      else
      {
        std::stringstream   msgStream;

        msgStream << "Retrieved " << pResource->Quantity << " of " << Universe::ResourceName( pResource->Type );

        m_Messages.push_back( msgStream.str() );
        m_MessageDisplayTime = 5.0f;
      }
      theApp.m_PlayerData.Collect( m_pVisitedStarSystem, m_PlanetIndex, *pResource );
      RemoveResource( pResource );

      theApp.PlaySound( LD::SOUND_FOUND );
      break;
    }

    ++itR;
  }

  if ( !m_Won )
  {
    std::list<Unit>::iterator   itU( m_Units.begin() );
    while ( itU != m_Units.end() )
    {
      Unit&   unit( *itU );

      unit.Update( this, ElapsedTime );
      if ( unit.m_RemoveMe )
      {
        itU = m_Units.erase( itU );
      }
      else
      {
        ++itU;
      }
    }

    CheckCollisions();
  }

}



void CGSPlanet::SpawnParticle( int X, int Y, LD::TextureTypes Texture, bool SpawnBack )
{

  Unit    particleLeft;

  particleLeft.m_Angle    = (float)( rand() % 360 );
  particleLeft.m_Texture  = Texture;
  particleLeft.m_Type     = LD::UT_PARTICLE;
  particleLeft.m_LifeTime = 1.0f;

  particleLeft.m_X        = X;
  particleLeft.m_Y        = Y;

  if ( SpawnBack )
  {
    m_Units.push_back( particleLeft );
  }
  else
  {
    m_Units.push_front( particleLeft );
  }

}



void CGSPlanet::CheckCollisions()
{

  std::list<Unit>::iterator   itU( m_Units.begin() );
  while ( itU != m_Units.end() )
  {
    Unit&   unit( *itU );

    if ( unit.m_RemoveMe )
    {
      ++itU;
      continue;
    }

    if ( ( unit.m_Type == LD::UT_PLAYER_SHOT )
    ||   ( unit.m_Type == LD::UT_ENEMY_SHOT ) )
    {
      std::list<Unit>::iterator   itU2( m_Units.begin() );
      while ( itU2 != m_Units.end() )
      {
        Unit&   unit2( *itU2 );

        if ( unit.m_RemoveMe )
        {
          break;
        }
        if ( !unit2.m_RemoveMe )
        {
          if ( ( ( unit.m_Type == LD::UT_PLAYER_SHOT )
          &&     ( unit2.m_Type == LD::UT_ENEMY_TURRET ) )
          ||   ( ( unit.m_Type == LD::UT_ENEMY_SHOT )
          &&     ( unit2.m_Type == LD::UT_PLAYER ) ) )
          {
            float   angleToTarget = 0.0f;

            if ( SafeDistance( unit.m_X, unit.m_Y, unit2.m_X, unit2.m_Y, angleToTarget ) < 
                  sqrtf( (float)theApp.m_TexSec[unit.m_Texture].m_iWidth * theApp.m_TexSec[unit.m_Texture].m_iWidth +
                         theApp.m_TexSec[unit.m_Texture].m_iHeight * theApp.m_TexSec[unit.m_Texture].m_iHeight ) )
            {
              int   damageToUnit = unit.m_Life;
              if ( unit2.m_Type == LD::UT_PLAYER )
              {
                if ( m_Shield >= damageToUnit )
                {
                  m_Shield -= damageToUnit;
                  damageToUnit = 0;
                }
                else
                {
                  damageToUnit -= (int)m_Shield;
                  m_Shield = 0;
                }
              }
              unit2.m_Life -= damageToUnit;
              unit.m_RemoveMe = true;
              SpawnParticle( unit.m_X, unit.m_Y, LD::TEX_PARTICLE_FIRE, true );
              theApp.PlaySound( LD::SOUND_SHOT_HIT );
              if ( unit2.m_Life <= 0 )
              {
                unit2.m_RemoveMe = true;
                if ( unit2.m_Type == LD::UT_PLAYER )
                {
                  m_pPlayerUnit = NULL;
                  theApp.PlaySound( LD::SOUND_PLAYER_DEAD );
                  theApp.StopSound( LD::SOUND_ROVER );
                  theApp.StopSound( LD::SOUND_JET );
                  theApp.StopSound( LD::SOUND_BOAT );
                }
                else
                {
                  theApp.PlaySound( LD::SOUND_ENEMY_DEAD );

                  theApp.m_PlayerData.Destroyed( m_pVisitedStarSystem, m_PlanetIndex, unit2.m_X, unit2.m_Y );
                }

                for ( int i = 0; i < 20; ++i )
                {
                  SpawnParticle( unit.m_X + rand() % 21 - 10, unit.m_Y + rand() % 21 - 10, LD::TEX_PARTICLE_LAVA, true );
                }
              }
            }
          }
        }

        ++itU2;
      }

    }

    ++itU;
  }

}



void CGSPlanet::OnMouse( int X, int Y, int Buttons )
{

  if ( ( ( m_pPlayerUnit )
  &&     ( !m_Won )
  &&     ( m_OxygenSupply > 0.0f ) )
  &&   ( HandleButton( X, Y, Buttons, 640 - 120, 480 - 40, 120, 40, 1 ) ) )
  {
    theApp.PlaySound( LD::SOUND_BUTTON );
    theApp.NextState( new CGSStar( m_pVisitedStarSystem ) );
    return;
  }
  if ( ( m_Won )
  &&   ( m_ButtonReleased )
  &&   ( Buttons & 1 ) )
  {
    theApp.NextState( new CGSDone() );
    return;
  }

  if ( !( Buttons & 1 ) )
  {
    m_ButtonReleased = true;
  }

}



void CGSPlanet::OnChar( int iChar )
{

  if ( iChar == 27 )
  {
    if ( m_Won )
    {
      theApp.NextState( new CGSDone() );
    }
    else if ( ( m_pPlayerUnit )
    &&        ( m_OxygenSupply > 0.0f ) )
    {
      theApp.NextState( new CGSStar( m_pVisitedStarSystem ) );
    }
    else
    {
      theApp.NextState( new CGSMenu() );
    }
    return;
  }

}



void CGSPlanet::OnKeyDown( int iChar )
{

}



