//-------------------------------------- Ammo functions
function Ammo::onCollision(%data, %obj, %col)
{
   // %data = datablock of object; %obj = object number
   // %col = thing that collided with object (hopefully a player)

   if (%col.getDataBlock().className $= Armor)
   {
      %ammoName = %data.getName();
      %ammoStore = %col.inv[%ammoName];

      // if player has ammo pack, increase max amount of ammo
      if(%col.getMountedImage($BackpackSlot) != 0)
      {
         if(%col.getMountedImage($BackpackSlot).getName() $= "AmmoPackImage")
            %aMax = (%col.getDataBlock().max[%ammoName]) + AmmoPack.max[%ammoName];
         else
            %aMax = %col.getDataBlock().max[%ammoName];
      }
      else
         %aMax = %col.getDataBlock().max[%ammoName];

      if(%col.inv[%ammoName] < %aMax)
      {
         %col.incInventory(%ammoName, $AmmoIncrement[%ammoName]);
         serverPlay3D(ItemPickupSound, %col.getTransform());
         %obj.respawn();
         if (%col.client > 0)
            messageClient(%col.client, 'MsgItemPickup', '\c0You picked up %1.', %data.pickUpName);
      }
   }
}

function GrenadeThrown::onCollision(%data, %obj, %col)
{
   // nothing you can do now...
}

function HandInventory::onCollision(%data, %obj, %col)
{
   // %data = datablock of object; %obj = object number
   // %col = thing that collided with object (hopefully a player)
   if (%col.getDataBlock().className $= Armor)
   {
      %ammoName = %data.getName();
      %ammoStore = %col.inv[%ammoName];

      // if player has ammo pack, increase max amount of ammo
      if(%col.getMountedImage($BackpackSlot) != 0)
      {
         if(%col.getMountedImage($BackpackSlot).getName() $= "AmmoPackImage")
            %aMax = (%col.getDataBlock().max[%ammoName]) + AmmoPack.max[%ammoName];
         else
            %aMax = %col.getDataBlock().max[%ammoName];
      }
      else
         %aMax = %col.getDataBlock().max[%ammoName];

      if(%data.isGrenade)
      {
         // it's a grenade -- see if it matches the type the player is carrying
         %pgType = "None";
         for(%x = 0; $InvGrenade[%x] !$= ""; %x++)
         {
            %gren = $NameToInv[$InvGrenade[%x]];
            if(%col.inv[%gren] > 0)
            {
               %pgType = %gren;
               break;
            }
         }
         if((%pgType $= "None") || (%pgType $= %ammoName))
         {
            // player either has no grenades or this type of grenades -- OK to pick up more
            %canPickup = true;
         }
         else
         {
            // player has a different kind of grenade -- don't pick this kind up
            %canPickup = false;
         }
      }
      else
         %canPickup = true;

      if(%canPickup)
      {
         if(%col.inv[%ammoName] < %aMax)
         {
            %col.incInventory(%ammoName, $AmmoIncrement[%ammoName]);
            serverPlay3D(ItemPickupSound, %col.getTransform());
            %obj.respawn();
            if (%col.client > 0)
               messageClient(%col.client, 'MsgItemPickup', '\c0You picked up %1.', %data.pickUpName);
         }
      }
   }
}

//-------------------------------------- Specific turret functions

function SentryTurret::onAdd(%data, %obj)
{
   Parent::onAdd(%data, %obj);

   //error("error");
   %obj.mountImage(%data.barrel, 0, true);
}

function TurretDeployedCamera::onAdd(%this, %obj)
{
   Parent::onAdd(%this, %obj);   
   %obj.mountImage(DeployableCameraBarrel, 0, true);
	%obj.setRechargeRate(%this.rechargeRate);
}

function TurretDeployedCamera::onDestroyed(%this, %obj, %prevState)
{
   Parent::onDestroyed(%this, %obj, %prevState);
   $TeamDeployedCount[%obj.team, DeployedCamera]--;
   // doesn't seem to delete itself, so...
   %obj.schedule(500, "delete");
}

