//-------------------------------------------------------------------
//
//  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.
//
//-------------------------------------------------------------------

class CHelicopterMesh
{
  string MeshFile = "Models/Helicopter.mesh";
  string SkinFile = "Models/Helicopter.skin";
  string AnimFile = "Models/Helicopter.anim";
}

class CHelicopterSmokeGenerator
{
  string DustItemEffect = "EFFECTID_HelicopterSmokeTrackEffect";
  float  ItemsPerSecond = 1000.0;

  void StartSmokeGeneration()
  {
    EnableDustGeneration();
  }

  void StopSmokeGeneration()
  {
    DisableDustGeneration();
  }
}

class CHelicopterCollision
{
  float  MaxPositionHeight   = 1100.0f;
  float  PositionRestriction = 500.0f;
  float  RotationSpeed       = 4.0f;
  float  RotateReturnSpeed   = 0.5f;
  float  MaxRotationAngle    = Math_HALFPI * 0.5f;
  float  ThrowMoveFactor     = 0.15;
  float  ThrowRotateFactor   = 0.01f;
  float  ThrowMoveDamper     = 0.5f;
  string CollisionJointName  = "Hull_Collision_Map";
  string CollisionEffect     = "";
  string CollisionSound      = "SOUNDID_HelicopterCollisionSound";

  void DisableCollisionControl()
  {
    EnableObjectControl(false);
  }

  void SetTerrainCollisionMode()
  {
    RestrictCollisionTo(CLASSIFICATOR_TERRAIN);
  }
}

class CHelicopterCameraLinkControl
{
  void CHelicopterCameraLinkControl()
  {
    SetDefaultCameraView();
  }

  int m_CurrentViewMode = 0;
  void OnSetCameraView(
      int _ViewType
    )
  {
    if (CVT_DefaultView == _ViewType)
      SetDefaultCameraView();
    else
    if (CVT_NextView == _ViewType)
      SetCameraView(m_CurrentViewMode + 1);
  }

  void SetDefaultCameraView()
  {
    SetCameraView(0);
  }

  void SetCameraView(
      int _Mode
    )
  {
    m_CurrentViewMode = _Mode % 7;

    string RenderMode = CRM_Cocpit;
    if (0 != _Mode)
      RenderMode = CRM_WideScreen;

    Core_SendEventTo(
        Core_GetIdentificator(),
        "SetCocpitRenderMode",
        RenderMode
      );

    if (0 == _Mode)
    {
      SetCameraPosition(CRDSYS_Local, vector(-34.0, 0.0, -4.0), -1.0, 12.0);
      SetCameraViewTarget(CRDSYS_Local, vector(4000.0, 0.0, 0.0), true, -1.0);
      return;
    }
    else
    if (1 == _Mode)
    {
      SetCameraPosition(CRDSYS_Origin, vector(-1.0, 0.0, 0.0), -1.0, 30.0);
      SetCameraViewTarget(CRDSYS_Local, vector(0.0, 0.0, 0.0), false, -1.0);
      return;
    }
    else
    if (2 == _Mode)
    {
      SetCameraPosition(CRDSYS_Local, vector(25.0, 0.0, 0.0), -1.0, 10.0);
      SetCameraViewTarget(CRDSYS_Local, vector(0.0, 0.0, 0.0), false, -1.0);
      return;
    }
    else
    if (3 == _Mode)
    {
      SetCameraPosition(CRDSYS_Local, vector(0.0, 25.0, 0.0), -1.0, 10.0);
      SetCameraViewTarget(CRDSYS_Local, vector(0.0, 0.0, 0.0), false, -1.0);
      return;
    }
    else
    if (4 == _Mode)
    {
      SetCameraPosition(CRDSYS_Local, vector(0.0, -25.0, 0.0), -1.0, 10.0);
      SetCameraViewTarget(CRDSYS_Local, vector(0.0, 0.0, 0.0), false, -1.0);
      return;
    }

    SetDefaultCameraView();
  }

