//-------------------------------------------------------------------
//
//  This code is copyright 2001 by G5 Software.
//  Any unauthorized usage, either in part or in whole of this code
//  is strictly prohibited. Violators WILL be prosecuted to the
//  maximum extent allowed by law.
//
//-------------------------------------------------------------------

///////////////////////////////////
//
// Mission 2. "Convoy"
//
//


//
// *** mission AI controller ***
//

class CConvoyMission_AIController extends CBaseAIController
{
  boolean PlatoonAIsAttacks = false;
  boolean PlatoonBIsAttacks = false;

  boolean PlatoonAIsMoving = false;
  boolean PlatoonBIsMoving = false;

  void OnObjectEnterArea( int _NavPointIndex, string _NavPointName, string _ObjectID)
  {
    if ( _NavPointName == "NavPoint_Destination"
      && Core_IsStringStartsWith( _ObjectID, "SovietTruck_Transport"))
    {
      // Mission accomplished
      Core_BroadcastEvent("OnTransportsEnteredDestinationZone");
    };

    if ( _NavPointName == "NavPoint_Ambush_1"
      && ( Core_IsStringStartsWith( _ObjectID, "SovietTruck_Transport")))
      //|| Core_IsStringStartsWith( _ObjectID, "Helicopter") ) )
    {
      // Convoy entered ambush 1 back attack zone
      /*
      Core_SendEventTo(
        "NaziTank_Ambusher_1 1",
        "OnAttackConvoy");
      Core_SendEventTo(
        "NaziTank_Ambusher_1 2",
        "OnAttackConvoy");
        */

      Core_BroadcastEvent( "OnAttackConvoy_1");
    }

    if ( _NavPointName == "NavPoint_Ambush_2"
      && Core_IsStringStartsWith( _ObjectID, "SovietTruck_Transport"))
    {
      // Convoy entered ambush 2 back attack zone
      /*
      Core_SendEventTo(
        "NaziTank_Ambusher_2 1",
        "OnAttackConvoy");
      Core_SendEventTo(
        "NaziTank_Ambusher_2 2",
        "OnAttackConvoy");
        */

      Core_BroadcastEvent( "OnAttackConvoy_2");
    }

    if ( _NavPointName == "NavPoint_Ambush_1"
      && Core_IsStringStartsWith( _ObjectID, "SovietTruck_Transport") && !PlatoonAIsMoving)
    {
      PlatoonAIsMoving = true;
      Core_BroadcastEvent("Attack_A");
    }

    if ( _NavPointName == "NavPoint_Ambush_2"
      && Core_IsStringStartsWith( _ObjectID, "SovietTruck_Transport") && !PlatoonBIsMoving)
    {
      PlatoonBIsMoving = true;
      Core_BroadcastEvent("Attack_B");
    }
    if ( _NavPointName == "NavPoint_PatrolA"
      && Core_IsStringStartsWith( _ObjectID, "NaziTank_AttackA") && !PlatoonAIsAttacks)
    {
      PlatoonAIsAttacks = true;
      Core_BroadcastEvent("AttackTarget_A");
    }
    if ( _NavPointName == "NavPoint_PatrolB"
      && Core_IsStringStartsWith( _ObjectID, "NaziTank_AttackB") && !PlatoonBIsAttacks)
    {
      PlatoonBIsAttacks = true;
      Core_BroadcastEvent("AttackTarget_B");
    }
  }
}


//
// *** Autocade ***
//
// soviet transports convoy

class CConvoyMission_SovietTruck_ConvoyTransport extends CBaseAITask_BaseTask, CNavPointUser
{
  //
  // convoy parameters