function ScoutFlyer::onTrigger(%data, %obj, %trigger, %state)
{
   // data = ScoutFlyer datablock
   // obj = ScoutFlyer object number
   // trigger = 0 for "fire", 1 for "jump", 3 for "thrust"
   // state = 1 for firing, 0 for not firing
   if(%trigger == 0)
   {
      switch (%state) {
         case 0:
            %obj.fireWeapon = false;
            %obj.setImageTrigger(2, false);
            %obj.setImageTrigger(3, false);
         case 1:
            %obj.fireWeapon = true;
            if(%obj.nextWeaponFire == 2) {
               %obj.setImageTrigger(2, true);
               %obj.setImageTrigger(3, false);
            }
            else {
               %obj.setImageTrigger(2, false);
               %obj.setImageTrigger(3, true);
            }
      }
   }
}

function ScoutFlyer::playerDismounted(%data, %obj, %player)
{
   %obj.fireWeapon = false;
   %obj.setImageTrigger(2, false);
   %obj.setImageTrigger(3, false);
   setTargetSensorGroup(%obj.getTarget(), %obj.team);
}

function ScoutChaingunImage::onFire(%data,%obj,%slot)
{
   // obj = ScoutFlyer object number
   // slot = 2

   Parent::onFire(%data,%obj,%slot);
   %obj.nextWeaponFire = 3;
   schedule(%data.fireTimeout, 0, "fireNextGun", %obj);
}

function ScoutChaingunPairImage::onFire(%data,%obj,%slot)
{
   // obj = ScoutFlyer object number
   // slot = 3

   Parent::onFire(%data,%obj,%slot);
   %obj.nextWeaponFire = 2;
   schedule(%data.fireTimeout, 0, "fireNextGun", %obj);
}

function fireNextGun(%obj)
{
   if(%obj.fireWeapon)
   {
      if(%obj.nextWeaponFire == 2)
      {
         %obj.setImageTrigger(2, true);
         %obj.setImageTrigger(3, false);
      }
      else
      {
         %obj.setImageTrigger(2, false);
         %obj.setImageTrigger(3, true);
      }
   }
   else
   {
      %obj.setImageTrigger(2, false);
      %obj.setImageTrigger(3, false);
   }
}

function ScoutChaingunImage::onTriggerDown(%this, %obj, %slot)
{
}

function ScoutChaingunImage::onTriggerUp(%this, %obj, %slot)
{
}

function ScoutChaingunImage::onMount(%this, %obj, %slot)
{
//   %obj.setImageAmmo(%slot,true);
}

function ScoutChaingunPairImage::onMount(%this, %obj, %slot)
{
//   %obj.setImageAmmo(%slot,true);
}

function ScoutChaingunImage::onUnmount(%this,%obj,%slot)
{
}

function ScoutChaingunPairImage::onUnmount(%this,%obj,%slot)
{
}


function BomberTurret::onDamage(%data, %obj)
{
   %newDamageVal = %obj.getDamageLevel();
   if(%obj.lastDamageVal !$= "")
      if(isObject(%obj.getObjectMount()) && %obj.lastDamageVal > %newDamageVal)   
         %obj.getObjectMount().setDamageLevel(%newDamageVal);
   %obj.lastDamageVal = %newDamageVal;
}

function BomberTurret::damageObject(%this, %damageObj, %projectile, %amount, %damageType)
{
   //If vehicle turret is hit then apply damage to the vehicle
   %vehicle = %damageObj.getObjectMount();
   %vehicle.getDataBlock().damageObject(%vehicle, %projectile, %amount, %damageType);
}

function VehicleTurret::onEndSequence(%data, %obj, %thread)
{
   if($DeployThread == %thread)
      %obj.stopThread($DeployThread);
}

