//-------------------------------------------------------------------
//
//  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 CHelicopterRotorEffect
{
  final static string CID = "StaticEffect";

  void CHelicopterRotorEffect()
  {
    CreateParticle(
        EPPID_STATIC_PLANE_XY,
        vector(0.0, 0.0, 0.0),
        vector(6.0, 6.0, 6.0),
        5,
        color(1.0, 1.0, 1.0, 0.8),
        vector(1.0, 1.0, 1.0)
      );
  }
}

// helper classes
class CSingleParticleAnimator
{
  int   m_AnimFramesQty = 64;
  float m_SizeFactor    = 1.0;

  float m_SizePower     = 0.75;
  float m_PlacePower    = 1.0;
  color m_BaseColor     = color(1.0, 1.0, 1.0, 1.0);

  void GenerateParticleAnimation(
      int    _Particle,
      int    _StartFrame,
      vector _StartPlace,
      vector _FinalPlace,
      vector _BaseSize,
      int    _MaterialBase,
      float  _TimeScale
    )
  {
    SetPattern(_Particle, _StartFrame, _StartFrame + m_AnimFramesQty * _TimeScale, EPPID_BILLBOARD_PLANE);
    SetColor(_Particle, m_BaseColor);

    for (int FrameNum = 0; FrameNum < m_AnimFramesQty * _TimeScale; FrameNum = FrameNum + 1)
    {
      float Phase = float(FrameNum) / float(m_AnimFramesQty * _TimeScale - 1);
      SetMaterial(_Particle, _StartFrame + FrameNum, _MaterialBase + (m_AnimFramesQty - 1) * Phase);
      SetPosition(_Particle, _StartFrame + FrameNum,
        (_StartPlace + (_FinalPlace - _StartPlace) * pow(Phase, m_PlacePower)) * m_SizeFactor);
      SetSizeFactor(_Particle, _StartFrame + FrameNum, _BaseSize * m_SizeFactor);
    }

    // all other frames is NULL by default
  }

  void GenerateParticleAnimation(
      int    _Particle,
      int    _StartFrame,
      vector _StartPlace,
      vector _FinalPlace,
      vector _StartSize,
      vector _FinalSize,
      int    _MaterialBase,
      float  _TimeScale
    )
  {
    SetPattern(_Particle, _StartFrame, _StartFrame + m_AnimFramesQty * _TimeScale, EPPID_BILLBOARD_PLANE);
    SetColor(_Particle, m_BaseColor);

    for (int FrameNum = 0; FrameNum < m_AnimFramesQty * _TimeScale; FrameNum = FrameNum + 1)
    {
      float Phase = float(FrameNum) / float(m_AnimFramesQty * _TimeScale - 1);
      SetMaterial(_Particle, _StartFrame + FrameNum, _MaterialBase + (m_AnimFramesQty - 1) * Phase);
      SetPosition(_Particle, _StartFrame + FrameNum,
        (_StartPlace + (_FinalPlace - _StartPlace) * pow(Phase, m_PlacePower)) * m_SizeFactor);
      SetSizeFactor(_Particle, _StartFrame + FrameNum,
        (_StartSize + (_FinalSize - _StartSize) * pow(Phase, m_SizePower)) * m_SizeFactor);
    }

    // all other frames is NULL by default
  }
}

class CFramesTableCreator
  extends CSingleParticleAnimator
{
  float  m_SmokeHeight = 50.0;
  vector m_BasePlace   = vector(0.0, 0.0, 0.0);
  float  m_StartShift  = 0.0;
  float  m_ShiftFactor = 0.2;

  void GenerateSmokeTable(
      int _StartPlane,
      int _FinalPlane
    )
  {
    for (int Plane = _StartPlane; Plane < _FinalPlane; Plane = Plane + 1)
    {
      vector Direction = vector(rand(m_SmokeHeight * m_ShiftFactor), rand(m_SmokeHeight * m_ShiftFactor), 0.0);

      GenerateParticleAnimation(
        Plane, 0,
        m_BasePlace + Direction * m_StartShift,
        m_BasePlace + Direction + vector(0.0, 0.0, m_SmokeHeight),
        vector(2.0, 2.0, 4.0), vector(5.0, 5.0, 5.0),
        300, 1.0);
    }
  }

  void GenerateWhiteSmokeTable(
      int _StartPlane,
      int _FinalPlane
    )
  {
    for (int Plane = _StartPlane; Plane < _FinalPlane; Plane = Plane + 1)
    {
      vector Direction = vector(rand(m_SmokeHeight * m_ShiftFactor), rand(m_SmokeHeight * m_ShiftFactor), 0.0);

      GenerateParticleAnimation(
        Plane, 0,
        m_BasePlace + Direction * m_StartShift,
        m_BasePlace + Direction + vector(0.0, 0.0, m_SmokeHeight),
        vector(2.0, 2.0, 4.0), vector(5.0, 5.0, 5.0),
        500, 1.0);
    }
  }

  void GenerateFireSmokeTable(
      int _StartPlane,
      int _FinalPlane
    )
  {
    for (int Plane = _StartPlane; Plane < _FinalPlane; Plane = Plane + 1)
    {
      vector Direction = vector(rand(m_SmokeHeight * m_ShiftFactor), rand(m_SmokeHeight * m_ShiftFactor), 0.0);

      GenerateParticleAnimation(
        Plane, 0,
        m_BasePlace + Direction * m_StartShift,
        m_BasePlace + Direction + vector(0.0, 0.0, m_SmokeHeight),
        vector(2.0, 2.0, 4.0), vector(5.0, 5.0, 5.0),
        400, 1.0);
    }
  }

  void GenerateFireTable(
      int _StartPlane,
      int _FinalPlane
    )
  {
    for (int Plane = _StartPlane; Plane < _FinalPlane; Plane = Plane + 1)
    {
      GenerateParticleAnimation(
        Plane, 0,
        m_BasePlace, m_BasePlace + vector(rand(1.5), rand(1.5), rand(1.0, 2.0)),
        vector(1.0, 1.0, 1.0), vector(1.0, 1.0, 1.0),
        400, 1.0);
    }
  }
}



