#include <Xtreme/X2dRenderer.h>

#include <MasterFrame/XAct.h>

#include <IO/FileChunk.h>

#include ".\level.h"
#include ".\Unit.h"
#include ".\BirdiesRevenge.h"

#include ".\Birdie.h"
#include ".\Bubble.h"
#include ".\Bonus.h"
#include ".\Note.h"

#include ".\GameLogic.h"



Level::Level() :
  m_GameEventHandler( NULL ),
  m_FixedTime( 0.0f ),
  m_ExtraStartDelay( 0 ),
  m_FlashStartDelay( 0 )
{
}



Level::~Level()
{
  Clear();
}



void Level::Display( XRenderer& Renderer )
{
  GR::tPoint    ptOffset( (int)m_Offset.x, (int)m_Offset.y );

  int     iX1 = ptOffset.x / 20;
  int     iY1 = ptOffset.y / 20;

  int     iX2 = iX1 + 40;
  int     iY2 = iY1 + 30;

  for ( int i = iX1; i <= iX2; ++i )
  {
    for ( int j = iY1; j <= iY2; ++j )
    {
      Birdie2::eFeldTypes Feld = m_Field.Field( i, j );
      if ( Feld != Birdie2::FT_EMPTY )
      {
        Renderer.RenderTextureSection2d( ( i - iX1 ) * 20 - ( ptOffset.x % 20 ), ( j - iY1 ) * 20 - ( ptOffset.y % 20 ), theApp.Section( CMisc::printf( "Tile.%d", Feld + 1 ) ) );
      }
    }
  }

  tListUnits::iterator    it( m_Units.begin() );
  while ( it != m_Units.end() )
  {
    Unit*    pUnit( *it );

    pUnit->Display( ptOffset, Renderer );

    ++it;
  }
}



void Level::UpdateUnits( GR::f32 ElapsedTime )
{
  tListUnits::iterator    it( m_Units.begin() );
  while ( it != m_Units.end() )
  {
    Unit*    pUnit( *it );

    if ( pUnit->m_RemoveMe )
    {
      pUnit->ProcessEvent( *this, Unit::ET_DIE );
      m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_UNIT_DELETED, pUnit ) );

      delete pUnit;
      it = m_Units.erase( it );
    }
    else
    {
      if ( ( m_StartPause > 0.0f )
      &&   ( pUnit->m_IsNasty ) )
      {
        // Monster haben Startpause
      }
      else
      {
        pUnit->Update( *this, ElapsedTime );
      }
      ++it;
    }
  }

  it = m_Units.begin();
  while ( it != m_Units.end() )
  {
    next_object:;

    Unit*    pUnit( *it );

    if ( pUnit->m_RemoveMe )
    {
      pUnit->ProcessEvent( *this, Unit::ET_DIE );
      m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_UNIT_DELETED, pUnit ) );

      delete pUnit;
      it = m_Units.erase( it );
    }
    else
    {
      GR::tRect   rcBounds( pUnit->CollisionBounds() );

      tListUnits::iterator    it2( m_Units.begin() );
      while ( it2 != m_Units.end() )
      {
        Unit*    pUnit2( *it2 );

        if ( ( pUnit != pUnit2 )
          && ( !pUnit2->m_RemoveMe )
          && ( rcBounds.intersects( pUnit2->CollisionBounds() ) ) )
        {
          GR::u32   dwResult = OnCollision( pUnit, pUnit2 );
          if ( dwResult == 2 )
          {
            it2 = m_Units.erase( it2 );
            continue;
          }
          dwResult = OnCollision( pUnit2, pUnit );
          if ( dwResult == 2 )
          {
            it = m_Units.erase( it );
            goto next_object;
          }
        }

        ++it2;
      }

      ++it;
    }
  }
}



bool Level::IsCompleted()
{
  bool    importantUnitLeft = false;

  tListUnits::iterator    it( m_Units.begin() );
  while ( it != m_Units.end() )
  {
    Unit*    pUnit( *it );

    if ( ( pUnit->m_IsNasty )
    ||   ( pUnit->m_Type == Birdie2::UT_BUBBLE )
    ||   ( ( pUnit->m_Type == Birdie2::UT_BONUS )
    &&     ( !( (Bonus*)pUnit )->m_Done ) ) )
    {
      importantUnitLeft = true;
      break;
    }
    ++it;
  }

  return !importantUnitLeft;
}