function BomberTurret::onTrigger(%data, %obj, %trigger, %state)
{
   //error("onTrigger: trigger = " @ %trigger @ ", state = " @ %state);
   //error("obj = " @ %obj @ ", class " @ %obj.getClassName());
   switch (%trigger)
   {
      case 0:
         %obj.fireTrigger = %state;
         if(%obj.selectedWeapon == 1)
         {
            %obj.setImageTrigger(4, false);
            if(%obj.getImageTrigger(6))
            {
               %obj.setImageTrigger(6, false);
               ShapeBaseImageData::deconstruct(%obj.getMountedImage(6), %obj);
            }
            if(%state)
               %obj.setImageTrigger(2, true);
            else
               %obj.setImageTrigger(2, false);
         }
         else if(%obj.selectedWeapon == 2)
         {
            %obj.setImageTrigger(2, false);
            if(%obj.getImageTrigger(6))
            {
               %obj.setImageTrigger(6, false);
               ShapeBaseImageData::deconstruct(%obj.getMountedImage(6), %obj);
            }
            if(%state)
               %obj.setImageTrigger(4, true);
            else
               %obj.setImageTrigger(4, false);
         } 
         else
         {
            %obj.setImageTrigger(2, false);
            %obj.setImageTrigger(4, false);
            if(%state)
               %obj.setImageTrigger(6, true);
            else
            {
               %obj.setImageTrigger(6, false);
               BomberTargetingImage::deconstruct(%obj.getMountedImage(6), %obj);
            }                   
         }

      case 2:
         if(%state)
         {
            %obj.getDataBlock().playerDismount(%obj);
         }
   }
}

function BomberTurret::playerDismount(%data, %obj)
{
   //Passenger Exiting
   %obj.fireTrigger = 0;
   %obj.setImageTrigger(2, false);
   %obj.setImageTrigger(4, false);
   if(%obj.getImageTrigger(6))
   {
      %obj.setImageTrigger(6, false);
      ShapeBaseImageData::deconstruct(%obj.getMountedImage(6), %obj);
   }
   %client = %obj.getControllingClient();
   commandToClient(%client, 'endBomberSight');
//   %client.player.setControlObject(%client.player);
   %client.player.mountVehicle = false;
//   %client.player.getDataBlock().doDismount(%client.player);
   if(%client.player.getState() !$= "Dead")
      %client.player.mountImage(%client.player.lastWeapon, $WeaponSlot);
   setTargetSensorGroup(%obj.getTarget(), 0);
   setTargetNeverVisMask(%obj.getTarget(), 0xffffffff);
}

//function BomberTurret::getHudNum(%data, %num)
//{
//   if(%num == 1)
//      return 0;
//   else
//      return 4;
//}

function AIAimingTurretBarrel::onFire(%this,%obj,%slot)
{
}

function BomberBombImage::onUnmount(%this,%obj,%slot)
{
}

function BomberBombPairImage::onUnmount(%this,%obj,%slot)
{
}

function BomberTurretBarrel::onTriggerDown(%this, %obj, %slot)
{
   %obj.turretBarrelSchedule = %obj.schedule(300, "setImageTrigger", 3, true);
}

function BomberTurretBarrel::onTriggerUp(%this, %obj, %slot)
{
   cancel(%obj.turretBarrelSchedule);
   %obj.setImageTrigger( 3, false);
}

function BomberTurretBarrelPair::onMount(%this, %obj, %slot)
{
//   %obj.setImageAmmo(%slot,true);
}

function BomberTurretBarrel::onMount(%this, %obj, %slot)
{
//   %obj.setImageAmmo(%slot,true);
}


function BomberBombImage::onTriggerDown(%this, %obj, %slot)
{
   %obj.schedule(500, "setImageTrigger", 5, true);
}

function BomberBombImage::onTriggerUp(%this, %obj, %slot)
{
   %obj.schedule(600, "setImageTrigger", 5, false);
}

function BomberBombPairImage::onMount(%this, %obj, %slot)
{
//   %obj.setImageAmmo(%slot,true);
}

function BomberBombImage::onMount(%this, %obj, %slot)
{
}

function BomberBombImage::onUnmount(%this,%obj,%slot)
{
}

function BomberBombPairImage::onUnmount(%this,%obj,%slot)
{
}

function MobileTurretBase::onAdd(%this, %obj)
{
   Parent::onAdd(%this, %obj);
   setTargetSensorGroup(%obj.target, %obj.team);
   setTargetNeverVisMask(%obj.target, 0xffffffff);
}