// bullet trace effects
class CBaseBulletTraceEffect
{
  final static string CID = "StaticEffect";

  void CBaseBulletTraceEffect(
      color Color
    )
  {
    CreateParticle(
        EPPID_BILLBOARD_XAXIS,
        vector(3.0, 0.0, 0.0),
        vector(3.0, 0.1, 0.1),
        0,
        Color,
        vector(1.0, 1.0, 1.0)
      );
  }
}

class CRedBulletTraceEffect extends CBaseBulletTraceEffect
{
  void CRedBulletTraceEffect()
  {
    CBaseBulletTraceEffect(color(1.0, 0.3, 0.3, 1.0));
  }
}

class CGreenBulletTraceEffect extends CBaseBulletTraceEffect
{
  void CGreenBulletTraceEffect()
  {
    CBaseBulletTraceEffect(color(0.3, 1.0, 0.3, 1.0));
  }
}

class CBlueBulletTraceEffect extends CBaseBulletTraceEffect
{
  void CBlueBulletTraceEffect()
  {
    CBaseBulletTraceEffect(color(0.3, 0.3, 1.0, 1.0));
  }
}

class CYellowBulletTraceEffect extends CBaseBulletTraceEffect
{
  void CYellowBulletTraceEffect()
  {
    CBaseBulletTraceEffect(color(1.0, 1.0, 0.0, 1.0));
  }
}

class CMagentaBulletTraceEffect extends CBaseBulletTraceEffect
{
  void CMagentaBulletTraceEffect()
  {
    CBaseBulletTraceEffect(color(1.0, 0.5, 0.0, 1.0));
  }
}



// explosions
class CTankGunBulletHitEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CTankGunBulletHitEffect()
  {
    SetEffectDuration(2.0);
    UseIdentityMatrix(true);
    CreateFramesTable(2, 3 * m_AnimFramesQty);

    m_SizeFactor = 2.0;
    m_BaseColor  = color(1.0, 1.0, 1.0, 0.75);

    GenerateParticleAnimation(0, 0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0), vector(1.5, 1.5, 1.5), 200, 1.0);
    GenerateParticleAnimation(1, 0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 2.0), vector(0.5, 0.5, 2.0), vector(4.0, 4.0, 4.0), 400, 3.0);
  }
}

class CFlakGunBulletHitEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CFlakGunBulletHitEffect()
  {
    SetEffectDuration(2.0);
    UseIdentityMatrix(true);
    CreateFramesTable(2, 3 * m_AnimFramesQty);

    m_SizeFactor = 1.0;
    m_BaseColor  = color(1.0, 1.0, 1.0, 0.75);

    GenerateParticleAnimation(0, 0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0), vector(1.5, 1.5, 1.5), 200, 1.0);
    GenerateParticleAnimation(1, 0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 2.0), vector(0.5, 0.5, 2.0), vector(4.0, 4.0, 4.0), 400, 3.0);
  }
}

class CMissileExplosionEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CMissileExplosionEffect()
  {
    SetEffectDuration(2.5);
    UseIdentityMatrix(true);
    CreateFramesTable(2, m_AnimFramesQty *3 + 16);

    m_SizeFactor = 4.0;
    GenerateParticleAnimation(0,  0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0), vector(2.0, 2.0, 2.0), vector(10.0, 10.0, 4.0), 200, 2.0);
    GenerateParticleAnimation(1, 16, vector(0.0, 0.0, 0.5), vector(0.0, 0.0, 5.0), vector(0.5, 0.5, 2.0), vector(6.0, 6.0, 6.0), 400, 3.0);
  }
}

class CKatushaRocketExplosionEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CKatushaRocketExplosionEffect()
  {
    SetEffectDuration(5.0);
    UseIdentityMatrix(true);
    CreateFramesTable(3, m_AnimFramesQty * 6 + 48);

    m_SizeFactor = 6.0;
    GenerateParticleAnimation(0,  0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0), vector(2.0, 2.0, 2.0), vector(20.0, 20.0, 4.0), 200, 2.0);
    GenerateParticleAnimation(1, 32, vector(0.0, 0.0, 1.5), vector(0.0, 0.0, 3.0), vector(1.0, 1.0, 6.0), vector(6.0,  6.0,  6.0), 400, 3.0);
    GenerateParticleAnimation(2, 48, vector(0.0, 0.0, 3.0), vector(0.0, 0.0, 5.0), vector(6.0, 6.0, 6.0), vector(10.0, 10.0, 10.0), 300, 6.0);
  }
}

class CAirBombExplosionEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CAirBombExplosionEffect()
  {
    SetEffectDuration(5.0);
    UseIdentityMatrix(true);
    CreateFramesTable(3, m_AnimFramesQty * 6 + 48);

    m_SizeFactor = 6.0;
    GenerateParticleAnimation(0,  0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0), vector(2.0, 2.0, 2.0), vector(20.0, 20.0, 4.0), 200, 2.0);
    GenerateParticleAnimation(1, 32, vector(0.0, 0.0, 1.5), vector(0.0, 0.0, 3.0), vector(1.0, 1.0, 6.0), vector(6.0,  6.0,  6.0), 400, 3.0);
    GenerateParticleAnimation(2, 48, vector(0.0, 0.0, 3.0), vector(0.0, 0.0, 5.0), vector(6.0, 6.0, 6.0), vector(10.0, 10.0, 10.0), 300, 6.0);
  }
}

class CPanzerFaustExplosionEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CPanzerFaustExplosionEffect()
  {
    SetEffectDuration(1.5);
    UseIdentityMatrix(true);
    CreateFramesTable(1, m_AnimFramesQty);

    m_SizeFactor = 1.0;
    m_BaseColor  = color(1.0, 1.0, 1.0, 0.75);

    GenerateParticleAnimation(0, 0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0), vector(0.5, 0.5, 0.5), vector(4.0, 4.0, 4.0), 400, 1.0);
  }
}

class CHelicopterSmokeEffect
  extends CFramesTableCreator
{
  final static string CID = "SampledEffect";

  void CHelicopterSmokeEffect()
  {
    SetEffectDuration(30.0);
    UseIdentityMatrix(true);
    CreateFramesTable(20, m_AnimFramesQty);

    m_BaseColor   = color(1.0, 1.0, 1.0, 1.0);
    m_SizeFactor  = 7.0;
    m_SmokeHeight = rand(30.0, 40.0);

    GenerateSmokeTable(0, 10);
    GenerateFireTable(10, 20);

    for (float Time = 0.0; Time < 50.0; Time = Time + 1.0)
    {
      AddReference(rand_int(10), Time / 75.0, 0.25);
      AddReference(10 + rand_int(10), Time / 75.0, 0.05);
    }
  }
}

class CUnitExplosionEffect
  extends CFramesTableCreator
{
  final static string CID = "SampledEffect";

  void CUnitExplosionEffect()
  {
    SetEffectDuration(15.0);
    UseIdentityMatrix(true);
    CreateFramesTable(20, m_AnimFramesQty);

    m_BaseColor   = color(1.0, 1.0, 1.0, 1.0);
    m_SizeFactor  = 3.0;
    m_SmokeHeight = rand(25.0, 35.0);

    GenerateSmokeTable(0, 10);
    GenerateFireTable(10, 20);

    for (float Time = 0.0; Time < 25.0; Time = Time + 1.0)
    {
      AddReference(rand_int(10), Time / 50.0, 0.5);
      AddReference(10 + rand_int(10), Time / 50.0, 0.1);
    }
  }
}

class CItemExplosionEffect
  extends CFramesTableCreator
{
  final static string CID = "SampledEffect";

  void CItemExplosionEffect()
  {
    SetEffectDuration(15.0);
    UseIdentityMatrix(true);
    CreateFramesTable(20, m_AnimFramesQty);

    m_BaseColor   = color(1.0, 1.0, 1.0, 1.0);
    m_SizeFactor  = 3.0;
    m_SmokeHeight = rand(25.0, 35.0);

    GenerateSmokeTable(0, 10);
    GenerateFireTable(10, 20);

    for (float Time = 0.0; Time < 25.0; Time = Time + 1.0)
    {
      AddReference(rand_int(10), Time / 50.0, 0.5);
      AddReference(10 + rand_int(10), Time / 50.0, 0.1);
    }
  }
}

class CTreeExplosionEffect
  extends CFramesTableCreator
{
  final static string CID = "SampledEffect";

  void CTreeExplosionEffect()
  {
    SetEffectDuration(10.0 + rand(2.5));
    UseIdentityMatrix(true);
    CreateFramesTable(20, m_AnimFramesQty);

    m_ShiftFactor = 0.2;

    m_SizeFactor  = 3.0;
    m_StartShift  = 0.3;
    m_BasePlace   = vector(0.0, 0.0, 5.0);
    m_BaseColor   = color(1.0, 1.0, 1.0, 1.0);
    m_SmokeHeight = rand(15.0, 20.0);
    GenerateSmokeTable(0, 10);

    m_SizeFactor  = 2.0;
    m_StartShift  = 0.0;
    m_BasePlace   = vector(0.0, 0.0, 0.0);
    m_BaseColor   = color(1.0, 1.0, 1.0, 0.5);
    m_SmokeHeight = rand(7.5, 12.5);
    GenerateFireSmokeTable(10, 20);

    for (float Time = 0.0; Time < 10.0; Time = Time + 1.0)
    {
      AddReference(rand_int(10), Time / 20.0, 0.5);
      AddReference(10 + rand_int(10), Time / 30.0, 0.3);
    }
  }
}

class CBuildingExplosionEffect
  extends CFramesTableCreator
{
  final static string CID = "SampledEffect";

  void CBuildingExplosionEffect()
  {
    SetEffectDuration(30.0);
    UseIdentityMatrix(true);
    CreateFramesTable(20, m_AnimFramesQty);

    m_BaseColor   = color(1.0, 1.0, 1.0, 1.0);
    m_SizeFactor  = 5.0;
    m_SmokeHeight = rand(30.0, 40.0);

    GenerateSmokeTable(0, 10);
    GenerateFireTable(10, 20);

    for (float Time = 0.0; Time < 50.0; Time = Time + 1.0)
    {
      AddReference(rand_int(10), Time / 75.0, 0.25);
      AddReference(10 + rand_int(10), Time / 75.0, 0.05);
    }
  }
}

