
//--------------------------------------------------------------------------
// VehicleMine
// The Anti-Vehicle Mine scans 26 meters around itself looking for an enemy piloted 
// vehicle, tracks it, and then detonates doing tremendous damage.

//--------------------------------------------------------------------------
// Shape
//--------------------------------------------------------------------------

datablock ItemData(VehicleMineSpinner)
{
   className = Weapon;
   shapeFile = "deploy_sensor_motion.dts";
   maxDamage = 1.3;
   destroyedLevel = 1.3;
   disabledLevel = 1.0;
   explosion = DeployablesExplosion;

   sticky = true;
   mass = 0;
   friction = 1.0;

   deployedObject = true;

   targetNameTag         = 'Vehicle Mine';
   targetTypeTag         = 'Anti-Vehicle Mine';

   deployAmbientThread = true;

   debrisShapeName = "debris_generic_small.dts";
   debris = DeployableDebris;
};

// This ignores damage to the spinner as part of the whole or it would take damage
// twice as quickly from splash weapons.
function VehicleMineSpinner::damageObject(%Data, %Spinner, %SourceObject, %Position, %Amount, %DamageType)
{

}

datablock ShapeBaseImageData(VehicleMineImage)
{
   mass = 8.0;
   emap = true;

   shapeFile = "stackable2s.dts";
   item = VehicleMine;
   deployed = VehicleMineDeployed;

   mountPoint = 1;
   offset = "0 -0.3 -0.2";

   stateName[0] = "Idle";
   stateTransitionOnTriggerDown[0] = "Activate";

   stateName[1] = "Activate";
   stateScript[1] = "onActivate";
   stateTransitionOnTriggerUp[1] = "Idle";

   maxDepSlope = 40;
};

datablock ItemData(VehicleMine)
{
   className = Pack;
   catagory = "Packs";
   image = VehicleMineImage;
   shapeFile = "stackable2s.dts";
   mass = 3.0;
   elasticity = 0.1;
   friction = 0.4;
   pickupRadius = 1;
   rotate = true;
   pickUpName = "an anti-vehicle mine";
};

datablock ItemData(VehicleMineDeployed)
{
   className = Weapon;
   category = "VehicleMine";

   item = "VehicleMine";
   shapeFile = "stackable2s.dts";

   mass = 8.0;
   elasticity = 0.1;
   friction = 1.0;

   explosion = SatchelMainExplosion;
   pickupRadius = 1;
   maxDamage = 1.3;

   indirectDamage = 3.6;
   damageRadius = 28.0;

   radiusDamageType = $DamageType::Explosion;
   kickBackStrength = 6500;

   aiAvoidThis = true;
   dynamicType = $TypeMasks::DamagableItemObjectType;

   deployedObject = true;
  
   name = "Deployed Anti-Vehicle Mine";

   spacing = 17.0;
   proximity = 16.0;

   armTime = 2000;
   noTimeout = true;
};

function VehicleMineImage::onActivate(%data, %Player, %slot)
{
   ShapeBaseImageData::onActivate(%data, %Player, %slot);
}

function VehicleMineImage::onDeploy(%Mine, %Player, %Slot)
{
   %Client = %Player.client;
   %Team = %Client.team;

   // check for other deployed mines in the immediate vicinity
   %Position = %Mine.surfacePt;
   %Spacing = VehicleMineDeployed.spacing;

   InitContainerRadiusSearch(%Position, %Spacing, $TypeMasks::ItemObjectType);
   while ((%ObjectFound = containerSearchNext()) != 0)
   {
      // If it finds another vehicle mine, return
      if (%ObjectFound.getDatablock().category = "VehicleMine")
      {
         messageClient(%this.client, "", "Too close to another anti-vehicle mine.");
         return(0);
      }
      continue;         
   }

   // increment the team count for this deployed object
   $TeamDeployedCount[%Team, %Mine.item]++;

   // Take the deployable off the player's back and out of inventory
   %Player.unmountImage(%Slot);
   %Player.decInventory(VehicleMine, 1);  
   
   // Make the new mine
   %Item = new Item() {
      dataBlock = VehicleMineDeployed;
      rotation = "0 0 1 " @ (getRandom() * 360);
      position = %Mine.surfacePt;
   };
   MissionCleanup.add(%Item);

   %Item.armed = false;
   %Item.damaged = 0;
   %Item.detonated = false;
   %Item.owner = %Client;
   %Item.team = %Team;

   schedule(500, 0, VehicleMineRestCheck, %Item);

   return(%Item);
}

// This checks to see if the mine has come to a stop and then does several checks
// before it will set it active
function VehicleMineRestCheck(%Mine)
{
   // If mine is detonated, ignore it
   if (%Mine.detonated)
      return(0);

   // a delay before mine is armed
   %ArmTime = %Mine.getDataBlock().armTime;
   %Mine.Check = schedule(%ArmTime, 0, VehicleMineArm, %Mine);

   // Play charging sound
   %Mine.playAudio(0, SniperRifleSwitchSound);
}