function MobileTurretBase::onDamage(%data, %obj)
{
   %newDamageVal = %obj.getDamageLevel();
   if(%obj.lastDamageVal !$= "")
      if(isObject(%obj.getObjectMount()) && %obj.lastDamageVal > %newDamageVal)   
         %obj.getObjectMount().setDamageLevel(%newDamageVal);
   %obj.lastDamageVal = %newDamageVal;
}

function MobileTurretBase::damageObject(%this, %targetObject, %sourceObject, %position, %amount, %damageType)
{
   //If vehicle turret is hit then apply damage to the vehicle
   %vehicle = %targetObject.getObjectMount();
   if(%vehicle)
      %vehicle.getDataBlock().damageObject(%vehicle, %sourceObject, %position, %amount, %damageType);
}

function MobileTurretBase::onEndSequence(%data, %obj, %thread)
{
   //Used so that the parent wont be called..
}

function AssaultPlasmaTurret::onDamage(%data, %obj)
{
   %newDamageVal = %obj.getDamageLevel();
   if(%obj.lastDamageVal !$= "")
      if(isObject(%obj.getObjectMount()) && %obj.lastDamageVal > %newDamageVal)   
         %obj.getObjectMount().setDamageLevel(%newDamageVal);
   %obj.lastDamageVal = %newDamageVal;
}

function AssaultPlasmaTurret::damageObject(%this, %damageObj, %projectile, %amount, %damageType)
{                                           
   //If vehicle turret is hit then apply damage to the vehicle
   %vehicle = %damageObj.getObjectMount();
   %vehicle.getDataBlock().damageObject(%vehicle, %projectile, %amount, %damageType);
}

function AssaultPlasmaTurret::onTrigger(%data, %obj, %trigger, %state)
{
   switch (%trigger) {
      case 0:
         %obj.fireTrigger = %state;
         if(%obj.selectedWeapon == 1)
         {
            %obj.setImageTrigger(4, false);
            if(%state)
               %obj.setImageTrigger(2, true);
            else
               %obj.setImageTrigger(2, false);
         }                       
         else
         {
            %obj.setImageTrigger(2, false);
            if(%state)
               %obj.setImageTrigger(4, true);
            else           
               %obj.setImageTrigger(4, false);
         } 
      case 2:
         if(%state) 
         {
            %obj.getDataBlock().playerDismount(%obj);
         }
   }
}

function AssaultPlasmaTurret::playerDismount(%data, %obj)
{
   //Passenger Exiting
   %obj.fireTrigger = 0;
   %obj.setImageTrigger(2, false);
   %obj.setImageTrigger(4, false);
   %client = %obj.getControllingClient();
// %client.setControlObject(%client.player);
   %client.player.mountImage(%client.player.lastWeapon, $WeaponSlot);
   %client.player.mountVehicle = false;
   setTargetSensorGroup(%obj.getTarget(), 0);
   setTargetNeverVisMask(%obj.getTarget(), 0xffffffff);
//   %client.player.getDataBlock().doDismount(%client.player);
}

//function AssaultPlasmaTurret::getHudNum(%data, %num)
//{
//   if(%num == 1)
//      return 1;
//   else
//      return 3;
//}


// ------------------------------------------
// camera functions
// ------------------------------------------

$CameraDeployTime = 1000;
$CameraDeployCheckMax = 6;
$CameraMinVelocity = 0.1;

function CameraGrenadeThrown::onThrow(%this, %gren)
{
   // schedule a check to see if the camera is at rest but not deployed
   %gren.checkCount = 0;
   %gren.velocCheck = %this.schedule($CameraDeployTime, "checkCameraDeploy", %gren);
}

function CameraGrenadeThrown::onStickyCollision(%data, %obj)
{
   cancel(%obj.velocCheck);
   %pos = %obj.getLastStickyPos();
   %norm = %obj.getLastStickyNormal();
   
   %intAngle = getTerrainAngle(%norm);  // staticShape.cs
   %rotAxis = vectorNormalize(vectorCross(%norm, "0 0 1"));
   if (getWord(%norm, 2) == 1 || getWord(%norm, 2) == -1)
      %rotAxis = vectorNormalize(vectorCross(%norm, "0 1 0"));

   %rotation = %rotAxis @ " " @ %intAngle;
   %dcSucc = activateCamera(%pos, %rotation, %obj.sourceObject, %obj.sourceObject.team);
   if(%dcSucc == 0)
      messageClient(%obj.sourceObject.client, 'MsgDeployFailed', '\c2Your team\'s control network has reached its capacity for this item.~wfx/misc/misc.error.wav');
   %obj.schedule(50,"delete");
}