void Level::UpdateUnitsFixed()
{
  tListUnits::iterator    it( m_Units.begin() );
  while ( it != m_Units.end() )
  {
    Unit*    pUnit( *it );

    if ( pUnit->m_RemoveMe )
    {
      pUnit->ProcessEvent( *this, Unit::ET_DIE );
      m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_UNIT_DELETED, pUnit ) );

      delete pUnit;
      it = m_Units.erase( it );
    }
    else
    {
      if ( ( m_StartPause > 0.0f )
      &&   ( pUnit->m_IsNasty ) )
      {
        // Monster haben Startpause
      }
      else
      {
        pUnit->UpdateFixed( *this );
      }
      ++it;
    }
  }

  it = m_Units.begin();
  while ( it != m_Units.end() )
  {
    next_object:;

    Unit*    pUnit( *it );

    if ( pUnit->m_RemoveMe )
    {
      pUnit->ProcessEvent( *this, Unit::ET_DIE );
      m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_UNIT_DELETED, pUnit ) );

      delete pUnit;
      it = m_Units.erase( it );
    }
    else
    {
      GR::tRect   rcBounds( pUnit->CollisionBounds() );

      tListUnits::iterator    it2( m_Units.begin() );
      while ( it2 != m_Units.end() )
      {
        Unit*    pUnit2( *it2 );

        if ( ( pUnit != pUnit2 )
          && ( !pUnit2->m_RemoveMe )
          && ( rcBounds.intersects( pUnit2->CollisionBounds() ) ) )
        {
          GR::u32   dwResult = OnCollision( pUnit, pUnit2 );
          if ( dwResult == 2 )
          {
            it2 = m_Units.erase( it2 );
            continue;
          }
          dwResult = OnCollision( pUnit2, pUnit );
          if ( dwResult == 2 )
          {
            it = m_Units.erase( it );
            goto next_object;
          }
        }

        ++it2;
      }

      ++it;
    }
  }

  if ( m_DonePause == 0.0f )
  {
    if ( IsCompleted() )
    {
      m_NastiesAlive = 0;
      m_DonePause = 5.0f;
    }
  }
}



Unit* Level::SpawnUnit( int X, int Y, Birdie2::eUnitTypes UnitType )
{
  Unit*   pUnit = Unit::FromType( UnitType );
  if ( pUnit == NULL )
  {
    return false;
  }
  pUnit->m_Position.set( X, Y );
  pUnit->m_StartPosition.set( X, Y );


  pUnit->ProcessEvent( *this, Unit::eUnitEvent::ET_INIT );

  m_Units.push_back( pUnit );

  return pUnit;
}



void Level::Update( const GR::f32 ElapsedTime )
{
  if ( m_StartPause > 0.0f )
  {
    m_StartPause -= ElapsedTime;
    if ( m_StartPause < 0.0f )
    {
      m_StartPause = 0.0f;
    }
  }

  if ( m_DeathPause > 0.0f )
  {
    m_DeathPause -= ElapsedTime;
    if ( m_DeathPause <= 0.0f )
    {
      m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_PLAYER_DIED ) );
      return;
    }
  }

  if ( m_DonePause > 0.0f )
  {
    m_DonePause -= ElapsedTime;
    if ( m_DonePause <= 0.0f )
    {
      m_GameEventHandler( Birdie2::CGameEvent( Birdie2::CGameEvent::GE_LEVEL_COMPLETED ) );
      return;
    }
  }

  GR::f32     timeLeft = ElapsedTime;

  while ( timeLeft > 0.0f )
  {
    if ( m_FixedTime + timeLeft >= 0.02f )
    {
      GR::f32     timeDelta = 0.02f - m_FixedTime;

      timeLeft -= timeDelta;
      m_FixedTime = 0.0f;

      UpdateUnits( timeDelta );
      UpdateFixed();
    }
    else
    {
      m_FixedTime += timeLeft;
      UpdateUnits( timeLeft );
      timeLeft = 0.0f;
    }
  }
}