class CFireBallExplosionEffect
  extends CFramesTableCreator
{
  final static string CID = "SampledEffect";

  void CFireBallExplosionEffect()
  {
    int SmokeQuantity = 1 + rand_int(1);
    int PatternsQty   = 3;

    SetEffectDuration(10.0);
    UseIdentityMatrix(true);
    CreateFramesTable(SmokeQuantity * PatternsQty * 2 + 1, m_AnimFramesQty);

    m_BaseColor   = color(1.0, 1.0, 1.0, 1.0);
    m_SizeFactor  = 2.0;

    for (int Smoke = 0; Smoke < SmokeQuantity; Smoke = Smoke + 1)
    {
      m_BasePlace   = vector(rand(5.0), rand(5.0), 0.0);
      m_SmokeHeight = rand(10.0, 20.0);

      GenerateSmokeTable(Smoke * PatternsQty * 2, Smoke * PatternsQty * 2 + PatternsQty);
      GenerateFireTable(Smoke * PatternsQty * 2 + PatternsQty, Smoke * PatternsQty * 2 + PatternsQty * 2);

      for (float Time = 0.0; Time < 7.5; Time = Time + 1.0)
      {
        AddReference(Smoke * PatternsQty * 2 + rand_int(PatternsQty), Time / 20.0, 0.5);
        AddReference(Smoke * PatternsQty * 2 + PatternsQty + rand_int(PatternsQty), Time / 20.0, 0.2);
      }
    }

    m_SizeFactor = 2.0;
    GenerateParticleAnimation(SmokeQuantity * PatternsQty * 2, 0,
      vector(0.0, 0.0, 1.0), vector(0.0, 0.0, 2.0),
      vector(9.0, 9.0, 2.0), vector(15.0, 15.0, 4.0), 400, 1.0);
    AddReference(SmokeQuantity * PatternsQty * 2, 0.0, 0.1);
  }
}

class CSmallBarrelExplosionEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CSmallBarrelExplosionEffect()
  {
    SetEffectDuration(5.0);
    UseIdentityMatrix(true);
    CreateFramesTable(2, m_AnimFramesQty * 4 + 32);

    m_SizeFactor = 2.0;
    GenerateParticleAnimation(0,  0, vector(0.0, 0.0, 0.5), vector(0.0, 0.0, 5.0), vector(0.5, 0.5, 2.0), vector(4.0, 4.0, 4.0), 400, 2.0);
    GenerateParticleAnimation(1, 32, vector(0.0, 0.0, 3.0), vector(0.0, 0.0, 5.0), vector(6.0, 6.0, 6.0), 300, 4.0);
  }
}

class CCisternExplosionEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CCisternExplosionEffect()
  {
    SetEffectDuration(5.0);
    UseIdentityMatrix(true);
    CreateFramesTable(4, m_AnimFramesQty * 6 + 64);

    m_SizeFactor = 12.0;
    GenerateParticleAnimation(0,  0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0), vector(2.0, 2.0, 2.0), vector(20.0, 20.0, 4.0), 200, 2.0);
    GenerateParticleAnimation(1, 32, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 3.0), vector(1.0, 1.0, 6.0), vector(6.0,  6.0,  6.0), 400, 3.0);
    GenerateParticleAnimation(2, 48, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 5.0), vector(6.0, 6.0, 6.0), vector(10.0, 10.0, 10.0), 300, 6.0);
    GenerateParticleAnimation(3, 64, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 5.0), vector(6.0, 6.0, 6.0), vector(10.0, 10.0, 10.0), 300, 6.0);
  }
}

class CHelicopterExplosionEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CHelicopterExplosionEffect()
  {
    SetEffectDuration(4.0);
    UseIdentityMatrix(true);
    CreateFramesTable(4, m_AnimFramesQty * 6 + 64);

    m_SizeFactor = 6.0;
    GenerateParticleAnimation(0,  0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0), vector(2.0, 2.0, 2.0), vector(20.0, 20.0, 4.0), 200, 2.0);
    GenerateParticleAnimation(1, 32, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 3.0), vector(1.0, 1.0, 6.0), vector(6.0,  6.0,  4.0), 400, 3.0);
    GenerateParticleAnimation(2, 48, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 5.0), vector(6.0, 6.0, 6.0), vector(10.0, 10.0, 10.0), 300, 6.0);
    GenerateParticleAnimation(3, 64, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 5.0), vector(6.0, 6.0, 6.0), vector(10.0, 10.0, 10.0), 300, 6.0);
  }
}

class CAmmoBoxExplosionEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CAmmoBoxExplosionEffect()
  {
    SetEffectDuration(5.0);
    UseIdentityMatrix(true);
    CreateFramesTable(2, m_AnimFramesQty * 4 + 32);

    m_SizeFactor = 8.0;
    GenerateParticleAnimation(0,  0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0), vector(4.0, 4.0, 4.0), vector(6.0, 6.0, 6.0), 200, 1.0);
    m_BaseColor  = color(1.0, 0.8, 0.5, 0.7);
    GenerateParticleAnimation(1, 32, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 2.0), vector(6.0, 6.0, 6.0), 500, 4.0);
  }
}

class CHangarExplosionEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CHangarExplosionEffect()
  {
    SetEffectDuration(5.0);
    UseIdentityMatrix(true);
    CreateFramesTable(2, m_AnimFramesQty * 2 + 64);

    m_SizeFactor = 14.0;
    GenerateParticleAnimation(0,  0, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0), vector(2.0, 2.0, 2.0), vector(20.0, 20.0, 4.0), 200, 2.0);
    GenerateParticleAnimation(1, 64, vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0), vector(9.0, 9.0, 2.0), vector(30.0, 30.0, 6.0), 400, 2.0);
  }
}



// gun fire effects
class CGunFireTriple
{
  color m_DirectColor = color(1.0, 1.0, 1.0, 0.0);
  color m_SideColor   = color(1.0, 0.9, 0.5, 0.0);

  float m_ColorPower  = 5.0;
  float m_GeomPower   = 0.5;

  float m_SizeFactor  = 1.0;

  void GenerateGunFireTriple(
      int _StartParticle,
      int _StartFrame,
      int _FinaleFrame
    )
  {
    final int FramesQty = _FinaleFrame - _StartFrame;

    for (int FrameNum = 0; FrameNum < FramesQty; FrameNum = FrameNum + 1)
    {
      float Phase  = float(FrameNum) / float(FramesQty - 1);
      float GeometryPhase = pow(Phase, m_GeomPower);

      SetPosition(_StartParticle + 0, _StartFrame + FrameNum,
        vector(0.9, 0.0, 0.0) * pow(Phase, m_GeomPower) * m_SizeFactor);
      SetSizeFactor(_StartParticle + 0, _StartFrame + FrameNum,
        vector(0.9, 0.3, 0.3) * pow(Phase, m_GeomPower) * m_SizeFactor);
      SetColor(_StartParticle + 0, _StartFrame + FrameNum,
        m_DirectColor + color(0.0, 0.0, 0.0, 1.0 - pow(Phase, m_ColorPower)));

      SetSizeFactor(_StartParticle + 1, _StartFrame + FrameNum,
        vector(0.2, 0.2, 0.6) * pow(Phase, m_GeomPower) * m_SizeFactor);
      SetColor(_StartParticle + 1, _StartFrame + FrameNum,
        m_SideColor + color(0.0, 0.0, 0.0, 1.0 - pow(Phase, m_ColorPower)));

      SetSizeFactor(_StartParticle + 2, _StartFrame + FrameNum,
        vector(0.2, 0.6, 0.2) * pow(Phase, m_GeomPower) * m_SizeFactor);
      SetColor(_StartParticle + 2, _StartFrame + FrameNum,
        m_SideColor + color(0.0, 0.0, 0.0, 1.0 - pow(Phase, m_ColorPower)));
    }

    // main plane
    SetPattern(_StartParticle + 0, EPPID_BILLBOARD_XAXIS);
    SetMaterial(_StartParticle + 0, 3);

    // side planes
    SetPattern(_StartParticle + 1, EPPID_BILLBOARD_ZAXIS);
    SetMaterial(_StartParticle + 1, 1);
    SetPosition(_StartParticle + 1, vector(-0.1, 0.0, 0.0) * m_SizeFactor);

    SetPattern(_StartParticle + 2, EPPID_BILLBOARD_YAXIS);
    SetMaterial(_StartParticle + 2, 1);
    SetPosition(_StartParticle + 2, vector(-0.1, 0.0, 0.0) * m_SizeFactor);
  }
}

class CMachineGunFireEffect
  extends CGunFireTriple
{
  final static string CID = "DynamicEffect";

  void CMachineGunFireEffect()
  {
    SetEffectDuration(0.2);
    CreateFramesTable(3, 15);

    GenerateGunFireTriple(0, 0, 14);
  }
}

class CBigGunFireEffect
  extends CGunFireTriple
{
  final static string CID = "DynamicEffect";

  void CBigGunFireEffect()
  {
    SetEffectDuration(0.2);
    CreateFramesTable(3, 16);

    m_SizeFactor = 4.0;
    GenerateGunFireTriple(0, 0, 16);
  }
}

class CBigGunFireCloudEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CBigGunFireCloudEffect()
  {
    SetEffectDuration(2.0);
    CreateFramesTable(2, m_AnimFramesQty * 4 + 32);

    m_SizeFactor = 2.0;
    m_BaseColor  = color(1.0, 1.0, 1.0, 1.0);
    GenerateParticleAnimation(0,  8, vector(0.0, 0.0, 0.0), vector(1.0, 0.0, 0.0), vector(1.0, 0.1, 0.1), vector(1.0, 1.0, 1.0), 400, 1.0);
    m_BaseColor  = color(1.0, 1.0, 1.0, 0.3);
    GenerateParticleAnimation(1, 32, vector(0.5, 0.0, 0.0), vector(4.0, 0.0, 0.0), vector(1.0, 1.0, 1.0), vector(2.0, 2.0, 2.0), 500, 4.0);
  }
}

class CPanzerFaustFireEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CPanzerFaustFireEffect()
  {
    SetEffectDuration(1.5);
    CreateFramesTable(1, m_AnimFramesQty * 4);

    m_SizeFactor = 2.0;
    m_BaseColor  = color(1.0, 1.0, 1.0, 0.5);
    GenerateParticleAnimation(0, 0,
      vector(0.0, 0.0, 1.0), vector(0.0, 0.0, rand(3.0, 4.0)),
      vector(4.0, 4.0, 4.0), vector(4.0, 4.0, 4.0), 500, 4.0);
  }
}

class CRocketFireCloudEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CRocketFireCloudEffect()
  {
    SetEffectDuration(1.5);
    CreateFramesTable(1, m_AnimFramesQty * 4);

    m_SizeFactor = 2.0;
    m_BaseColor  = color(1.0, 1.0, 1.0, 0.5);
    GenerateParticleAnimation(0, 0,
      vector(0.0, 0.0, 0.0), vector(rand(-5.0, -4.0), rand(1.0), rand(2.0, 3.0)),
      vector(4.0, 4.0, 4.0), vector(4.0, 4.0, 4.0), 500, 4.0);
  }
}




// Inverse track effects
class CMissileInverseTrackEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CMissileInverseTrackEffect()
  {
    SetEffectDuration(2.0);
    CreateFramesTable(1, m_AnimFramesQty * 10);

    m_PlacePower = 1.0;
    m_SizePower  = 0.3;

    m_BaseColor  = color(1.0, 1.0, 1.0, 0.8);
    GenerateParticleAnimation(
      0, 0,
      vector(-1.0, 0.0, 0.0), vector(-1.0, 0.0, 0.0),
      vector(15.0, 2.0, 2.0), vector(15.0, 0.5, 0.5),
      400, 1.0);

    m_BaseColor  = color(1.0, 1.0, 1.0, 0.3);
    GenerateParticleAnimation(
      0, m_AnimFramesQty,
      vector(1.0, 0.0, 0.0), vector(1.0, 0.0, 0.0) + vector(0.0, rand(2.5), rand(2.5)),
      vector(9.0, 5.0, 5.0),
      500, 9.0);

    SetAlphaSpace(0, vector(0.3, 1.0, 1.0));
    SetAlphaSpace(0, 0, m_AnimFramesQty, vector(1.0, 1.0, 1.0));
  }
}

class CRocketInverseTrackEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CRocketInverseTrackEffect()
  {
    SetEffectDuration(0.2);
    CreateFramesTable(1, m_AnimFramesQty);

    m_PlacePower = 1.0;
    m_SizePower  = 0.3;

    m_BaseColor = color(1.0, 1.0, 1.0, 0.8);
    GenerateParticleAnimation(
      0, 0,
      vector(-0.5, 0.0, 0.0), vector(-0.5, 0.0, 0.0),
      vector(6.0, 2.0, 2.0), vector(6.0, 0.2, 0.2),
      400, 1.0);
  }
}

class CFireBallInverseTrackEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CFireBallInverseTrackEffect()
  {
    SetEffectDuration(0.5);
    CreateFramesTable(1, m_AnimFramesQty);

    m_PlacePower = 1.0;
    m_SizePower  = 1.0;
    m_SizeFactor = 1.0;

    m_BaseColor = color(1.0, 1.0, 1.0, 0.5);
    GenerateParticleAnimation(
      0, 0,
      vector(0.0, 0.0, 0.0), vector(0.0, rand(2.5), rand(2.5)),
      vector(6.0, 6.0, 6.0), vector(6.0, 1.0, 1.0),
      400, 1.0);
  }
}

class CBlackFireBallInverseTrackEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CBlackFireBallInverseTrackEffect()
  {
    SetEffectDuration(1.5);
    CreateFramesTable(1, m_AnimFramesQty * 5);

    m_PlacePower = 1.0;
    m_SizePower  = 1.0;
    m_SizeFactor = 1.0;

    m_BaseColor = color(1.0, 1.0, 1.0, 0.5);
    GenerateParticleAnimation(
      0, 0,
      vector(0.0, 0.0, 0.0), vector(0.0, rand(2.5), rand(2.5)),
      vector(6.0, 6.0, 6.0), vector(3.0, 3.0, 3.0),
      400, 1.0);

    m_BaseColor = color(1.0, 1.0, 1.0, 1.0);
    GenerateParticleAnimation(
      0, m_AnimFramesQty,
      vector(3.0, 0.0, 0.0), vector(3.0, rand(6.0), rand(6.0)),
      vector(8.0, 8.0, 8.0),
      300, 4.0);
  }
}

class CSplashInverseTrackEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CSplashInverseTrackEffect()
  {
    SetEffectDuration(1.0);
    CreateFramesTable(1, m_AnimFramesQty);

    m_PlacePower = 1.0;
    m_SizePower  = 1.0;
    m_SizeFactor = 1.0;

    m_BaseColor = color(1.0, 1.0, 1.0, 0.5);
    GenerateParticleAnimation(
      0, 0,
      vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 0.0),
      vector(5.0, 3.0, 3.0), vector(5.0, 0.2, 0.2),
      400, 1.0);
  }
}

class CPanzerFaustInverseTrackEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CPanzerFaustInverseTrackEffect()
  {
    SetEffectDuration(1.5);
    CreateFramesTable(1, m_AnimFramesQty);

    m_PlacePower = 1.0;
    m_SizePower  = 0.3;

    m_BaseColor  = color(1.0, 1.0, 1.0, 0.3);
    GenerateParticleAnimation(
      0, 0,
      vector(-1.0, 0.0, 0.0), vector(-1.0, rand(3.0), rand(3.0)),
      vector(4.0, 0.5, 0.5), vector(4.0, 4.0, 4.0),
      500, 1.0);

    SetAlphaSpace(0, vector(0.5, 1.0, 1.0));
  }
}