function CameraGrenadeThrown::checkCameraDeploy(%this, %gren)
{
   %gren.checkCount++;
   if(VectorLen(%gren.getVelocity()) < $CameraMinVelocity)
   {
      // camera has come to rest but not deployed -- probably on a staticshape (station, gen, etc)
      // no resolution, so get rid of it
      %gren.schedule(50, "delete");
   }
   else if(%gren.checkCount >= $CameraDeployCheckMax)
   {
      // camera's still moving but it's been check several times -- it was thrown from too great
      // a height or off the edge of the world -- delete it
      %gren.schedule(50, "delete");
   }
   else
   {
      // check back in a little while
      %gren.velocCheck = %this.schedule($CameraDeployTime, "checkCameraDeploy", %gren);
   }
}

function activateCamera(%position, %rotation, %sourceObj, %team)
{
   if($TeamDeployedCount[%team, DeployedCamera] >= $TeamDeployableMax[DeployedCamera])
   {
      // team has too many cameras deployed already, don't deploy this one
      return 0;
   }
   %dCam = new Turret()
   {
      dataBlock = "TurretDeployedCamera";                            
      team = %team;
      needsNoPower = true;
      owner = %sourceObj.client;
      ownerHandle = %sourceObj.client.handle;
      position = %position;
      rotation = %rotation;
   };
   addToDeployGroup(%dCam);

   if(%dCam.getTarget() != -1)
      setTargetSensorGroup(%dCam.getTarget(), %team);

   %dCam.playAudio($DeploySound, CameraGrenadeAttachSound);
   %dCam.deploy();
   %dCam.playThread($AmbientThread, "ambient");

   // increment team's deployed count for cameras
   $TeamDeployedCount[%team, DeployedCamera]++;
   return 1;
}

function FlareGrenade::onUse(%this, %obj)
{
   // a stripped-down version of HandInventory::onUse from weapons.cs
   if(Game.handInvOnUse(%data, %obj)) {
      %obj.decInventory(%this, 1);
      %p = new FlareProjectile() {
         dataBlock        = FlareGrenadeProj;
         initialDirection = %obj.getEyeVector();
         initialPosition  = getBoxCenter(%obj.getWorldBox());
         sourceObject     = %obj;
         sourceSlot       = 0;
      };
      FlareSet.add(%p);
      MissionCleanup.add(%p);
      serverPlay3D(GrenadeThrowSound, getBoxCenter(%obj.getWorldBox()));
      %p.schedule(6000, "delete");
      // miscellaneous grenade-throwing cleanup stuff
      %obj.lastThrowTime[%data] = getSimTime();
      %obj.throwStrength = 0;
   }
}

// uncomment when explosion type can be set from script (dont want underwater explosion here)
//function grenadeOnEnterLiquid(%data, %obj, %coverage, %type, %flash)
//{
//   // 4: Lava 
//   // 5: Hot Lava
//   // 6: Crusty Lava
//   if(%type >=4 && %type <= 6)
//   {
//      if(%obj.getDamageState() !$= "Destroyed")
//      {
//         cancel(%obj.detThread);
//         if(%flash)
//            detonateFlashGrenade(%obj);
//         else
//            detonateGrenade(%obj);
//         return(true);
//      }
//   }
//   
//   // flash grenades do not ignore quicksand
//   if((%type == 7) && !%flash)
//      return(true);
//
//   return(false);
//}

function GrenadeThrown::onThrow(%this, %gren)
{
   AIGrenadeThrown(%gren);
   %gren.detThread = schedule(1500, %gren, "detonateGrenade", %gren);
}

//function GrenadeThrown::onEnterLiquid(%data, %obj, %coverage, %type)
//{
//   if(!grenadeOnEnterLiquid(%data, %obj, %coverage, %type, false))
//      Parent::onEnterLiquid(%data, %obj, %coverage, %type);
//}