Unit* Level::SpawnExtra()
{
  if ( m_ExtraStartPositions.empty() )
  {
    return NULL;
  }
  GR::tPoint    randPos( m_ExtraStartPositions[rand() % m_ExtraStartPositions.size()] );

  return GameLogic::SpawnExtra( *this, randPos );
}



Unit* Level::SpawnFlash()
{
  if ( m_FlashStartPositions.empty() )
  {
    return NULL;
  }
  GR::tPoint    randPos( m_FlashStartPositions[rand() % m_FlashStartPositions.size()] );

  return SpawnUnit( randPos.x, randPos.y, Birdie2::UT_FLASH_BUBBLE );
}



void Level::UpdateFixed()
{
  UpdateUnitsFixed();

  ++m_ExtraStartDelay;
  if ( m_ExtraStartDelay == 100 )
  {
    SpawnExtra();
  }
  ++m_FlashStartDelay;
  if ( m_FlashStartDelay == 200 )
  {
    SpawnFlash();
    m_FlashStartDelay = 0;
  }
}



void Level::Clear()
{
  tListUnits::iterator    it( m_Units.begin() );
  while ( it != m_Units.end() )
  {
    Unit*    pUnit( *it );

    delete pUnit;

    ++it;
  }
  m_Units.clear();
  m_ExtraStartPositions.clear();
  m_ExtraStartDelay = 0;
  m_FlashStartPositions.clear();
  m_FlashStartDelay = 0;
  m_BubbleTargetPos.set( 380, 20 );
}



bool Level::IsFeldBlocking( Unit* pUnit, const Birdie2::eFeldTypes Feld, Birdie2::eDir Dir )
{
  switch ( pUnit->m_Type )
  {
    case Birdie2::UT_BIRDIE:
      if ( ( ( Feld == Birdie2::FT_WALL )
      ||     ( Feld == Birdie2::FT_PLATFORM_1 )
      ||     ( Feld == Birdie2::FT_PLATFORM_2 )
      ||     ( Feld == Birdie2::FT_PLATFORM_3 )
      ||     ( Feld == Birdie2::FT_PLATFORM_4 ) )
      &&   ( ( Dir == Birdie2::DIR_N )
      ||     ( Dir == Birdie2::DIR_W )
      ||     ( Dir == Birdie2::DIR_E ) ) )
      {
        return false;
      }
      break;
    case Birdie2::UT_AUFZIEH:
      if ( ( Feld == Birdie2::FT_WALL )
      &&   ( Dir == Birdie2::DIR_N ) )
      {
        return false;
      }
      break;
    case Birdie2::UT_THING:
      if ( ( Feld == Birdie2::FT_WALL )
      &&   ( Dir != Birdie2::DIR_S ) )
      {
        return false;
      }
      break;
    case Birdie2::UT_BONUS:
      if ( !( (Bonus*)pUnit )->m_Done )
      {
        return false;
      }
      break;
    case Birdie2::UT_POINTS:
    case Birdie2::UT_BOSS_SHOT:
    case Birdie2::UT_PUMPKIN_PIECE:
      return false;
    case Birdie2::UT_NOTE:
      if ( Feld == Birdie2::FT_SOLID )
      {
        return true;
      }
      return false;
  }

  if ( ( Feld == Birdie2::FT_EMPTY )
  ||   ( IsTileBorder( Feld ) ) )
  {
    return false;
  }
  return true;
}



bool Level::UnitMustStayInBounds( Birdie2::eUnitTypes UnitType )
{
  if ( ( UnitType == Birdie2::UT_POINTS )
  ||   ( UnitType == Birdie2::UT_FLASH )
  ||   ( UnitType == Birdie2::UT_BIRDIE )
  ||   ( UnitType == Birdie2::UT_PUMPKIN_PIECE )
  ||   ( UnitType == Birdie2::UT_BOSS_SHOT ) )
  {
    return false;
  }
  return true;
}



