
//--------------------------------------
// Particle Cannon
//--------------------------------------

datablock LinearFlareProjectileData(ParticleBlast1)
{
   directDamage        = 0.048;
   directDamageType    = $DamageType::Energy;

   hasDamageRadius     = true;
   indirectDamage      = 0.18;
   damageRadius        = 3.5;
   radiusDamageType    = $DamageType::Electricity;
   kickBackStrength    = 750;

   sound               = discProjectileSound;

   explosion           = PlasmaBarrelBoltExplosion;
   splash              = PlasmaSplash;
   underwaterExplosion = "UnderwaterDiscExplosion";

   EMPDuration = 3.2;
   EMPStrength = 0.36;

   dryVelocity         = 90;
   wetVelocity         = 65;

   baseEmitter = ParticleCannon1Emitter;

   fizzleTimeMS      = 5200;
   lifetimeMS        = 6200;
   explodeOnDeath    = false;

   fizzleUnderwaterMS = 3000;

   numFlares         = 0;
   scale             = "0.6 0.6 0.6";
   size              = 0.6;
   flareColor        = "0.4 1.0 1.0";
   flareModTexture   = "flaremod";
   flareBaseTexture  = "flarebase";

   hasLight    = true;
   lightRadius = 3.2;
   lightColor  = "0.4 1.0 1.0 0.5";
};

datablock LinearFlareProjectileData(ParticleBlast2)
{
   directDamage        = 0.08;
   directDamageType    = $DamageType::Energy;

   hasDamageRadius     = true;
   indirectDamage      = 0.42;
   damageRadius        = 4.5;
   radiusDamageType    = $DamageType::Electricity;
   kickBackStrength    = 1050;

   sound               = discProjectileSound;

   explosion           = PlasmaBarrelBoltExplosion;
   splash              = PlasmaSplash;
   underwaterExplosion = "UnderwaterDiscExplosion";

   EMPDuration = 5.6;
   EMPStrength = 0.32;

   dryVelocity         = 90;
   wetVelocity         = 65;

   baseEmitter = ParticleCannon2Emitter;

   fizzleTimeMS      = 7200;
   lifetimeMS        = 8200;
   explodeOnDeath    = false;

   fizzleUnderwaterMS = 3000;

   numFlares         = 0;
   scale             = "0.6 0.6 0.6";
   size              = 0.6;
   flareColor        = "0.4 1.0 1.0";
   flareModTexture   = "flaremod";
   flareBaseTexture  = "flarebase";

   hasLight    = true;
   lightRadius = 3.8;
   lightColor  = "0.4 1.0 1.0 0.5";
};

datablock LinearFlareProjectileData(ParticleBlast3)
{
   directDamage        = 0.105;
   directDamageType    = $DamageType::Energy;

   hasDamageRadius     = true;
   indirectDamage      = 0.68;
   damageRadius        = 5.5;
   radiusDamageType    = $DamageType::Electricity;
   kickBackStrength    = 1350;

   sound               = discProjectileSound;

   explosion           = PlasmaBarrelBoltExplosion;
   splash              = PlasmaSplash;
   underwaterExplosion = "UnderwaterDiscExplosion";

   EMPDuration = 7.2;
   EMPStrength = 0.28;

   dryVelocity         = 90;
   wetVelocity         = 65;

   baseEmitter = ParticleCannon3Emitter;

   fizzleTimeMS      = 9200;
   lifetimeMS        = 10200;
   explodeOnDeath    = false;

   fizzleUnderwaterMS = 3000;

   numFlares         = 0;
   scale             = "0.6 0.6 0.6";
   size              = 0.6;
   flareColor        = "0.4 1.0 1.0";
   flareModTexture   = "flaremod";
   flareBaseTexture  = "flarebase";

   hasLight    = true;
   lightRadius = 4.2;
   lightColor  = "0.4 1.0 1.0 0.5";
};

datablock LinearFlareProjectileData(ParticleBlast4)
{
   directDamage        = 0.14;
   directDamageType    = $DamageType::Energy;

   hasDamageRadius     = true;
   indirectDamage      = 0.92;
   damageRadius        = 6.5;
   radiusDamageType    = $DamageType::Electricity;
   kickBackStrength    = 1650;

   sound               = discProjectileSound;

   explosion           = PlasmaBarrelBoltExplosion;
   splash              = PlasmaSplash;
   underwaterExplosion = "UnderwaterDiscExplosion";

   EMPDuration = 8.4;
   EMPStrength = 0.22;

   dryVelocity         = 90;
   wetVelocity         = 65;

   baseEmitter = ParticleCannon4Emitter;

   fizzleTimeMS      = 11200;
   lifetimeMS        = 12200;
   explodeOnDeath    = false;

   fizzleUnderwaterMS = 3000;

   numFlares         = 0;
   scale             = "0.6 0.6 0.6";
   size              = 0.6;
   flareColor        = "0.4 1.0 1.0";
   flareModTexture   = "flaremod";
   flareBaseTexture  = "flarebase";

   hasLight    = true;
   lightRadius = 4.8;
   lightColor  = "0.4 1.0 1.0 0.5";
};

