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