--------------------------------------------------------------------------------------------
Sticky and Team Friendly Mine Tutorial
--------------------------------------------------------------------------------------------
This tutorial makes mines team friendly when team damage is off. It also makes them stick to walls and rotates them accordingly. To make them rotate (since items won't), it convert the mines to statics once they come to rest.

Update: Removed gap between deployed mine and walls in function deployMineCheck. (01/25/02)

Step #1
// ------------------------------------------
// weapTurretCode.cs
// ------------------------------------------
At the bottom of the file, replace all the mine code with this:


// ----------------------------------------------
// mine functions
// ----------------------------------------------

function MineThrown::onThrow(%this, %mine, %thrower)
{
   %mine.armed = false;
   %mine.damaged = 0;
   %mine.detonated = false;
   %mine.depCount = 0;
   %mine.theClient = %thrower.client;
   schedule(1500, %mine, "deployMineCheck", %mine, %thrower);
}

function deployMineCheck(%mineObj2, %player)
{
   if(%mineObj2.depCount > MineDeployed.maxDepCount)
      explodeMine(%mineObj, true);

   // wait until the mine comes to rest
   if(%mineObj2.getVelocity() $= "0 0 0")
   {
      %mineObj = new StaticShape() {
         dataBlock = MineDeployed;
         sourceObject = %player;
         armed = false;
         damaged = 0;
         detonated = false;
         depCount = 0;
         team = %player.team;
         theClient = %player.client;
      };
      %pos = posFromTransform(%mineObj2.getTransform());
      %norm = %mineObj2.getLastStickyNormal();
      %masks = $TypeMasks::InteriorObjectType | $TypeMasks::TerrainObjectType;
      %endpos = VectorAdd(%pos, VectorScale(%norm, -1));
      %hit = ContainerRayCast(%pos, %endpos, %masks, %minObj);
      if (%hit)
         %pos = getWords(%hit, 1, 3);

      //Use below line to move slightly away from wall if needed.
      //%pos = VectorAdd(%pos, VectorScale(%norm, 0.1));

      %mineObj2.schedule(1, delete);
      %mineObj.setDeployRotation(%pos, %norm);
      // 2-second delay before mine is armed -- let deploy thread play out etc.
      schedule(%mineObj.getDatablock().armTime, %mineObj, "armDeployedMine", %mineObj);

      // check for other deployed mines in the vicinity
      InitContainerRadiusSearch(%mineObj.getWorldBoxCenter(), %mineObj.getDatablock().spacing, $TypeMasks::StaticShapeObjectType);
      while((%itemObj = containerSearchNext()) != 0)
      {
         if(%itemObj == %mineObj)
            continue;
         %ioType = %itemObj.getDatablock().getName();
         if(%ioType $= "MineDeployed")
            schedule(100, %mineObj, "explodeMine", %mineObj, true);
         else
            continue;
      }
      // play "deploy" thread
      %mineObj.playThread(0, "deploy");
      serverPlay3D(MineDeploySound, %mineObj.getTransform());
      %mineTeam = %mineObj.sourceObject.team;
      $TeamDeployedCount[%mineTeam, MineDeployed]++;
      if($TeamDeployedCount[%mineTeam, MineDeployed] > $TeamDeployableMax[MineDeployed])
      {
         messageClient( %player.client, '', 'Maximum allowable mines deployed.' );
         schedule(100, %mineObj, "explodeMine", %mineObj, true);
      }
      else
      {
         //start the thread that keeps checking for objects near the mine...
         mineCheckVicinity(%mineObj);

         //let the AI know *after* it's come to rest...
         AIDeployMine(%mineObj);

         //let the game know there's a deployed mine
         Game.notifyMineDeployed(%mineObj);
      }
   }
   else
   {
      //schedule this deploy check again a little later
      %mineObj2.depCount++;
      schedule(500, %mineObj2, "deployMineCheck", %mineObj2, %player);
   }
}

function armDeployedMine(%mine)
{
   %mine.armed = true;
}

function mineCheckVicinity(%mine)
{
   // this function is called after the mine has been deployed. It will check the
   // immediate area around the mine (2.5 meters at present) 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.

   // don't bother to check if mine isn't armed yet
   if(%mine.armed)
      // don't keep checking if mine is already detonating
      if(!%mine.boom)
      {
         // the actual check for objects in the area
         %mineLoc = %mine.getWorldBoxCenter();
         %masks = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType;
         %detonateRange = %mine.getDatablock().proximity;

         InitContainerRadiusSearch(%mineLoc, %detonateRange, %masks);
         while((%tgt = containerSearchNext()) != 0)
         {
            if (($teamDamage) || (%tgt.team != %mine.team))
            {
               %mine.detonated = true;
               schedule(50, %mine, "explodeMine", %mine, false);
               break;
            }
         }
      }
   // if nothing set off the mine, schedule another check
   if(!%mine.detonated)
      schedule(300, %mine, "mineCheckVicinity", %mine);
}

function MineDeployed::onCollision(%data, %obj, %col)
{
   // don't detonate if mine isn't armed yet
   if(!%obj.armed)
      return;

   // don't detonate if mine is already detonating
   if(%obj.boom)
      return;

   //check to see what it is that collided with the mine
   %struck = %col.getClassName();
   if(%struck $= "Player" || %struck $= "WheeledVehicle" || %struck $= "FlyingVehicle")
   {
      if (($teamDamage) || (%col.team != %obj.team))
      {
         //error("Mine detonated due to collision with #"@%col@" ("@%struck@"); armed = "@%obj.armed);
         explodeMine(%obj, false);
      }
   }
}

function explodeMine(%mo, %noDamage)
{
   %mo.noDamage = %noDamage;
   %mo.setDamageState(Destroyed);
}

function MineDeployed::damageObject(%data, %targetObject, %sourceObject, %position, %amount, %damageType)
{
   if(!%targetObject.armed)
      return;

   if(%targetObject.boom)
      return;

   %targetObject.damaged += %amount;

   if(%targetObject.damaged >= %data.maxDamage)
   {
      %targetObject.setDamageState(Destroyed);
   }
}

function MineDeployed::onDestroyed(%data, %obj, %lastState)
{
   %obj.boom = true;
   %mineTeam = %obj.team;
   $TeamDeployedCount[%mineTeam, MineDeployed]--;
   // %noDamage is a boolean flag -- don't want to set off all other mines in
   // vicinity if there's a "mine overload", so apply no damage/impulse if true
   if(!%obj.noDamage)
      RadiusExplosion(%obj, %obj.getPosition(), %data.damageRadius, %data.indirectDamage,
                      %data.kickBackStrength, %obj.sourceObject, %data.radiusDamageType);

   %obj.schedule(600, "delete");
}


Step #2
// ------------------------------------------
// Mine.cs
// ------------------------------------------
Replace the mine datablocks at the bottom with this:


datablock ItemData(MineThrown)
{
   className = Weapon;
   shapeFile = "mine.dts";
   mass = 0.75;
   elasticity = 0.2;
   friction = 0.6;
   pickupRadius = 3;
   maxDamage = 0.2;
   explosion = MineExplosion;
   underwaterExplosion = UnderwaterMineExplosion;
   indirectDamage = 0.55;
   damageRadius = 6.0;
   radiusDamageType = $DamageType::Mine;
   kickBackStrength = 1500;
	aiAvoidThis = true;
   dynamicType = $TypeMasks::DamagableItemObjectType;
	spacing = 6.0; // how close together mines can be
	proximity = 2.5; // how close causes a detonation (by player/vehicle)
	armTime = 2200; // 2.2 seconds to arm a mine after it comes to rest
	maxDepCount = 9; // try to deploy this many times before detonating

   computeCRC = true;
   sticky = true;
};

datablock StaticShapeData(MineDeployed)
{
   className = Weapon;
   shapeFile = "mine.dts";
   mass = 0.75;
   elasticity = 0.2;
   friction = 0.6;
   pickupRadius = 3;
   maxDamage = 0.2;
   explosion = MineExplosion;
   underwaterExplosion = UnderwaterMineExplosion;
   indirectDamage = 0.55;
   damageRadius = 6.0;
   radiusDamageType = $DamageType::Mine;
   kickBackStrength = 1500;
	aiAvoidThis = true;
   dynamicType = $TypeMasks::DamagableItemObjectType;
	spacing = 6.0; // how close together mines can be
	proximity = 2.5; // how close causes a detonation (by player/vehicle)
	armTime = 2200; // 2.2 seconds to arm a mine after it comes to rest
	maxDepCount = 9; // try to deploy this many times before detonating

   computeCRC = true;
   sticky = true;
};

datablock ItemData(Mine)
{
   className = HandInventory;
   catagory = "Handheld";
   shapeFile = "ammo_mine.dts";
   mass = 1;
   elasticity = 0.2;
   friction = 0.7;
   pickupRadius = 2;

   thrownItem = MineThrown;
	pickUpName = "some mines";

   computeCRC = true;

};