  vector   DestinationPoint        = GetNavPoint("NavPoint_Destination");//vector( 474 * 8, 1883 * 8, 0); // where to go
  float    CruiserSpeed            = 22; // autocade with guard should keep this speed
  float    RunSpeed                = 28; // autocade wo guards should keep this speed
  float    OvertakeSpeed           = 34; // maximum allowed speed for overtake
  float    AutocadDistanceMin      = 20; // nearest allowed distance in autocade
  float    AutocadDistanceOptimum  = 25; // try to keep this distance in autocade
  float    AutocadDistanceOvertake = 40; // overtake distance
  float    DisperceRadius          = 50;
  string   CurLeader               = "";
  boolean  IsLeader                = false;


  //
  // current state

  boolean  Moving   = false; // true when object is moving to destination
  boolean  Ambushed = false; // true when object is under ambush
  boolean  Run      = false; // true when object is running without stop to destination

  void ClearState()
  {
    Moving    = false;
    Ambushed  = false;
    Run       = false;
    CurLeader = "";
    IsLeader  = false;
  }


  //
  // start up initialization

  void Init()
  {
    // give start order
    GiveOrder_MoveToTarget();
  }


  //
  // orders

  void GiveOrder_MoveToTarget()
  {
    //Core_LogMessage("" + Core_GetIdentificator() + ": order: move to target");

    SetFireStyle_NoFire();

    string Leader = GetCommander("Convoy_Rank"); // find leader that we should followed by
    if ( Moving == true
      && Leader == CurLeader)
    {
      // nothing changed
      return;
    }

    // set state
    ClearState();
    Moving = true;
    CurLeader = Leader;

    if ( Leader == "")
    {
      // we are leader. go directly to destination
      SetOrder_MoveTo(
        DestinationPoint,
        CruiserSpeed);
    }
    else
    {
      // leader found. follow him
      SetOrder_Follow(
        Leader, // follow leader
        AutocadDistanceMin,
        AutocadDistanceOptimum,
        AutocadDistanceOvertake,
        CruiserSpeed,
        OvertakeSpeed);
    };
  }

  void GiveOrder_RunToTarget()
  {
    //Core_LogMessage("" + Core_GetIdentificator() + ": order: run to target");

    string Leader = GetCommander("Convoy_Rank"); // find leader that we should followed by
    if ( Run == true
      && Leader == CurLeader)
    {
      // nothing changed
      return;
    }

    // set state
    ClearState();
    Run = true;

    CurLeader = Leader;

    if ( Leader == "")
    {
      // we are leader. go directly to destination
      SetOrder_MoveTo(
        DestinationPoint,
        RunSpeed);
    }
    else
    {
      // leader found. follow him
      SetOrder_Follow(
        Leader, // follow leader
        AutocadDistanceMin,
        AutocadDistanceOptimum,
        AutocadDistanceOvertake,
        RunSpeed,
        OvertakeSpeed);
    };
  }

  void GiveOrder_Disperse()
  {
    //Core_LogMessage("" + Core_GetIdentificator() + ": order: disperce");

    // set state
    ClearState();
    Ambushed = true;

    SetOrder_StopNow();

/*
    string Leader = GetCommander("Convoy_Rank"); // find leader that we should followed by
        if ( Leader == "")
        {
            SetOrder_StopNow();
        }
*/

/*
        // move to random point
        SetOrder_MoveTo(
            GetNowPosition() + vector( rand(DisperceRadius), rand(DisperceRadius), 0.0),
            OvertakeSpeed);
*/
  }


  //
  // events

  void OnToDamage(
    float   _DamageRate,
    string  _TargetId,
    string  _SourceType,
    matrix  _SourcePlace)
  {
    Core_LogMessage("" + Core_GetIdentificator() + ": OnToDamage");

    //string EnemyID = GetTargetedEnemy();

    // report ambush
    Core_BroadcastEvent("OnAmbush");
  }

  void OnEnemyTargeted()
  {
  //#TMP: do not look for enemies
  /*
    //Core_LogMessage("" + Core_GetIdentificator() + ": OnEnemyTargeted");

    //string EnemyID = GetTargetedEnemy();

    // report ambush
    Core_BroadcastEvent("OnAmbush");
    */
  }