datablock ItemData(ParticleCannon)
{
   className = Weapon;
   catagory = "Spawn Items";
   shapeFile = "weapon_missile.dts";
   image = ParticleCannonImage;

   mass = 1;
   trueMass = 7;

   elasticity = 0.2;
   friction = 0.6;
   pickupRadius = 2;
   pickUpName = "a particle cannon";

   lightType = "PulsingLight";
   lightColor  = "0.24 0.66 0.66 0.3";
   lightTime = "4500";
   lightRadius = "3.5";

   computeCRC = true;
   emap = true;
};

datablock ShapeBaseImageData(ParticleCannonImage)
{
   className = WeaponImage;
   shapeFile = "weapon_missile.dts";

   offset = "0 0 -0.07";
   armThread = lookms;
   emap = true;

   usesEnergy = true;
   fireEnergy = 12;
   minEnergy = 12;

   item = ParticleCannon;

   UseCrossHair = Chaingun;

   emap = true;

   mass = 1;

   ChargingDrain = 0.8;

   projectile = DiscProjectile;
   projectileType = LinearProjectile;

   stateName[0]                = "Activate";
   stateTransitionOnTimeout[0] = "ActivateReady";
   stateTimeoutValue[0]        = 0.5;
   stateSequence[0]            = "Activate";

   stateName[1]                = "ActivateReady";
   stateTransitionOnLoaded[1]  = "Ready";
   stateTransitionOnNoAmmo[1]  = "NoAmmo";

   stateName[2]                    = "Ready";
   stateTransitionOnNoAmmo[2]      = "NoAmmo";
   stateTransitionOnTriggerDown[2] = "Charging";
   stateSound[2]                   = DiscSwitchSound;

   stateName[3]                    = "Charging";
   stateScript[3]                  = "onCharge";   
   stateTransitionOnTimeout[3]     = "Waiting";
   stateTimeoutValue[3]            = 0.2;
   stateAllowImageChange[3]        = false;

   stateName[4]                    = "Waiting";
   stateTransitionOnNoAmmo[4]      = "Fire";
   stateTransitionOnTriggerUp[4]   = "Fire";
   stateEnergyDrain[4]             = 28;
   stateAllowImageChange[4]        = false;
   stateTransitionOnTimeout[4]     = "Waiting";
   stateTimeoutValue[4]            = 0.5;
   stateSound[4]                   = ShockLanceMissSound;

   stateName[5]                    = "Fire";
   stateTimeoutValue[5]            = 0.6;
   stateTransitionOnTimeout[5]     = "ActivateReady";
   stateFire[4]                    = true;
   stateScript[5]                  = "onFire";
   stateSound[5]                   = plasmaExpSound;
   stateAllowImageChange[5]        = false;

   stateName[6]                    = "NoAmmo";
   stateTransitionOnAmmo[6]        = "ActivateReady";
   stateSequence[6]                = "NoAmmo";
   stateTransitionOnTriggerDown[6] = "DryFire";

   stateName[7]                    = "DryFire";
   stateSound[7]                   = MissileDryFireSound;
   stateTimeoutValue[7]            = 1.0;
   stateTransitionOnTimeout[7]     = "ActivateReady";
};

datablock ShapeBaseImageData(ParticleCannonImagePair)
{
   className = WeaponImage;

   shapeFile = "weapon_missile.dts";
   offset = "0 0 0.07";
   rotation = "0 0 0 90";
   armThread = lookms;

   item           = Shotgun;
   ammo           = ShotgunAmmo;

   projectile     = ShotgunPellet;
   projectileType = TracerProjectile;

   emap = true;

   casing              = ShotgunShellDebris;
   shellExitDir        = "1.0 0.3 1.0";
   shellExitOffset     = "0.15 -0.56 -0.1";
   shellExitVariance   = 10.0;
   shellVelocity       = 1.0;

   projectileSpread = 20.0 / 1000.0;
   projectileCount = 7;

   stateName[0]                     = "WaitFire";
   stateTransitionOnTriggerDown[0]  = "Fire";

   stateName[1]                     = "Fire";
   stateTransitionOnTimeout[1]      = "StopFire";
   stateTimeoutValue[1]             = 0.3;
   stateFire[1]                     = true;
   stateAllowImageChange[1]         = true;
   stateSequence[1]                 = "Fire";
   stateScript[1]                   = "onFire";

   stateName[2]                     = "StopFire";
   stateTimeoutValue[2]             = 0.1;
   stateTransitionOnTimeout[2]      = "WaitFire";
   stateScript[2]                   = "stopFire";
};