  void ShowHelicopterDeath()
  {
    vector CameraPosition = Core_GetMatrixOrigin(GetCurrentCameraPosition());
    vector ObjectPosition = Core_GetMatrixOrigin(GetCurrentObjectPosition());

    vector Position = CameraPosition - ObjectPosition;
    Position = vector(Core_GetVectorX(Position), Core_GetVectorY(Position), 0.0);
    Position = (150.0 / Core_Magnitude(Position)) * Position + vector(0.0, 0.0, 40.0);

    SetCameraPosition(CRDSYS_Origin, Position, 35.0, 0.0);
    SetCameraViewTarget(CRDSYS_Origin, vector(0.0, 0.0, 0.0), false, Math_PI * 0.1);
  }

  void ShowHelicopterFinal()
  {
    vector CameraPosition = Core_GetMatrixOrigin(GetCurrentCameraPosition());
    vector ObjectPosition = Core_GetMatrixOrigin(GetCurrentObjectPosition());

    vector Position = CameraPosition - ObjectPosition;
    Position = vector(Core_GetVectorX(Position), Core_GetVectorY(Position), 0.0);
    Position = (75.0 / Core_Magnitude(Position)) * Position + vector(0.0, 0.0, 25.0);

    SetCameraPosition(CRDSYS_Origin, Position, 10.0, 0.0);
  }
}

class CHelicopterStateControl extends CUnitLifeControl, CDifficultyLevel
{
  bool m_FreeFallEnabled = false;
  bool m_ObjectDetonated = false;

  void CHelicopterStateControl()
  {
    CUnitLifeControl(GetHelicopterHP());
    m_DestroyPause = 0.0;
    m_ExplosionId  = "";
    m_SplashOnHit  = false;
  }

  void HitpointsWasChanged(
      float _NowHitpoints
    )
  {
    Core_SendEventTo(Core_GetIdentificator(),
      "OnHitpointsWasChanged", _NowHitpoints / m_MaxHitpoints);
  }

  void DestroyComponent()
  {
    Core_SendEventTo(
      Core_GetIdentificator(),
      "OnSetCameraView",
      CVT_DefaultView);

    Core_SendEventTo(
      Core_GetIdentificator(),
      "StartFreeFall",
      GetUnitSpeed());

    Core_SendEventTo(
      Core_GetIdentificator(),
      "StartSmokeGeneration");

    // make spherical damage on collision
    Core_DistributeEvent(
        1.0,
        "OnDetonation",
        "SphericExplosion",   // source type (explosion type)
        GetUnitPosition(),  // source place
        50.0
      );

    Core_SendEventTo(Core_GetIdentificator(), "ShowHelicopterDeath");

    m_FreeFallEnabled = true;
  }

  void OnCollisionOccured(
      float _fPower
    )
  {
    bool ToDestroy = m_IsExploded;

    OnToDamage(
        GetCollisionDamageFactor() * m_MaxHitpoints * _fPower / m_DeathPower,
        Core_GetIdentificator(),
        "Collision",
        GetUnitPosition()
      );

    if (!m_FreeFallEnabled || !ToDestroy)
      return;

    if (m_ObjectDetonated)
      return;
    m_ObjectDetonated = true;

    Core_SendEventTo(Core_GetIdentificator(), "StopEngineSound");
    Core_SendEventTo(Core_GetIdentificator(), "StopFreeFall");
    Core_SendEventTo(Core_GetIdentificator(), "ShowHelicopterFinal");
    Core_SendEventTo(Core_GetIdentificator(), "StartSmokeGeneration");

    Core_CallFunction(
      "Explosions",
      "CreateExplosion",
      "EXPLID_HelicopterExplosion",
      GetUnitPosition());

    Core_CallFunction(
      "Effects",
      "CreateEffect",
      "EFFECTID_HelicopterSmokeEffect",
      GetUnitPosition());

    GenerateBullets(
        50,
        "BULLETID_ExplosionFireSplash",
        array(0.0, Math_HALFPI),
        0,
        array(0.0, 3.0),
        array(70.0, 90.0),
        GetUnitPosition()
      );

    GenerateBullets(
        10,
        "BULLETID_ExplosionSmokeSplash",
        array(0.0, Math_HALFPI),
        0,
        array(0.0, 1.5),
        array(40.0, 50.0),
        GetUnitPosition()
      );

    // Destroy object
    Core_PostEventTo(
        SOID_MissionController,
        "DestroyGameObject",
        Core_GetIdentificator()
      );
  }