bool Level::CanMove( Unit* pUnit, const GR::tPoint& ptCurPos, Birdie2::eDir Dir )
{
  GR::tRect   rcBounds( pUnit->MovementBounds() );


  switch ( Dir )
  {
    case Birdie2::DIR_W:
      if ( ( rcBounds.Left % 20 ) != 0 )
      {
        // schon innerhalb des Tiles
        return true;
      }
      rcBounds.offset( -1, 0 );
      break;
    case Birdie2::DIR_E:
      if ( ( ( rcBounds.Right - 1 ) % 20 ) != 19 )
      {
        // schon innerhalb des Tiles
        return true;
      }
      rcBounds.offset( 1, 0 );
      break;
    case Birdie2::DIR_N:
      if ( ( rcBounds.Top % 20 ) != 0 )
      {
        // schon innerhalb des Tiles
        return true;
      }
      rcBounds.offset( 0, -1 );
      break;
    case Birdie2::DIR_S:
      if ( ( ( rcBounds.Bottom - 1 ) % 20 ) != 19 )
      {
        // schon innerhalb des Tiles
        return true;
      }
      rcBounds.offset( 0, 1 );
      break;
  }

  int     iX1 = rcBounds.Left / 20;
  int     iY1 = rcBounds.Top / 20;
  int     iX2 = ( rcBounds.Right - 1 ) / 20;
  int     iY2 = ( rcBounds.Bottom - 1 ) / 20;

  if ( Dir == Birdie2::DIR_S )
  {
    iY1 = iY2;
  }
  else if ( Dir == Birdie2::DIR_N )
  {
    iY2 = iY1;
  }
  else if ( Dir == Birdie2::DIR_W )
  {
    iX2 = iX1;
  }
  else if ( Dir == Birdie2::DIR_E )
  {
    iX1 = iX2;
  }

  for ( int iX = iX1; iX <= iX2; ++iX )
  {
    for ( int iY = iY1; iY <= iY2; ++iY )
    {
      int     ty = iY;

      if ( ( !pUnit->m_IsNasty )
      &&   ( UnitMustStayInBounds( pUnit->m_Type ) ) )
      {
        if ( ( iX < 1 )
        ||   ( iX >= m_Field.Width() - 1 )
        ||   ( iY < 1 )
        ||   ( iY >= m_Field.Height() - 1 ) )
        {
          return false;
        }
      }
      if ( ( pUnit->m_Type != Birdie2::UT_POINTS )
      &&   ( pUnit->m_Type != Birdie2::UT_PUMPKIN_PIECE )
      &&   ( pUnit->m_Type != Birdie2::UT_BOSS_SHOT ) )
      {
        if ( ( iX < 1 )
        ||   ( iX >= m_Field.Width() - 1 ) )
        {
          return false;
        }
      }
      if ( iY < 0 )
      {
        ty = 0;
      }
      if ( iY >= m_Field.Height() )
      {
        ty = m_Field.Height() - 1;
      }

      if ( IsFeldBlocking( pUnit, m_Field.Field( iX, ty ), Dir ) )
      {
        return false;
      }
    }
  }
  return true;
}



bool Level::Load( IIOStream& StreamIn )
{
  Clear();

  m_Field.InitFeld( 40, 30 );

  GR::IO::FileChunk    ChunkLevel;

  while ( ChunkLevel.Read( StreamIn ) )
  {
    MemoryStream   MemIn( ChunkLevel.GetMemoryStream() );

    switch ( ChunkLevel.Type() )
    {
      case 0x0001:
        {
          GR::u32     dwVersion = MemIn.ReadU32();
          std::string strName = MemIn.ReadString();
        }
        break;
      case 0x0002:
        {
          GR::u32     dwWidth = MemIn.ReadU32();
          GR::u32     dwHeight = MemIn.ReadU32();

          m_Field.InitFeld( dwWidth, dwHeight );
          MemIn.ReadBlock( m_Field.Data(), m_Field.DataSize() );
        }
        break;
      case 0x0003:
        {
          Birdie2::eUnitTypes   UnitType = (Birdie2::eUnitTypes)MemIn.ReadU32();

          Unit*    pUnit = Unit::FromType( UnitType );
          if ( pUnit )
          {
            pUnit->m_Position.x = MemIn.ReadU32();
            pUnit->m_Position.y = MemIn.ReadU32();
            pUnit->m_ExtraData = MemIn.ReadU32();
            pUnit->m_ExtraData2 = MemIn.ReadU32();

            m_Units.push_back( pUnit );
            pUnit->OnLoad( *this );
          }
          else
          {
            MemIn.ReadU32();
            MemIn.ReadU32();
            MemIn.ReadU32();
            MemIn.ReadU32();
          }
        }
        break;
      case 0x0004:
        {
          GR::tPoint    pos;

          pos.x = MemIn.ReadI32();
          pos.y = MemIn.ReadI32();

          m_ExtraStartPositions.push_back( pos );
        }
        break;
      case 0x0005:
        {
          GR::tPoint    pos;

          pos.x = MemIn.ReadI32();
          pos.y = MemIn.ReadI32();

          m_FlashStartPositions.push_back( pos );
        }
        break;
    }
  }
  return !m_Units.empty();
}