// Dust effects
class CDustEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CDustEffect()
  {
    SetEffectDuration(2.0);
    CreateFramesTable(2, m_AnimFramesQty);

    m_PlacePower = 0.5;
    m_BaseColor  = color(95.0 / 256.0, 92.0 / 256.0, 73.0 / 256.0, 0.3);

    for (int ParticleNum = 0; ParticleNum < 2; ParticleNum = ParticleNum + 1)
    {
      GenerateParticleAnimation(
        ParticleNum, 0,
        vector(0.0, 0.0, 0.0), vector(rand(0.1), rand(4.0), rand(0.0, 4.0)),
        vector(4.0, 4.0, 4.0), 500, 1.0);
      SetAlphaSpace(ParticleNum, vector(0.3, 0.5, 0.5));
    }
  }
}

class CBulletHitGroundEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CBulletHitGroundEffect()
  {
    SetEffectDuration(3.0);
    CreateFramesTable(1, m_AnimFramesQty);

    m_PlacePower = 0.5;
    m_SizePower  = 0.5;
    m_BaseColor  = color(1.0, 0.9, 0.6, 0.25);

    GenerateParticleAnimation(
      0, 0,
      vector(0.0, 0.0, 0.0), vector(0.0, 0.0, 6.0),
      vector(1.0, 1.0, 2.0), vector(6.0, 6.0, 6.0),
      500, 1.0);
  }
}

class CBulletHitObjectEffect
{
  final static string CID = "DynamicEffect";

  void CBulletHitObjectEffect()
  {
    SetEffectDuration(0.2);
    CreateFramesTable(1, 3);

    SetPattern(0, EPPID_BILLBOARD_PLANE);
    SetMaterial(0, 6);
    SetPosition(0, vector(0.0, 0.0, 0.0));

    SetColor(0, 0, color(1.0, 1.0, 1.0, 1.0));
    SetColor(0, 1, color(1.0, 1.0, 1.0, 1.0));
    SetColor(0, 2, color(1.0, 1.0, 1.0, 0.0));

    SetSizeFactor(0, 0, vector(0.1, 0.1, 0.1));
    SetSizeFactor(0, 1, vector(1.0, 1.0, 1.0));
    SetSizeFactor(0, 2, vector(1.0, 1.0, 1.0));
  }
}

class CSplashBulletTraceEffect
{
  final static string CID = "StaticEffect";

  void CSplashBulletTraceEffect()
  {
    CreateParticle(
        EPPID_BILLBOARD_XAXIS,
        vector(0.0, 0.0, 0.0),
        vector(0.3, 0.15, 0.15),
        0,
        color(1.0, 0.9, 0.6, 1.0),
        vector(1.0, 1.0, 1.0)
      );
  }
}

class CHelicopterSmokeTrackEffect
  extends CSingleParticleAnimator
{
  final static string CID = "DynamicEffect";

  void CHelicopterSmokeTrackEffect()
  {
    SetEffectDuration(5.0);
    CreateFramesTable(1, m_AnimFramesQty * 5);

    m_PlacePower = 1.0;
    m_SizePower  = 1.0;
    m_SizeFactor = 1.5;

    m_BaseColor = color(1.0, 1.0, 1.0, 0.5);
    GenerateParticleAnimation(
      0, 0,
      vector(0.0, 0.0, 0.0), vector(0.0, rand(2.5), rand(2.5)),
      vector(6.0, 6.0, 6.0), vector(3.0, 3.0, 3.0),
      400, 1.0);

    m_BaseColor = color(1.0, 1.0, 1.0, 1.0);
    GenerateParticleAnimation(
      0, m_AnimFramesQty,
      vector(3.0, 0.0, 0.0), vector(3.0, rand(6.0), rand(6.0)),
      vector(8.0, 8.0, 8.0),
      300, 4.0);
  }
}




// #TMP tasks to change
class CTimeJumpSplashRingEffect
{
  final static string CID = "DynamicEffect";

  void CTimeJumpSplashRingEffect()
  {
    SetEffectDuration(1.0);
    CreateFramesTable(1, 2);

    SetPattern(0, EPPID_STATIC_PLANE_XY);
    SetMaterial(0, 1);
    SetPosition(0, vector(0.0, 0.0, 0.0));

    SetSizeFactor(0, 0, vector(0.1, 0.1, 0.1));
    SetSizeFactor(0, 1, vector(100.0, 100.0, 100.0));

    SetColor(0, 0, color(0.5, 0.0, 1.0, 1.0));
    SetColor(0, 1, color(0.5, 0.0, 1.0, 0.0));
  }
}

class CTimeJumpEffect
{
  final static string CID = "DynamicEffect";

  void CTimeJumpEffect()
  {
    SetEffectDuration(15.0);
    CreateFramesTable(2, 4);

    vector WindowSize = vector(10.0, 10.0, 10.0);
    vector FlashSize  = vector(25.0, 25.0, 25.0);

    // pattern 0
    SetPattern(0, EPPID_STATIC_PLANE_YZ);
    SetMaterial(0, 1);
    SetPosition(0, vector(0.0, 0.0, 0.0));

    SetSizeFactor(0, 0,    vector(0.1, 0.1, 0.1));
    SetSizeFactor(0, 1, 4, FlashSize);

    SetColor(0, 0, 3, color(0.5, 0.0, 1.0, 1.0));
    SetColor(0,    3, color(0.5, 0.0, 1.0, 0.0));

    // pattern 1
    SetPattern(1, EPPID_STATIC_PLANE_YZ);
    SetMaterial(1, 2);
    SetPosition(1, vector(0.0, 0.0, 0.0));

    SetSizeFactor(1, 0,    vector(0.1, 0.1, 0.1));
    SetSizeFactor(1, 1, 4, WindowSize);

    SetColor(1, 0, 3, color(1.0, 1.0, 1.0, 1.0));
    SetColor(1,    3, color(1.0, 1.0, 1.0, 0.0));
  }
}