  void OnNoEnemy()
  {
    //Core_LogMessage("" + Core_GetIdentificator() + ": OnNoEnemy");

    if ( Run == true)
      return;

    if ( Ambushed
      && GetCommander("Convoy_Rank") == "")
    {
      // end ambush when commander see no enemy on radar
      Core_BroadcastEvent("OnEndAmbush");
    }
  }

  void OnLeaderLost( string _LeaderID)
  {
    if ( Moving)
    {
      GiveOrder_MoveToTarget();
    }

    if ( Run)
    {
      GiveOrder_RunToTarget();
    }
  }

  void OnUpdate()
  {
    /*
        Core_LogMessage("" + Core_GetIdentificator() + ": OnUpdate");

        if ( Retreat == true)// || Run == true)
            return;

    Core_LogMessage("" + Core_GetIdentificator() + ": OnUpdate: state passed");
     */

    if ( GetGroupObjectsNum("Guard_Rank") == 0) // no guardians left
    {
      GiveOrder_RunToTarget();

      return;
    };

    if ( Ambushed
      && GetCommander("Convoy_Rank") == "" // we are commander in group
      && GetTargetedEnemy() == "")                 // and cannot see enemy in radar
    {
      // end ambush when commander see no enemy on radar
      Core_BroadcastEvent("OnEndAmbush");
    }
  }

  void OnAmbush()
  {
    if ( Run == true)
      return;

    if ( ! Ambushed)
    {
      //Core_LogMessage("--- Ambush!!!");
      if ( GetGroupObjectsNum("Guard_Rank") > 0)
      {
        GiveOrder_Disperse();
      }
    }
  }

  void OnEndAmbush()
  {
    if ( Run == true)
      return ;

    //Core_LogMessage("=== EndAmbush!!!");
    GiveOrder_MoveToTarget();
  }
};

class CConvoyMission_SovietTank_ConvoyGuard extends CConvoyMission_SovietTruck_ConvoyTransport
{
  //
  // additional state for guardians

  boolean  Defend = false; // true when object is defending convoy

  void ClearState()
  {
    Moving    = false;
    Ambushed  = false;
    Run       = false;
    Defend    = false;
    CurLeader = "";
    IsLeader  = false;
  }

  //
  // events

  void OnAmbush()
  {
    if ( ! Ambushed)
    {
      //Core_LogMessage("+++ Ambush!!!");
      GiveOrder_AttackEnemy();
    }
  }

  void GiveOrder_AttackEnemy()
  {
    //Core_LogMessage("" + Core_GetIdentificator() + ": order: line formation");

    SetFireStyle_Nearest();

    // set state
    ClearState();
    Defend   = true;
    Ambushed = true;

    string NearestEnemy = GetTargetedEnemy();

    if ( NearestEnemy == "")
      NearestEnemy = GetNearestEnemyUnit_Ranged(1000.0);

    if ( NearestEnemy != "")
    {
      SetAttackStyle_DirectMove( true);
      SetOrder_Attack( NearestEnemy, 30.0, 120.0, 30.0);
      SetFireStyle_Enemy( NearestEnemy);
    };
  };
};


//
// *** Ambushes
//

class CConvoyMission_NaziTank_Ambusher extends CBaseAITask_BaseTask
{
  //
  // start up initialization

  void Init()
  {
    // give start order
    SetFireStyle_NoFire();
  }

  void OnEnemyTargeted()
  {
    string EnemyID = GetTargetedEnemy();
    SetFireStyle_Enemy( EnemyID);
  }

  void OnOrderedEnemyKilled()
  {
    string EnemyID = GetTargetedEnemy();
    if ( EnemyID != "")
    {
      SetFireStyle_Enemy( EnemyID);
    }
    else
    {
      SetFireStyle_Nearest();
    }
  }
}

