
// --------------------------------------------------------------------------
// Havoc Team Friendly Mines
// These mines will only go off if an enemy is near or enemy piloted vehicle
// The Anti-Personnel are tracked all as MineDeployed so that the total of 25
// is not exceeded, but the players determine the types.  Also if a mine can't
// deploy for some reason, it tells the user and does not explode just waits
// to be picked up.
// --------------------------------------------------------------------------


// ----------------------------------------------
// Standard Mine

// This is a single undeployed mine that can be used if picked up, the same as a regular one.
datablock ItemData(MineSingle)
{     
   className = HandInventory;
   category = "Dropped";
   item = "Mine";
   shapeFile = "mine.dts";
   mass = 0.75;

   elasticity = 0.2;
   friction = 0.7;
   pickupRadius = 1;

   isMine = true;

   AlternateObject = Mine;
 
   thrownItem = MineDeployed;
   pickUpName = "an anti-personnel mine";
};

function MineSingle::onPickup(%this, %Mine, %Player, %Amount)
{
   %Player.incInventoy(%Mine.AlternateObject, 1);
   %Player.decInventoy(%Mine, 1);
}

function MineRepack(%Mine)
{
   %Transform = %Mine.getTransform();
   %Position = posFromTransform(%Transform);
 
   %NewItem = new Item()
   {
      dataBlock = %Mine.getDataBlock().packedItem;
      position = %Position;
   };
   MissionCleanup.add(%NewItem);

   %Mine.delete();
}

datablock ItemData(MineDeployed)
{
   className = Weapon;
   category = "Mine";
   shapeFile = "mine.dts";
   item = "Mine";
   packedItem = "MineSingle";

   DeployedItem = WallMine;

   mass = 0.75;


   elasticity = 0.3;
   friction = 0.6;

   explosion = MineExplosion;
   maxDamage = 0.35;
   hasDamageRadius     = true;
   indirectDamage = 0.6;
   damageRadius = 6.0;
   radiusDamageType = $DamageType::Explosion;
   kickBackStrength = 1500;
   aiAvoidThis = true;
   dynamicType = $TypeMasks::DamagableItemObjectType;
   spacing = 6.0;
   proximity = 2.5;
   armTime = 2000;
   rearDamageFactor = 1.2;
};

datablock StaticShapeData(WallMine) : StaticShapeDamageProfile
{
   className = Weapon;
   category = "Mine";

   shapeFile = "mine.dts";
   item = "Mine";

   sticky = true;

   mass = 0.0;
   elasticity = 0;
   friction = 1.0;

   explosion = MineExplosion;

   maxDamage = 0.35;
   hasDamageRadius     = true;
   indirectDamage = 0.6;
   damageRadius = 6.0;
   radiusDamageType = $DamageType::Explosion;
   kickBackStrength = 1500;

   aiAvoidThis = true;

   dynamicType = $TypeMasks::DamagableItemObjectType;
   spacing = 6.0;
   proximity = 2.5;

   armTime = 2000;

   rearDamageFactor    = 1.2;
};

datablock ItemData(MineFizzle)
{
   className = Weapon;
   category = "Mine";
   shapeFile = "mine.dts";
   item = "Mine";
   mass = 0.75;
   elasticity = 0.2;
   friction = 0.6;
   explosion      = "DeployablesExplosion";
   maxDamage = 1000;
   hasDamageRadius = false;
   aiAvoidThis = false;
};

datablock ItemData(Mine)
{     
   className = HandInventory;
   catagory = "Handheld";

   shapeFile = "mine.dts";
   mass = 1;
   trueMass = 0.04;

   elasticity = 0.2;
   friction = 0.7;
   pickupRadius = 1;

   DeployedItem = WallMine;

   isMine = true;

   thrownItem = MineDeployed;
   pickUpName = "some anti-personnel mines";
};