bool Level::Save( IIOStream& StreamOut )
{
  GR::IO::FileChunk    ChunkLevel( 0x0001 );

  // Version
  ChunkLevel.AppendU32( 1 );
  ChunkLevel.AppendString( "Name" );

  if ( !ChunkLevel.Write( StreamOut ) )
  {
    return false;
  }

  GR::IO::FileChunk    ChunkData( 0x0002 );

  ChunkData.AppendU32( m_Field.Width() );
  ChunkData.AppendU32( m_Field.Height() );
  ChunkData.AppendData( m_Field.Data(), m_Field.DataSize() );

  if ( !ChunkData.Write( StreamOut ) )
  {
    return false;
  }

  tListUnits::iterator    it( m_Units.begin() );
  while ( it != m_Units.end() )
  {
    Unit*    pUnit( *it );

    GR::IO::FileChunk    ChunkUnit( 0x0003 );

    ChunkUnit.AppendU32( pUnit->m_Type );
    ChunkUnit.AppendU32( pUnit->m_Position.x );
    ChunkUnit.AppendU32( pUnit->m_Position.y );
    ChunkUnit.AppendU32( pUnit->m_ExtraData );
    ChunkUnit.AppendU32( pUnit->m_ExtraData2 );

    if ( !ChunkUnit.Write( StreamOut ) )
    {
      return false;
    }

    ++it;
  }

  auto    it2( m_ExtraStartPositions.begin() );
  while ( it2 != m_ExtraStartPositions.end() )
  {
    GR::IO::FileChunk    chunkExtraStartPos( 0x0004 );

    chunkExtraStartPos.AppendI32( it2->x );
    chunkExtraStartPos.AppendI32( it2->y );

    if ( !chunkExtraStartPos.Write( StreamOut ) )
    {
      return false;
    }

    ++it2;
  }

  auto    it3( m_FlashStartPositions.begin() );
  while ( it3 != m_FlashStartPositions.end() )
  {
    GR::IO::FileChunk    chunkFlashStartPos( 0x0005 );

    chunkFlashStartPos.AppendI32( it3->x );
    chunkFlashStartPos.AppendI32( it3->y );

    if ( !chunkFlashStartPos.Write( StreamOut ) )
    {
      return false;
    }

    ++it3;
  }
  return true;
}



GR::u32 Level::OnCollision( Unit* pUnit1, Unit* pUnit2 )
{
  if ( m_DeathPause > 0.0f )
  {
    return 0;
  }
  return GameLogic::UnitsCollide( pUnit1, pUnit2, *this );
}



bool Level::IsTileBorder( Birdie2::eFeldTypes Field )
{
  if ( ( Field >= Birdie2::FT_BORDER_1 )
  &&   ( Field <= Birdie2::FT_BORDER_6 ) )
  {
    return true;
  }
  return false;
}