class CConvoyMission_NaziTank_Attacker extends CBaseAITask_BaseTask
{
  //
  // start up initialization

  void Init()
  {
    // give start order
    SetFireStyle_NoFire();
  }

  void OnEnemyTargeted()
  {
    string EnemyID = GetTargetedEnemy();
    SetOrder_Attack( EnemyID, 100.0, 150.0, 12.0);
    SetFireStyle_Enemy( EnemyID);
  }

  void OnOrderedEnemyKilled()
  {
    string EnemyID = GetTargetedEnemy();
    if ( EnemyID != "")
    {
      SetOrder_Attack( EnemyID, 100.0, 150.0, 12.0);
      SetFireStyle_Enemy( EnemyID);
    }
    else
    {
      SetFireStyle_Nearest();
    }
  }
}

class CConvoyMission_NaziTank_TransportKiller extends CBaseAITask_BaseTask
{
  //
  // current state

  boolean AttackTruck = false;


  //
  // start up initialization

  void Init()
  {
    // give start order
    SetFireStyle_NoFire();
    SetRadarRestrictions("Truck"); // attack only trucks
  }


  //
  // events

  void OnToDamage(
    float   _DamageRate,
    string  _TargetId,
    string  _SourceType,
    matrix  _SourcePlace)
  {
    SetRadarRestrictions(); // attack everybody
    SetFireStyle_Nearest();
  }

  void OnEnemyTargeted()
  {
    string EnemyID = GetTargetedEnemy();
    SetOrder_Attack( EnemyID, 100.0, 150.0, 12.0);
    SetFireStyle_Enemy( EnemyID);
    AttackTruck = true;
  }

  void OnOrderedEnemyKilled()
  {
    string EnemyID = GetTargetedEnemy();
    if ( EnemyID != "")
    {
      SetOrder_Attack( EnemyID, 100.0, 150.0, 12.0);
      SetFireStyle_Enemy( EnemyID);
      AttackTruck = true;
    }
    else
    {
      SetFireStyle_Nearest();
    }
  }
}


//
// *** special attackers
//

class CConvoyMission_NaziTank_BackAttacker_1 extends CBaseAITask_BaseTask
{
  //
  // current state

  boolean  Attacking = false;


  //
  // start up initialization

  void Init()
  {
    // give start order
    SetFireStyle_NoFire();
  }

  void OnAttackConvoy_1()
  {
    if ( !Attacking)
    {
      Core_LogMessage("" + Core_GetIdentificator() + ": order: Attack Convoy");

      string EnemyID = GetLastSlave("Convoy_Rank");
      SetOrder_Attack( EnemyID, 100.0, 150.0, 55.0);
      SetFireStyle_Enemy( EnemyID);

      Attacking = true;
    };
  }

  void OnOrderedEnemyKilled()
  {
    Core_LogMessage("" + Core_GetIdentificator() + ": order: ReAttack Convoy");

    string EnemyID = GetLastSlave("Convoy_Rank");
    if ( EnemyID != "")
    {
      SetOrder_Attack( EnemyID, 100.0, 150.0, 55.0);
      SetFireStyle_Enemy( EnemyID);
    }
    else
    {
      SetFireStyle_Nearest();
    }
  }
}

class CConvoyMission_NaziTank_BackAttacker_2 extends CBaseAITask_BaseTask
{
  //
  // current state

  boolean  Attacking = false;


  //
  // start up initialization

  void Init()
  {
    // give start order
    SetFireStyle_NoFire();
  }

  void OnAttackConvoy_2()
  {
    if ( !Attacking)
    {
      Core_LogMessage("" + Core_GetIdentificator() + ": order: Attack Convoy");

      string EnemyID = GetLastSlave("Convoy_Rank");
      SetOrder_Attack( EnemyID, 100.0, 150.0, 55.0);
      SetFireStyle_Enemy( EnemyID);

      Attacking = true;
    }
  }