class CEffectsArray
{
  void CEffectsArray()
  {
    // Load effects materials
    LoadMaterials("Common/effects");

    // Create effects patterns
    CreatePattern("CTimeJumpEffect", "EFFECTID_TimeJumpEffect");
    CreatePattern("CTimeJumpSplashRingEffect", "EFFECTID_TimeJumpSplashRingEffect");

    CreatePattern("CTankGunBulletHitEffect", "EFFECTID_TankGunBulletHitEffect");
    CreatePattern("CFlakGunBulletHitEffect", "EFFECTID_FlakGunBulletHitEffect");

    CreatePattern("CHelicopterSmokeEffect", "EFFECTID_HelicopterSmokeEffect");
    CreatePattern("CMissileExplosionEffect", "EFFECTID_MissileExplosionEffect");
    CreatePattern("CKatushaRocketExplosionEffect", "EFFECTID_KatushaRocketExplosionEffect");
    CreatePattern("CSmallBarrelExplosionEffect", "EFFECTID_SmallBarrelExplosionEffect");
    CreatePattern("CCisternExplosionEffect", "EFFECTID_CisternExplosionEffect");
    CreatePattern("CAmmoBoxExplosionEffect", "EFFECTID_AmmoBoxExplosionEffect");
    CreatePattern("CHangarExplosionEffect", "EFFECTID_HangarExplosionEffect");
    CreatePattern("CAirBombExplosionEffect", "EFFECTID_AirBombExplosionEffect");
    CreatePattern("CUnitExplosionEffect", "EFFECTID_UnitExplosionEffect", 3);
    CreatePattern("CItemExplosionEffect", "EFFECTID_ItemExplosionEffect", 3);
    CreatePattern("CTreeExplosionEffect", "EFFECTID_TreeExplosionEffect", 3);
    CreatePattern("CBuildingExplosionEffect", "EFFECTID_BuildingExplosionEffect", 3);

    CreatePattern("CMachineGunFireEffect", "EFFECTID_HelicopterGunFireEffect");
    CreatePattern("CMachineGunFireEffect", "EFFECTID_AntiairGunFireEffect");
    CreatePattern("CMachineGunFireEffect", "EFFECTID_GunTowerGunFireEffect");

    CreatePattern("CBigGunFireEffect", "EFFECTID_TankGunFireEffect");
    CreatePattern("CBigGunFireCloudEffect", "EFFECTID_TankGunFireCloudEffect");

    CreatePattern("CBigGunFireEffect", "EFFECTID_FlakGunFireEffect");
    CreatePattern("CBigGunFireCloudEffect", "EFFECTID_FlakGunFireCloudEffect");
    CreatePattern("CBigGunFireEffect", "EFFECTID_MobileFlakGunFireEffect");
    CreatePattern("CBigGunFireCloudEffect", "EFFECTID_MobileFlakGunFireCloudEffect");

    CreatePattern("CMachineGunFireEffect", "EFFECTID_AJeepGunFireEffect");
    CreatePattern("CMachineGunFireEffect", "EFFECTID_ArmedSandBagsGunFireEffect");

    CreatePattern("CPanzerFaustFireEffect", "EFFECTID_PanzerFaustFireEffect");
    CreatePattern("CPanzerFaustExplosionEffect", "EFFECTID_PanzerFaustExplosionEffect");
    CreatePattern("CPanzerFaustInverseTrackEffect", "EFFECTID_PanzerFaustInverseTrackEffect", 5);

    CreatePattern("CMissileInverseTrackEffect", "EFFECTID_MissileInverseTrack", 5);
    CreatePattern("CRocketInverseTrackEffect", "EFFECTID_RocketInverseTrack", 5);

    CreatePattern("CDustEffect", "EFFECTID_DustEffect", 5);
    CreatePattern("CHelicopterSmokeTrackEffect", "EFFECTID_HelicopterSmokeTrackEffect", 5);

    CreatePattern("CRocketFireCloudEffect", "EFFECTID_HelicopterRocketFireCloudEffect");
    CreatePattern("CRocketFireCloudEffect", "EFFECTID_KatushaRocketFireCloudEffect");

    CreatePattern("CFireBallExplosionEffect", "EFFECTID_FireBallExplosionEffect", 5);
    CreatePattern("CBlackFireBallInverseTrackEffect", "EFFECTID_BlackFireBallInverseTrack", 5);
    CreatePattern("CFireBallInverseTrackEffect", "EFFECTID_FireBallInverseTrack", 5);
    CreatePattern("CSplashInverseTrackEffect", "EFFECTID_BlackFireSplashInverseTrack", 5);

    CreatePattern("CBulletHitObjectEffect", "EFFECTID_BulletHitObjectEffect", 5);
    CreatePattern("CBulletHitGroundEffect", "EFFECTID_BulletHitGroundEffect", 5);

    CreatePattern("CHelicopterExplosionEffect", "EFFECTID_HelicopterExplosionEffect");
  }
}