// This function arms the mine and lets the bots know it is there
function VehicleMineArm(%Mine)
{
   %Mine.armed = true;
   %Proximity = %Mine.getDataBlock().proximity;

   %Transform = %Mine.getTransform();
   %Position = posFromTransform(%Transform);

   // Create the other part of the mine and link the two parts together
   %PositionXY = getWords(%Position, 0, 1);
   %PositionZ = getWord(%Position, 2) + 0.45;
   %Position = %PositionXY @ " " @ %PositionZ;

   %Item = new Item()
   {
      dataBlock = VehicleMineSpinner;
      position = %Position;
      rotation = "0 0 1 " @ (getRandom() * 360);
   };
   MissionCleanup.add(%Item);

   %Item.Master = %Mine;
   %Mine.Slave = %Item;

   // Start the 1 second loop searching for enemies
   %Mine.CheckTime = 0;
   %Mine.Check = VehicleMineCheckVicinity(%Mine, %Position, %Proximity);
}

// This makes the mine purely proximity, not contact.
function VehicleMineDeployed::onCollision(%data, %Mine, %col)
{

}

// This function is called after the mine has been deployed. It will check the
// immediate area around the mine the defined range for vehicles
// passing by.  When an enemy vehicle is found it begins tracking it and records
// the distance each loop (.25 seconds apart).
function VehicleMineCheckVicinity(%Mine, %Position, %Range)
{
   // don't keep checking if mine is already detonating
   if(%Mine.detonated)
      return(0);

   if(%Mine.CheckTime == 5)
   {
      %Mine.playAudio(0, PlasticBeep);
      %Mine.CheckTime = 0;
   } else {
      %Mine.CheckTime++;
   }

   %Masks = $TypeMasks::VehicleObjectType;
   InitContainerRadiusSearch(%Position, %Range, %Masks);

   while((%Target = containerSearchNext()) != 0) 
   {
      // Make the mine team friendly
      if (%Target.lastPilot.team == %Mine.team)
         continue;

      %Transform = %Mine.getTransform();
      %Position2 = posFromTransform(%Transform);
         
      %Distance = VectorLen(VectorSub(%Position, %Position2));
        
      %Mine.Check = schedule(250, 0, VehicleMineTargetTrack, %Mine, %Target, %Position, %Distance);
      return(0);
   }

   // If nothing was found, schedule another check in a second
   %this.Check = schedule(1000, 0, "VehicleMineCheckVicinity", %Mine, %Position, %Range);
}

// When the distance is starts increasing from the mine or target, it will explode.
// This allows the enemy to get as close as possible before it blows, maximizing damage.
function VehicleMineTargetTrack(%Mine, %Target, %Position, %Distance)
{
   %Transform = %Target.getTransform();
   %Position2 = posFromTransform(%Transform);

   %Distance2 = VectorLen(VectorSub(%Position, %Position2));

   // If the enemy is further than they were last time, blow it
   if (%Distance2 > %Distance + 0.2)
   {
      %Mine.setDamageState(Destroyed);
   } else {
      %Mine.Check = schedule(250, 0, VehicleMineTargetTrack, %Mine, %Target, %Position, %Distance2);
   }
}

// This function applied damage to the mine, it can cause it to explode.
// if the damage is sufficient.  One idea is to make the person who shot
// the mine responsible for the effect if that is what caused it to explode.
function VehicleMineDeployed::damageObject(%Data, %Mine, %SourceObject, %Position, %Amount, %DamageType)
{
   if (%Mine.detonated == true)
      return(0);

   %Mine.damaged += %Amount;

   if(%Mine.damaged >= %Data.maxDamage)
   {
      if (%SourceObject.team == %Mine.team)
         %Mine.Premature = true;

      %Mine.setDamageState(Destroyed);
   }
}

// This function does the actual explosion, gives credit to the one shooting it
function VehicleMineDeployed::onDestroyed(%data, %Mine, %lastState)
{
   // Mark the mine as blown so that all associated functions halt
   %Mine.detonated = true;

   Cancel(%Mine.Check);

   // Locate the mine and it's properties
   %Transform = %Mine.getTransform();
   %Position = posFromTransform(%Transform);
   %Source = %Mine.owner;

   %DataBlock = %Mine.getDataBlock();

   %Radius = %DataBlock.damageRadius;
   %Damage = %DataBlock.indirectDamage;
   %Impulse = %DataBlock.kickBackStrength;
   %Type = %DataBlock.radiusDamageType;

   // Allow the mine to be replaced
   $TeamDeployedCount[%Mine.Team, VehicleMine]--;

   if (%Mine.Premature == true)
      RadiusExplosion(%Mine, %Position, %Radius / 3, %Damage / 3, %Impulse / 3, %Source.player, %Type);
   else
      RadiusExplosion(%Mine, %Position, %Radius, %Damage, %Impulse, %Source.player, %Type);

   %Slave = %Mine.Slave;
   %Slave.schedule(100, delete);
   %Mine.schedule(100, delete);
}

function VehicleMineDeployed::ItemSwap(%Data, %Object)
{
   %Transform = %Object.getTransform();
   %Position = posFromTransform(%Transform);

   %Item = %Object.getDataBlock().item;

   %NewItem = new Item()
   {
      dataBlock = %Item;
      position = %Position;
   };
   MissionCleanup.add(%NewItem);

   $TeamDeployedCount[%Object.team, %Item]--;

   %Object.Slave.delete();
   %Object.delete();

   %NewItem.applyImpulse(%Position, "0 0 10");
   %NewItem.schedulePop();
}