  void ConsoleCommand_SetImmortalMode(
      bool _ImmortalMode
    )
  {
    m_ImmortalMode = _ImmortalMode;
    if (m_ImmortalMode)
      Core_LogMessage("immortal mode on");
    else
      Core_LogMessage("immortal mode off");
  }
}

class CHelicopterFreeFallControl extends CWorldPhysics
{
  void CHelicopterFreeFallControl()
  {
    EnableFreeFall(false);
  }

  void StartFreeFall(
      vector _InitSpeed
    )
  {
    Core_SendEventTo(
      Core_GetIdentificator(),
      "DisableCollisionControl");

    Core_SendEventTo(
      Core_GetIdentificator(),
      "SetTerrainCollisionMode");

    Core_CallFunction(
        SOID_GameController,
        "EnableControl",
        Core_GetIdentificator(),
        false
      );

    SetFreeFallSpeed(_InitSpeed);
    SetFreeFallAccel(g_Gravity);
    SetFreeFallAngle(Math_PI * 0.05, Math_PI * 0.001);

    EnableFreeFall(true);
  }

  void StopFreeFall()
  {
    EnableFreeFall(false);
  }
}

class CHelicopterRotorAnimator
{
  string AnimationName = "rotor";
  float  SpeedFactor   = 0.15;
}

class CHelicopterGun extends CBaseWeaponDescriptor
{
  int    AmmoQuantity      = -1;
  float  BulletSpeed       = 600.0;
  float  FireDeviation     = 0.005;
  string BulletPatternId   = "BULLETID_HelicopterGunBullet";
  string LinkJointName     = "_Gun_Fire_01";
  string EffectOnFire      = "EFFECTID_HelicopterGunFireEffect";
  string SoundOnFire       = "SOUNDID_HelicopterGunFireSound";
  float  TargetingRange    = 3.0;

  string WeaponName        = "Gun";
  float  FireWeaponDelay   = 0.15;
  bool   IsAutotargeting   = false;
  int    AttachSlotNumber  = 0;
}

class CHelicopterMissileWeapon extends CBaseWeaponDescriptor
{
  void ConsoleCommand_LoadFullAmmo()
  {
    ResetAmmoQuantity();
  }

  void ConsoleCommand_SetUnlimitedAmmo(
      bool _Unlimited
    )
  {
    if (_Unlimited)
      ResetAmmoQuantity();

    SetUnlimitedAmmo(_Unlimited);

    if (_Unlimited)
      Core_LogMessage("unlimited ammo on");
    else
      Core_LogMessage("unlimited ammo off");
  }
}

class CHelicopterS8Launcher extends CHelicopterMissileWeapon, CDifficultyLevel
{
  int    AmmoQuantity      = GetS8MissileQuantity();
  float  BulletSpeed       = 250.0;
  float  FireDeviation     = 0.0;
  string LinkJointName     = "";
  string EffectOnFire      = "";
  string FireCloudEffect   = "EFFECTID_HelicopterRocketFireCloudEffect";
  string SoundOnFire       = "SOUNDID_HelicopterMissileFireSound";
  float  TargetingRange    = 5.0;

  float  FireWeaponDelay   = 1.0;
  bool   IsAutotargeting   = false;
  string BulletPatternId   = "BULLETID_HelicopterRocket";

  bool   NotifyOnFire      = true;
}

class CHelicopterVikhrLauncher extends CHelicopterMissileWeapon, CDifficultyLevel
{
  int    AmmoQuantity      = GetVikhrMissileQuantity();
  float  BulletSpeed       = 200.0;
  float  FireDeviation     = 0.0;
  string LinkJointName     = "";
  string EffectOnFire      = "";
  string FireCloudEffect   = "EFFECTID_HelicopterRocketFireCloudEffect";
  string SoundOnFire       = "SOUNDID_HelicopterMissileFireSound";
  float  TargetingRange    = 0.0;

  float  FireWeaponDelay   = 1.0;
  bool   IsAutotargeting   = true;
  string BulletPatternId   = "BULLETID_HelicopterMissile";