void Level::CreateBorders()
{
  // clear off all borders
  for ( int i = 0; i < m_Field.Width(); ++i )
  {
    for ( int j = 0; j < m_Field.Height(); ++j )
    {
      if ( IsTileBorder( m_Field.Field( i, j ) ) )
      {
        m_Field.SetField( i, j, Birdie2::FT_EMPTY );
      }
    }
  }
  // 
  for ( int i = 0; i < m_Field.Width(); ++i )
  {
    for ( int j = 0; j < m_Field.Height(); ++j )
    {
      if ( m_Field.Field( i, j ) != Birdie2::FT_EMPTY )
      {
        continue;
      }
      bool    tileAbove = ( ( j > 0 )
                         && ( m_Field.Field( i, j - 1 ) != Birdie2::FT_EMPTY )
                         && ( !IsTileBorder( m_Field.Field( i, j - 1 ) ) ) );
      bool    tileToLeft = ( ( i > 0 )
                          && ( m_Field.Field( i - 1, j ) != Birdie2::FT_EMPTY )
                          && ( !IsTileBorder( m_Field.Field( i - 1, j ) ) ) );
      bool    tileToTopLeft = ( ( i > 0 )
                          &&    ( j > 0 )
                          &&    ( m_Field.Field( i - 1, j - 1 ) != Birdie2::FT_EMPTY )
                          &&    ( !IsTileBorder( m_Field.Field( i - 1, j - 1 ) ) ) );

      if ( ( tileAbove )
      &&   ( tileToLeft ) )
      {
        m_Field.SetField( i, j, Birdie2::FT_BORDER_6 );
        continue;
      }
      if ( ( !tileAbove )
      &&   ( tileToTopLeft )
      &&   ( !tileToLeft ) )
      {
        m_Field.SetField( i, j, Birdie2::FT_BORDER_3 );
        continue;
      }
      if ( ( tileAbove )
      &&   ( !tileToTopLeft )
      &&   ( !tileToLeft ) )
      {
        m_Field.SetField( i, j, Birdie2::FT_BORDER_1 );
        continue;
      }
      if ( ( !tileAbove )
      &&   ( !tileToTopLeft ) 
      &&   ( tileToLeft ) )
      {
        m_Field.SetField( i, j, Birdie2::FT_BORDER_5 );
        continue;
      }
      if ( ( tileAbove )
      &&   ( !tileToLeft ) )
      {
        m_Field.SetField( i, j, Birdie2::FT_BORDER_2 );
        continue;
      }
      if ( ( !tileAbove )
      &&   ( tileToLeft ) )
      {
        m_Field.SetField( i, j, Birdie2::FT_BORDER_4 );
        continue;
      }
    }
  }
}



bool Level::PrepareForStart()
{
  CreateBorders();

  m_StartPause = 2.5f;
  m_DonePause  = 0.0f;
  m_DeathPause = 0.0f;

  m_NastiesAlive = 0;

  tListUnits::iterator    it( m_Units.begin() );
  while ( it != m_Units.end() )
  {
    Unit*    pUnit( *it );

    if ( pUnit->m_IsNasty )
    {
      m_NastiesAlive++;
      pUnit->m_FaceLeft = !!( rand() % 2 );
    }
    ++it;
  }

  return true;
}



bool Level::OnTopOfPlatform( Unit* pUnit )
{
  if ( !GameLogic::CanUnitStandOnPlatform( *pUnit ) )
  {
    return false;
  }

  GR::tRect   rcBounds( pUnit->MovementBounds() );

  GR::tRect   rcNewBounds( rcBounds );

  rcNewBounds.offset( 0, 1 );

  tListUnits::iterator    it( m_Units.begin() );
  while ( it != m_Units.end() )
  {
    Unit*    pOtherUnit( *it );

    if ( ( pOtherUnit != pUnit )
    &&   ( pOtherUnit->m_IsPlatform ) )
    {
      Note*  pNote = (Note*)pOtherUnit;

      GR::tRect   rcOther( pOtherUnit->MovementBounds() );

      if ( ( pNote->m_Rising )
      &&   ( rcNewBounds.Left < rcOther.Right )
      &&   ( rcNewBounds.Right > rcOther.Left )
      &&   ( std::abs( pNote->MovementBounds().Top - rcNewBounds.Bottom ) < 4 ) )
      {
        if ( pUnit->m_pOnUnit != pNote )
        {
          if ( pUnit->m_pOnUnit )
          {
            pUnit->m_pOnUnit->m_CarriedUnits.remove( pUnit );
          }

          pUnit->m_pOnUnit = pNote;
          pNote->m_CarriedUnits.push_back( pUnit );

          pUnit->m_Position.y = pNote->MovementBounds().Top - pUnit->MovementBounds().height();
        }
        pUnit->m_OnGround = true;
        pUnit->m_Speed.y = 0;
        return true;
      }
    }
    ++it;
  }

  if ( pUnit->m_pOnUnit )
  {
    pUnit->m_pOnUnit->m_CarriedUnits.remove( pUnit );
    pUnit->m_pOnUnit = NULL;
    pUnit->m_OnGround = false;
  }
  return false;
}