// This is the initial mine throw it starts several things, including a check for
// to stabilize the mine.  If a mine was thrown over an edge or slides for a long
// time we disable the mine.  We give the mine 12 seconds to arm itself or we
// remove it
function MineDeployed::onThrow(%this, %Mine)
{
   %Mine.armed = false;
   %Mine.damaged = 0;
   %Mine.detonated = false;
   %Mine.team = %Mine.sourceObject.team;
   %Mine.MineCheck = schedule(1500, 0, "MineCheck", %Mine);
   %Mine.ArmCheck = schedule(12000, 0, "MineArmingCheck", %Mine);
}

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

}

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

   // If the mine is moving, check again in 0.75 seconds to see if it has stopped moving
   if (VectorLen(%Mine.getVelocity()) > 0.1)
   {
      %Mine.MineCheck = schedule(750, 0, "MineCheck", %Mine);
      return(0);
   }

   // Record the use of this mine - if blown prematurely or otherwise it will be decremented
   $TeamDeployedCount[%Team, MineDeployed]++; 

   // Check to make sure that the team does not have too many mines currently deployed
   %Team = %Mine.sourceObject.team;
   if ($TeamDeployedCount[%Team, MineDeployed] > $TeamDeployableMax[MineDeployed])
   {
      // Too many mines of this type in use on that team, repack it
      // Don't apply the full amount of damage.
      messageClient(%Mine.sourceObject, 'MsgCantSitHere', 'Too many anti-personnel mines already deployed.');
      MineRepack(%Mine);
      return(0);
   }
   
   // check for other deployed mines in the immediate vicinity
   %Position = %Mine.getWorldBoxCenter();
   %Spacing = %Mine.getDatablock().spacing;
   InitContainerRadiusSearch(%Position, %Spacing, $TypeMasks::ItemObjectType | $TypeMasks::StaticShapeObjectType);
   while ((%ObjectFound = containerSearchNext()) != 0)
   {

      // It will find itself so we ignore that
      if (%ObjectFound == %Mine)
         continue;

      // If it finds something other than another mine, ignore it.
      %Category =%ObjectFound.getDatablock().category;
      if (%Category !$= "Mine")
         continue;

      // Detonate mine because it is too close another mine
      messageClient(%Mine.sourceObject.client, 'MsgCantSitHere', 'Too close to another anti-personnel mine.');
      MineRepack(%Mine);
      return(0);
         
   }

   // a delay before mine is armed -- let the animation finished first
   %ArmTime = %Mine.getDatablock().armTime;
   %Mine.ArmMine = Schedule(%ArmTime, 0, "ArmMine", %Mine);
   
   // Play the digging into the ground animation and make the proper sound
   %Mine.playThread(0, "deploy");
   serverPlay3D(MineDeploySound, %Mine.getTransform());
}

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

   %Transform = %Mine.getTransform();
   %Position = posFromTransform(%Transform);
   %Proximity = %Mine.getDataBlock().proximity;

   // Start the .5 second loop searching for enemies
   MineCheckVicinity(%Mine, %Position, %Proximity);

   //let the AI know it's is there...
   AIDeployMine(%Mine);

   // Cancel the MineArmingCheck
   Cancel(%Mine.ArmCheck);
}

// This function will detonate the mine
function MineExplode(%Mine)
{
   %Mine.setDamageState(Destroyed);
}

// This function will caused the mine to be detonated at 10% power if it is not yet armed.
function MineArmingCheck(%Mine)
{
   // If armed, then we leave the mine alone.
   if (%Mine.armed == true)
      return;

   // If it doesn't exist, return.
   if (isObject(%Mine) == false)
      return;

   %Mine.setDamageState(Destroyed);
   return;
}

// This function is called after the mine has been deployed. It will check the
// immediate area around the mine the defined range for players or vehicles
// passing by, and detonate if any are found. This is to extend the range of the
// mine so players don't have to collide with them to set them off.

function MineCheckVicinity(%Mine, %Position, %Range)
{
   // don't keep checking if mine is already detonating
   if(%Mine.detonated == true)
      return;

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

   while((%Target = containerSearchNext()) != 0) 
   {
      // Make the mine team friendly for players
      if (%Target.client.team == %Mine.team && $Host::TeamFriendlyMines == true)
         continue;

      // Make the mine team friendly for vehicles piloted by friendlies
      if (%Target.lastPilot.client.team == %Mine.team && $Host::TeamFriendlyMines == true)
         continue;

      // Also if the mine owner is the one it found, then whipe the source as they
      // placed it while on the other team and it should not count as a suicide.
      if (%ObjectFound == %Mine.sourceObject && $Host::TeamFriendlyMines == true)
         %Mine.sourceObject = '';

      %Mine.setDamageState(Destroyed);

      return;
   }

   // If nothing was found, schedule another check in 0.5 seconds
   %Mine.MineCheckVicinity = schedule(650, %Mine, "MineCheckVicinity", %Mine, %Position, %Range);
}

// 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 MineDeployed::damageObject(%Data, %Mine, %SourceObject, %Position, %Amount, %DamageType)
{
   if (%Mine.detonated == true)
      return(0);

   %Mine.damaged += %Amount;

   if (%Mine.damaged >= %Data.maxDamage)
   {
      // If it is not armed, just make a pop
      if (%Mine.armed == true)
      {
         %Mine.setDamageState(Destroyed);
      } else {
         %Position = posFromTransform(%Mine.getTransform());

         %Item = new Item()
         {
            datablock = MineFizzle;
            position = %Position;
         };
         MissionCleanUp.add(%Item);

         %Mine.schedule(450, delete);
         schedule(500, 0, detonateGrenade, %Item);
      }
   }
}

// This function does the actual explosion, gives credit to the one shooting it
function MineDeployed::onDestroyed(%data, %Mine, %lastState)
{
   if (%Mine.detonated == true)
      return;

   // Mark the mine as blown so that all associated functions halt
   %Mine.detonated = true;

   // Cancel any potential schedules
   Cancel(%Mine.MineCheck);
   Cancel(%Mine.ArmCheck);
   Cancel(%Mine.MineArm);
   Cancel(%Mine.MineCheckVicinity);

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

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

   %DataBlock = %Mine.getDataBlock();
   %Radius = %DataBlock.damageRadius;
   %Damage = %DataBlock.indirectDamage;
   %Impulse = %DataBlock.kickBackStrength;
   %Type = %DataBlock.radiusDamageType;

   RadiusExplosion(%Mine, %Position, %Radius, %Damage, %Impulse, %Source, %Type);

   %Mine.schedule(450, "delete");
}

function WallMine::damageObject(%Data, %Mine, %SourceObject, %Position, %Amount, %DamageType)
{
   MineDeployed::damageObject(%Data, %Mine, %SourceObject, %Position, %Amount, %DamageType);
}

function WallMine::onDestroyed(%data, %Mine, %lastState)
{
   MineDeployed::onDestroyed(%data, %Mine, %lastState);
}