

datablock ItemData(TempItem)
{
   className    = Weapon;
   catagory     = "Spawn Items";

   shapeFile = "turret_muzzlepoint.dts";

   mass         = 0;
   elasticity   = 0.2;
   friction     = 0.6;

   maxDamage    = 10.0;

   computeCRC   = true;
   emap         = true;
};

//--------------------------------------
// Rifle and item...
//--------------------------------------
datablock ItemData(ShockLance)
{
   className    = Weapon;
   catagory     = "Spawn Items";

   shapeFile    = "weapon_shocklance.dts";
   image        = ShockLanceImage;

   mass         = 1;
   trueMass     = 2;

   elasticity   = 0.2;
   friction     = 0.6;
   pickupRadius = 2;
   pickUpName   = "a shocklance";

   computeCRC = true;
   emap = true;
};

datablock ShapeBaseImageData(ShockLanceImage)
{
   classname = WeaponImage;
   shapeFile = "weapon_shocklance.dts";
   item = ShockLance;
   offset = "0 0 0";
   emap = true;

   projectile = BasicShocker;

   usesEnergy = true;
   missEnergy = 5;
   hitEnergy  = 15;
   minEnergy  = 15;

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

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

   stateName[2] = "Ready";
   stateTransitionOnNoAmmo[2] = "NoAmmo";
   stateTransitionOnTriggerDown[2] = "Fire";

   stateName[3] = "Fire";
   stateTransitionOnTimeout[3] = "Reload";
   stateTimeoutValue[3] = 0.5;
   stateFire[3] = true;
   stateAllowImageChange[3] = false;
   stateSequence[3] = "Fire";
   stateScript[3] = "onFire";
   stateSound[3] = ShockLanceDryFireSound;

   stateName[4] = "Reload";
   stateTransitionOnNoAmmo[4] = "NoAmmo";
   stateTransitionOnTimeout[4] = "Ready";
   stateTimeoutValue[4] = 2.0;
   stateAllowImageChange[4] = false;
   stateSequence[4] = "Reload";
   stateSound[4] = ShockLanceReloadSound;

   stateName[5] = "NoAmmo";
   stateTransitionOnAmmo[5] = "Reload";
   stateSequence[5] = "NoAmmo";
   stateTransitionOnTriggerDown[5] = "DryFire";

   stateName[6]                  = "DryFire";
   stateSound[6]                 = ShockLanceDryFireSound;
   stateTimeoutValue[6]          = 1.0;
   stateTransitionOnTimeout[6]   = "Ready";
   
   stateName[7] = "CheckWet";
   stateTransitionOnWet[7] = "DryFire";
   stateTransitionOnNotWet[7] = "Fire";
};

function ShockLanceImage::onFire(%this, %Player, %Slot)
{
   if (%Player.PlayerNoFire == true)
      return;

   // If Player is cloaked, handle the cloaking/uncloaking
   if (%Player.isCloaked())
   {
      if (%Player.respawnCloakThread !$= "")
      {
         Cancel(%Player.respawnCloakThread);
         %Player.setCloaked(false);
      }
      else
      {
         if (%Player.getEnergyLevel() > 20)
         {   
            %Player.setCloaked(false);
            %Player.reCloak = %Player.schedule(500, "setCloaked", true); 
         }
      }   
   }

   %MuzzlePosition = %Player.getMuzzlePoint($WeaponSlot);
   %MuzzleVector = %Player.getMuzzleVector($WeaponSlot);

   // Check to see if the player is in the water.
   if (%Player.InWater == true)
   {
      // Do a shock radius from the player's weapon
      %this.RadiusShock(%Player, %MuzzlePosition, true);
      return;
   }

   // Check to see if the player is aiming at water.
   %WaterPosition = %Player.isAimingAtWater(8);

   if (%WaterPosition !$= "0")
   {
      // Do shock radius from where the shot would hit the water
      %this.RadiusShock(%Player, %WaterPosition, true);

      %Projectile = new TargetProjectile()
      {
         dataBlock        = ShocklanceBeam;
         initialDirection = %MuzzleVector;
         initialPosition  = %MuzzlePosition;
         sourceObject     = %Player;
         sourceSlot       = $WeaponSlot;
      };
      MissionCleanup.add(%Projectile);

      %Projectile.schedule(850, delete);

      return;
   }

   // If water is not involved, then shock like normal
   %this.RegularShock(%Player, %MuzzlePosition, %MuzzleVector, %Slot);
}