  void OnOrderedEnemyKilled()
  {
    Core_LogMessage("" + Core_GetIdentificator() + ": order: ReAttack Convoy");

    string EnemyID = GetLastSlave("Convoy_Rank");
    if ( EnemyID != "")
    {
      SetOrder_Attack( EnemyID, 100.0, 150.0, 55.0);
      SetFireStyle_Enemy( EnemyID);
    }
    else
    {
      SetFireStyle_Nearest();
    }
  }
}

class NaziPatrol_A extends CBaseAITask_Patrol, CNavPointUser
{
//  void Init()
//  {
//  }
  array GetPatrolTrip()
  {
    return array (GetNavPoint("NavPoint_Ambush_2"),
                  GetNavPoint("NavPoint_Ambush_1"));
  }
  float GetTripSpeed()
  {
    return 26;
  }
}

class NaziPatrol_B extends CBaseAITask_Patrol, CNavPointUser
{
//  void Init()
//  {
//  }
  array GetPatrolTrip()
  {
    return array (vector(5377.0, 9814.0, 0.0),
                  GetNavPoint("NavPoint_Ambush_2"));
  }
  float GetTripSpeed()
  {
    return 26;
  }
}
//==================================================================
class AttackPlatoon_A extends CBaseAITask_BaseTask, CNavPointUser
{
  int StartTime = 0;
  int CurrentTime = 0;
  boolean Started = false;
  final int TimeToStart = 220000;

  void Attack_A()
   {
     StartTime = GetGameTime();
   }

  void  OnUpdate()
   {
     CurrentTime = GetGameTime();
     if( CurrentTime >= (StartTime+TimeToStart) && !Started && StartTime > 0 )
       {
         Started = true;
         MoveToPointA();
//       DoAttack();
//         Core_LogMessage("Attack A has started. Time after convoy is "+(CurrentTime-StartTime));
       }
   }

  void MoveToPointA()
   {
     SetOrder_MoveTo( GetNavPoint("NavPoint_PatrolA"), 26 );
   }

  void AttackTarget_A()
    {
      DoAttack();
    }

  void DoAttack()
  {
    string NearestEnemy = GetTargetedEnemy();

    if ( NearestEnemy == "")
    {
      NearestEnemy = GetNearestEnemyUnit();
    };

    SetOrder_Attack( NearestEnemy, 100.0, 150.0, 27.0);
    SetFireStyle_Enemy( NearestEnemy );

  }

  void OnOrderedEnemyKilled()
  {
    SetFireStyle_Nearest();
    DoAttack();
  }
}
//------------------------------------------------------------------
class AttackPlatoon_B extends CBaseAITask_BaseTask, CNavPointUser
{
  int StartTime = 0;
  int CurrentTime = 0;
  boolean Started = false;
  final int TimeToStart = 130000;

  void Attack_B()
   {
     StartTime = GetGameTime();
   }

  void  OnUpdate()
   {
     CurrentTime = GetGameTime();
     if( CurrentTime >= (StartTime+TimeToStart) && !Started && StartTime > 0 )
       {
         Started = true;
         MoveToPointB();
//         DoAttack();
       }
   }

  void MoveToPointB()
   {
     SetOrder_MoveTo( GetNavPoint("NavPoint_PatrolB"), 26 );
   }

  void AttackTarget_B()
    {
      DoAttack();
    }

  void DoAttack()
  {
    string NearestEnemy = GetTargetedEnemy();

    if ( NearestEnemy == "")
    {
      NearestEnemy = GetNearestEnemyUnit();
    };

    SetOrder_Attack( NearestEnemy, 100.0, 150.0, 27.0);
    SetFireStyle_Enemy( NearestEnemy );

  }

  void OnOrderedEnemyKilled()
  {
    SetFireStyle_Nearest();
    DoAttack();
  }
}