function ParticleCannonImage::onMount(%this, %Player, %Slot)
{
   Parent::onMount(%this, %Player, %Slot);

   %Player.mountImage(ParticleCannonImagePair, 1);
}

function ParticleCannonImage::onunMount(%this, %Player, %Slot)
{
   Parent::onunMount(%this, %Player, %Slot);

   %Player.unmountImage(1);
}

// This function controls the charging of the cannon.
function ParticleCannonImage::onCharge(%Data, %Player, %Slot)
{
   // Record when the player pulled the trigger and started the charging
   %Player.CannonFireTime = getSimTime();

   // Play Charging Sound here
   %Player.ChargingSound = "";

   %Data.lightStart = getSimTime();

   %Player.ParticleCannonCharging = true;

//   %Player.ParticleCannonCheck = %Player.schedule(500, ParticleCannonChargeCheck, %Data, 0);
}

// This handles the cannon reaching full power and then firing like normal.  A large beam is shot from
// the cannon, there are 3 discharge drops and the players energy is restored.
function ParticleCannonImage::onFire(%Data, %Player, %Slot)
{
   if (%Player.PlayerNoFire == true || %Player.ParticleCannonCharging != true)
      return;

   %Player.ParticleCannonCharging = "";

   %ChargingTime = getSimTime() - %Player.CannonFireTime - 750;
   if (%ChargingTime < 0)
   {
      %Player.playAudio(0, BoosterSputterSound);
      %Player.OnParticleDischargeEffect(1);
   } else {
      // Play a loud sputtering sound
      %Position = %Player.getMuzzlePoint($WeaponSlot);
      %Vector = %Player.getMuzzleVector(%slot);
      %TimeScale = 1 + %ChargingTime / 55000;

      %Vector = VectorScale(%Vector, %TimeScale);

      if (%ChargingTime <= 1250)
      {
         %Projectile = new LinearFlareProjectile()
         {
            datablock = ParticleBlast1;
            initialPosition = %Position;
            initialDirection = %Vector;
            sourceSlot = $WeaponSlot;
            sourceObject = %Player;
            scale = ParticleBlast1.scale;
         };

      } else {

         if (%ChargingTime <= 2500)
         {

            %Projectile = new LinearFlareProjectile()
            {
               datablock = ParticleBlast2;
               initialPosition = %Position;
               initialDirection = %Vector;
               sourceSlot = $WeaponSlot;
               sourceObject = %Player;
               scale = ParticleBlast2.scale;
            };

         } else {

            if (%ChargingTime > 3750)
            {
               %Projectile = new LinearFlareProjectile()
               {
                  datablock = ParticleBlast4;
                  initialPosition = %Position;
                  initialDirection = %Vector;
                  sourceSlot = $WeaponSlot;
                  sourceObject = %Player;
                  scale = ParticleBlast4.scale;
               };

            } else {
               %Projectile = new LinearFlareProjectile()
               {
                  datablock = ParticleBlast3;
                  initialPosition = %Position;
                  initialDirection = %Vector;
                  sourceSlot = $WeaponSlot;
                  sourceObject = %Player;
                  scale = ParticleBlast3.scale;
               };
            }
         }
         MissionCleanUp.Add(%Projectile);
      }

      %ChargingPercent = %ChargingTime / 2500;
      %Player.OnParticleDischargeEffect(%ChargingPercent * 3);
   }

   return(%Projectile);
}

// This function causes the blue/white balls of energy to be thrown from
// the cannon the player is holding
function Player::OnParticleDischargeEffect(%this, %Number)
{
   if (%Number > 2)
      %Number = 3;

   // Raise the position to the cannon's level
   %Position = posFromTransform(%this.getTransform());
   %PositionXY = getWords(%Position, 0, 1);
   %PositionZ = getWord(%Position, 2) + 1.7;
   %Position = %PositionXY @ " " @ %PositionZ;

   // Move the position to the side
   %FacingVector = %this.getMuzzleVector($WeaponSlot);
   %FacingVector2D = VectorNormalize(getWords(%FacingVector, 0, 1) @ " 0");

   %Position2 = VectorAdd(%Position, VectorScale(%FacingVector2D, -1));

   %DisplacementVector = VectorNormalize(VectorCross(%FacingVector2D, "0 0 1"));

   // Define that point as the basis of all the effecst
   %BasePosition = VectorAdd(%Position2, VectorScale(%DisplacementVector, 0.6));

   %i = 0;
   while (%i < %Number)
   {
      if (%i < 1)
      {
         if (%Number <= 1)
            %DischargeVector = VectorScale(%FacingVector2D, -1);
         else
         {
            %DischargeVector = %DisplacementVector;
            %DischargeVector = VectorAdd(%DischargeVector, VectorScale(%FacingVector2D, -1));
         }
      } else {
         if (%i >= 2)
            %DischargeVector = VectorScale(%FacingVector2D, -1);
         else
         {
            %DischargeVector = VectorScale(%DisplacementVector, -1);
            %DischargeVector = VectorAdd(%DischargeVector, VectorScale(%FacingVector2D, -1));
         }
      }

      %Item = new GrenadeProjectile() 
      {
         dataBlock = ParticleCannonDischargeProjectile;
         initialDirection = %DischargeVector;
         initialPosition = %BasePosition;
      };
      MissionCleanup.add(%Item);

      %Item.schedule(850, delete);

      %i++;
   }
}