function ShockLanceImage::RegularShock(%this, %Player, %MuzzlePosition, %MuzzleVector, %Slot)
{
   %EndPosition = VectorAdd(%MuzzlePosition, VectorScale(%MuzzleVector, %this.projectile.extension));

   %DamageableMasks = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType |
                      $TypeMasks::StationObjectType | $TypeMasks::GeneratorObjectType |
                      $TypeMasks::SensorObjectType | $TypeMasks::TurretObjectType;

   %EverythingElseMask = $TypeMasks::TerrainObjectType |
                         $TypeMasks::InteriorObjectType |
                         $TypeMasks::ForceFieldObjectType |
                         $TypeMasks::StaticObjectType |
                         $TypeMasks::MoveableObjectType |
                         $TypeMasks::DamagableItemObjectType;

   %Target = ContainerRayCast(%MuzzlePosition, %EndPosition, %DamageableMasks | %EverythingElseMask, %Player);

   if (%Target !$= "0")
   {
      %TargetObject = getWord(%Target, 0);
      %TargetPosition = getWords(%Target, 1, 3);

      if (%TargetObject.getType() & %DamageableMasks)
      {
          %Player.setEnergyLevel(%Player.getEnergyLevel() - %this.hitEnergy);
          %Player.playAudio(0, ShockLanceHitSound);

         %Projectile = new ShockLanceProjectile()
         {
            dataBlock        = %this.projectile;
            initialDirection = %MuzzleVector;
            initialPosition  = %MuzzlePosition;
            sourceObject     = %Player;
            sourceSlot       = $WeaponSlot;
            targetId         = %Target;
         };
         MissionCleanup.add(%Projectile);
         // Should this be TargetObject? - Dev

         %Damage = %this.Projectile.DirectDamage;

         %HitLocation = getWord(%TargetObject.getDamageLocation(%MuzzlePosition), 1);
         echo("Hit Location: " @ %HitLocation);
         if (getSubStr(%HitLocation, 0, 4) $= "back")
            %Damage *= %this.Projectile.rearDamageFactor;
      
         %TargetObject.getDataBlock().damageObject(%TargetObject, %Player, %TargetPosition, %Damage, $DamageType::Electricity);

         %TargetObject.applyImpulse(%TargetPosition, VectorScale(%MuzzleVector, %Projectile.getDataBlock().impulse));

         %DontDisplay = false;
      }
      %DontDisplay = true;
   } else {
      %DontDisplay = true;
   }
   
   if (%DontDisplay == true)
   {
      // Miss
      %Player.setEnergyLevel(%Player.getEnergyLevel() - %this.missEnergy);
      %Player.playAudio(0, ShockLanceMissSound);

      %Projectile = new ShockLanceProjectile()
      {
         dataBlock        = %this.projectile;
         initialDirection = %MuzzleVector;
         initialPosition  = %MuzzlePosition;
         sourceObject     = %Player;
         sourceSlot       = $WeaponSlot;
      };
      MissionCleanup.add(%Projectile);
   }
}

