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;
};