// This function handles the exploding of the projectile.  It will attempt to EMP everyone within
// the blast, then do explosive damage, and then attemp to reemp a second late.  This favors people
// who have some shields up and prevents the strongest EMPing.
function ParticleBlast1::onExplode(%Data, %Projectile, %Position, %Modifier)
{
   %Radius = %Data.damageRadius;
   %Damage = %Data.indirectDamage;
   %KickBack = %Data.kickBackStrength;
   %SourceObject = %Projectile.sourceObject;

   %EMPStrength = %Data.EMPStrength;
   %EMPDuration = %Data.EMPDuration;

   %DamageType = %Data.radiusDamageType;

   EMPingCheck(%Position, %Radius, %EMPDuration, %EMPStrength, %SourceObject);
   RadiusExplosion(%Projectile, %Position, %Radius, %Damage, %KickBack, %SourceObject, %DamageType);
   schedule(1000, 0, EMPingCheck, %Position, %Radius, %EMPDuration * 0.7, %EMPStrength * 1.35, %SourceObject);

   AreaEMP(%Position);
}

function ParticleBlast2::onExplode(%Data, %Projectile, %Position, %Modifier)
{
   %Radius = %Data.damageRadius;
   %Damage = %Data.indirectDamage;
   %KickBack = %Data.kickBackStrength;
   %SourceObject = %Projectile.sourceObject;

   %EMPStrength = %Data.EMPStrength;
   %EMPDuration = %Data.EMPDuration;

   %DamageType = %Data.radiusDamageType;

   EMPingCheck(%Position, %Radius, %EMPDuration, %EMPStrength, %SourceObject);
   RadiusExplosion(%Projectile, %Position, %Radius, %Damage, %KickBack, %SourceObject, %DamageType);
   schedule(1000, 0, EMPingCheck, %Position, %Radius, %EMPDuration * 0.7, %EMPStrength * 1.35, %SourceObject);

   AreaEMP(%Position);
}

function ParticleBlast3::onExplode(%Data, %Projectile, %Position, %Modifier)
{
   %Radius = %Data.damageRadius;
   %Damage = %Data.indirectDamage;
   %KickBack = %Data.kickBackStrength;
   %SourceObject = %Projectile.sourceObject;

   %EMPStrength = %Data.EMPStrength;
   %EMPDuration = %Data.EMPDuration;

   %DamageType = %Data.radiusDamageType;

   EMPingCheck(%Position, %Radius, %EMPDuration, %EMPStrength, %SourceObject);
   RadiusExplosion(%Projectile, %Position, %Radius, %Damage, %KickBack, %SourceObject, %DamageType);
   schedule(1000, 0, EMPingCheck, %Position, %Radius, %EMPDuration * 0.7, %EMPStrength * 1.35, %SourceObject);

   AreaEMP(%Position);
   schedule(1250, 0, AreaEMP, %Position);
}

function ParticleBlast4::onExplode(%Data, %Projectile, %Position, %Modifier)
{
   %Radius = %Data.damageRadius;
   %Damage = %Data.indirectDamage;
   %KickBack = %Data.kickBackStrength;
   %SourceObject = %Projectile.sourceObject;

   %EMPStrength = %Data.EMPStrength;
   %EMPDuration = %Data.EMPDuration;

   %DamageType = %Data.radiusDamageType;

   EMPingCheck(%Position, %Radius, %EMPDuration, %EMPStrength, %SourceObject);
   RadiusExplosion(%Projectile, %Position, %Radius, %Damage, %KickBack, %SourceObject, %DamageType);
   schedule(1000, 0, EMPingCheck, %Position, %Radius, %EMPDuration * 0.7, %EMPStrength * 1.35, %SourceObject);
   schedule(2000, 0, EMPingCheck, %Position, %Radius, %EMPDuration * 0.4, %EMPStrength * 1.65, %SourceObject);

   AreaEMP(%Position);
   schedule(1250, 0, AreaEMP, %Position);
}