function ShockLanceImage::RadiusShock(%this, %Player, %Position, %InWater)
{
   %Damage = %this.projectile.directDamage;
   %DamageType = %this.projectile.radiusDamageType;

   // If we are checking for water related shock damage, then use the factor for that
   if (%InWater == true)
   {
      %Damage *= %this.projectile.UnderWaterFactor;
      %Radius = %this.projectile.UnderWaterRadius;
   } else {
      %Radius = %this.projectile.extension;
   }

   InitContainerRadiusSearch(%Position, %Radius, $TypeMasks::PlayerObjectType      |
                                                 $TypeMasks::VehicleObjectType     |
                                                 $TypeMasks::MoveableObjectType    |
                                                 $TypeMasks::StaticShapeObjectType |
                                                 $TypeMasks::ForceFieldObjectType  |
                                                 $TypeMasks::TurretObjectType      |
                                                 $TypeMasks::ItemObjectType);

   // Take a snap shot of the current placement of objects and load into an array for later
   // Processing
   %NumTargets = 0;
   while ((%TargetObject = containerSearchNext()) != 0)
   {
      // If the player is not in the water and it only affects the water
      if (%InWater == true && %TargetObject.InWater == false)
         continue;

      // Are they under the protection of a vehicle's shields
      if (%TargetObject.isMounted())
      {
         // Look through the mounted points on the vehicle to determine which one the player
         // is mounted to.  Perhaps later this can be set as a property of the player object.
         %Mount = %TargetObject.getObjectMount();
         %Found = -1;
         %NumMounts = %Mount.getDataBlock().numMountPoints;
         for (%i = 0; %i < %NumMounts; %i++)
         {
            if (%Mount.getMountNodeObject(%i) == %TargetObject)
            {
               %Found = %i;
               break;
            }
         }
      
         // Are they at a mounted point where they are shielded and does the vehicle have at least 15 energy
         if (%found != -1)
         {
            if (%Mount.getDataBlock().isProtectedMountPoint[%Found] && %Mount.getEnergyLevel() > 15)
            {
               continue;
            }
         }
      }

      // If they were not out of range or on a vehicle that had enough power and in a shielded area,
      // then we record them as targets to apply damage to.
      %Targets[%NumTargets]     = %TargetObject;
      %TargetDists[%NumTargets] = %Distance;
      %NumTargets++;
   }

   // If there are targets in the array, now apply the damage
   // and type
   %i = 0;
   while (%i < %NumTargets)
   {
      %TargetObject = %Targets[%i];
      %Distance = %TargetDists[%i];

      // Check to see if the player is somehow blocked from recieving the damage.
      // If 5% of thier body or less is exposed we ignore them for speed purposes.
      %Coverage = calcExplosionCoverage(%Position, %TargetObject,
                                        ($TypeMasks::InteriorObjectType |
                                         $TypeMasks::TerrainObjectType |
                                         $TypeMasks::ForceFieldObjectType |
                                         $TypeMasks::VehicleObjectType));
      if (%Coverage <= 0.05)
         continue;

      %DistanceFactor = (1.0 - (%Distance / %Radius));

      %DataBlock = %TargetObject.getDataBlock();
      %ClassName = %DataBlock.className;
      %MomentumVector = "0 0 1";

      %Amount = %DistanceFactor * %Coverage * %Damage;
      
      // Apply the actual Damage Last
      if(%Amount > 0.1)
      {
         %DataBlock.damageObject(%TargetObject, %Player, %Position, %Amount, %DamageType, %MomVec);
         ShockObject(%TargetObject);
      }

      %i++;
   }
}

//--------------------------------------
// Projectile
//--------------------------------------
datablock ShockLanceProjectileData(ShockEffect)
{
   directDamage        = 0;
   radiusDamageType    = $DamageType::Electricity;
   kickBackStrength    = 0;
   velInheritFactor    = 0;
   sound               = "";

   zapDuration = 1.5;
   boltLength = 14.0;
   extension = 14.0;
   
   lightningFreq = 25.0;
   lightningDensity = 3.0;
   lightningAmp = 0.25;
   lightningWidth = 0.05;

   shockwave = ShocklanceHit;
   							 
   boltSpeed[0] = 2.0;
   boltSpeed[1] = -0.5;

   texWrap[0] = 1.5;
   texWrap[1] = 1.5;

   startWidth[0] = 0.3;
   endWidth[0] = 0.6;
   startWidth[1] = 0.3;
   endWidth[1] = 0.6;
   
   texture[0] = "special/shockLightning01";
   texture[1] = "special/shockLightning02";
   texture[2] = "special/shockLightning03";
   texture[3] = "special/ELFBeam";

   emitter[0] = ShockParticleEmitter;
};

function ShockObject(%Object)
{
   %Position = posFromTransform(%Object.getTransform());

   %Projectile = new ShockLanceProjectile()
   {
      dataBlock        = ShockEffect;
      initialDirection = "0 0 0";
      initialPosition  = %Position;
      sourceObject     = %Object;
      sourceSlot       = $WeaponSlot;
      targetId         = %Object;
   };
   MissionCleanup.add(%Projectile);
}

datablock TargetProjectileData(ShocklanceBeam)
{
   directDamage        	= 0.0;
   hasDamageRadius     	= false;
   indirectDamage      	= 0.0;
   damageRadius        	= 0.0;
   velInheritFactor    	= 1.0;

   maxRifleRange       	= 10;
   beamColor           	= "0.7 1 1";
								
   startBeamWidth       = 0.20;
   pulseBeamWidth       = 0.15;
   beamFlareAngle       = 3.0;
   minFlareSize        	= 0.0;
   maxFlareSize        	= 400.0;
   pulseSpeed          	= 6.0;
   pulseLength         	= 0.150;

   textureName[0]      	= "special/nonlingradient";
   textureName[1]      	= "special/ELFBeam";
   textureName[2]      	= "special/ELFLightning";
   textureName[3]      	= "special/droplet";
};