  bool   NotifyOnFire      = true;
}

class CHelicopterMissileLauncher_1 extends CHelicopterVikhrLauncher
{
  string LinkJointName     = "_Gun_Fire_05";
  string WeaponName        = "Launcher 1";
  int    AttachSlotNumber  = 1;
}

class CHelicopterMissileLauncher_2 extends CHelicopterS8Launcher
{
  string LinkJointName     = "_Gun_Fire_04";
  string WeaponName        = "Launcher 2";
  int    AttachSlotNumber  = 2;
}

class CHelicopterMissileLauncher_3 extends CHelicopterS8Launcher
{
  string LinkJointName     = "_Gun_Fire_02";
  string WeaponName        = "Launcher 3";
  int    AttachSlotNumber  = 3;
}

class CHelicopterMissileLauncher_4 extends CHelicopterVikhrLauncher
{
  string LinkJointName     = "_Gun_Fire_03";
  string WeaponName        = "Launcher 4";
  int    AttachSlotNumber  = 4;
}

class CHelicopter extends
  CFlyingUnit, CArmedUnit, CUnitWithSound, CUnitWithCamera, CUnitWithStateControl
{
  void CreateRotorEffect(
      string Name,
      string Joint
    )
  {
    CreateComponent(Name + "Effect", "StaticEffect", "CHelicopterRotorEffect");
    CreateComponent(Name + "Link", "ObjectEffectLink");
    SetComponentSlaveObject(Name + "Link", Name + "Effect");
    SetComponentPositionable(Name + "Link", "Mesh", Joint);
  }

  void CHelicopter()
  {
    InitializeModelAsAnimated("CHelicopterMesh");
    InitializeSound("CHelicopterEngineSound");
    InitializeCamera("CHelicopterCameraLinkControl");
    CUnitWithStateControl("CHelicopterStateControl");

    CreateComponent("Rotor", "CircledAnimator", "CHelicopterRotorAnimator");
    SetComponentSlaveObject("Rotor", "Mesh");

    CreateStaticWeapon("Weapon", "CHelicopterGun");

    CreateStaticWeapon("Missile_1", "CHelicopterMissileLauncher_1");
    CreateStaticWeapon("Missile_2", "CHelicopterMissileLauncher_2");
    CreateStaticWeapon("Missile_3", "CHelicopterMissileLauncher_3");
    CreateStaticWeapon("Missile_4", "CHelicopterMissileLauncher_4");

    CreateComponent("Collision", "CollisionControl", "CHelicopterCollision");
    SetComponentSlaveObject("Collision", "Mesh");

    CreateRotorEffect("RotorUp", "RH_up");
    CreateRotorEffect("RotorDown", "RH_down");

    CreateComponent("FreeFall", "FreeFallControl", "CHelicopterFreeFallControl");
    SetComponentSlaveObject("FreeFall", "Mesh");

    CreateComponent("SmokeGenerator", "DustGenerator", "CHelicopterSmokeGenerator");
    SetComponentPositionable("SmokeGenerator", "Mesh");

    Core_AddClassificator("FlyingUnit"); // for behavior fire logic
  }
}

class CSovietHelicopter extends CHelicopter
{
  void CSovietHelicopter()
  {
    Core_AddClassificator("Russian");
  }
}

class CPlayerSovietHelicopter extends CSovietHelicopter
{
  void CPlayerSovietHelicopter()
  {
    // Create movement manual control
    CreateComponent("Manual", "ManualObjectControl");
    SetComponentSlaveObject("Manual", "Mesh");

    // Create and initialize cockpit
    CreateComponent("Cockpit", "Cockpit", "CHelicopterCockpit");
    SetComponentPositionable("Cockpit", "Mesh");

    for (int Index = 0; Index < m_WeaponNames.size(); Index = Index + 1)
      SetComponentSlaveObject("Cockpit", m_WeaponNames[Index]);

    // this classificator marks the model controlled by player in the game
    // it is used by ShadowRender to select the shadow page of the
    // corresponding size
    Core_AddClassificator(CLASSIFICATOR_PLAYER_MODEL);
    Core_AddClassificator(CLASSIFICATOR_CONTROLLABLE);
  }
}