function ConcussionGrenadeThrown::onThrow(%this, %gren)
{
   AIGrenadeThrown(%gren);
   %gren.detThread = schedule(2000, %gren, "detonateGrenade", %gren);
}

//function ConcussionGrenadeThrown::onEnterLiquid(%data, %obj, %coverage, %type)
//{
//   if(!grenadeOnEnterLiquid(%data, %obj, %coverage, %type, false))
//      Parent::onEnterLiquid(%data, %obj, %coverage, %type);
//}

function detonateGrenade(%obj)
{
   %obj.setDamageState(Destroyed);
   %data = %obj.getDataBlock();
   RadiusExplosion( %obj, %obj.getPosition(), %data.damageRadius, %data.indirectDamage, 
                   %data.kickBackStrength, %obj.sourceObject, %data.radiusDamageType);
   %obj.schedule(500,"delete");
}

function FlashGrenadeThrown::onThrow(%this, %gren)
{
   %gren.detThread = schedule(2000, %gren, "detonateFlashGrenade", %gren);
}

//function FlashGrenadeThrown::onEnterLiquid(%data, %obj, %coverage, %type)
//{
//   if(!grenadeOnEnterLiquid(%data, %obj, %coverage, %type, true))
//      Parent::onEnterLiquid(%data, %obj, %coverage, %type);
//}

function detonateFlashGrenade(%hg)
{
   %hg.setDamageState(Destroyed);
   %hgt = %hg.getTransform();
   %plX = firstword(%hgt);
   %plY = getWord(%hgt, 1);
   %plZ = getWord(%hgt, 2);
   %pos = %plX @ " " @ %plY @ " " @ %plZ;
   //all this stuff below ripped from projectiles.cs

   InitContainerRadiusSearch(%pos, 100.0, $TypeMasks::PlayerObjectType |
                                          $TypeMasks::TurretObjectType);

   while ((%damage = containerSearchNext()) != 0)
   {
      %dist = containerSearchCurrDist();

      %eyeXF = %damage.getEyeTransform();
      %epX   = firstword(%eyeXF);
      %epY   = getWord(%eyeXF, 1);
      %epZ   = getWord(%eyeXF, 2);
      %eyePos = %epX @ " " @ %epY @ " " @ %epZ;
      %eyeVec = %damage.getEyeVector();

      // Make sure we can see the thing...
      if (ContainerRayCast(%eyePos, %pos, $TypeMasks::TerrainObjectType |
                                          $TypeMasks::InteriorObjectType |
                                          $TypeMasks::StaticObjectType, %damage) !$= "0")
      {
         continue;
      }

      %distFactor = 1.0;
      if (%dist >= 100)
         %distFactor = 0.0;
      else if (%dist >= 20) {
         %distFactor = 1.0 - ((%dist - 20.0) / 80.0);
      }

      %dif = VectorNormalize(VectorSub(%pos, %eyePos));
      %dot = VectorDot(%eyeVec, %dif);

      %difAcos = mRadToDeg(mAcos(%dot));
      %dotFactor = 1.0;
      if (%difAcos > 60)
         %dotFactor = ((1.0 - ((%difAcos - 60.0) / 120.0)) * 0.2) + 0.3;
      else if (%difAcos > 45)
         %dotFactor = ((1.0 - ((%difAcos - 45.0) / 15.0)) * 0.5) + 0.5;

      %totalFactor = %dotFactor * %distFactor;
      %damage.setWhiteOut(%damage.getWhiteOut() + %totalFactor);
   }
   %hg.schedule(500, "delete");
}

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


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

function deployMineCheck(%mineObj)
{
   if(%mineObj.depCount > %mineObj.getDatablock().maxDepCount)
      explodeMine(%mineObj, true);
   // wait until the mine comes to rest
   if(%mineObj.getVelocity() $= "0 0 0")
   {
      // 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::ItemObjectType);
      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])
         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
      %mineObj.depCount++;
      schedule(500, %mineObj, "deployMineCheck", %mineObj);
   }
}

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) 
         {
            %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")
   {
      //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.sourceObject.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");
}