--------------------------------------------- Magnetic Air Mine Tutorial --------------------------------------------- This tutorial makes a new mine that sits up in the air and looks over a wide radius for enemy players or vehicles. When one gets in range, it changes to a missle (keeps the mine dts) and chases the enemy down. Update: Added max[MagneticMine] to ammopack.cs (4/7) Update: Fixed the clerical errors. Thanks for spotting those. --------------------------------------------- Before adding any new mines, a few things need changed to get the code ready for multiple mines. These pre-steps only need done once and will be ready for any future mines. Pre - Step #1 // ------------------------------------------ // Inventory.cs // ------------------------------------------ In function shapebase::use, below these lines: else if(%data $= Beacon) { %data.onUse(%this); if (%this.inv[%data.getName()] > 0) return true; } add this: else if(%data $= Mine) { for(%x = 0; $InvMine[%x] !$= ""; %x++) { if(%this.inv[$NameToInv[$InvMine[%x]]] > 0) { %data = $NameToInv[$InvMine[%x]]; break; } } } Pre - Step #2 // ------------------------------------------ // InventoryHud.cs // ------------------------------------------ In function invAmmoPackPass, change these lines: %mineFav = %client.favorites[getField(%client.mineIndex, 0)]; if((%mineFav !$= "EMPTY") && (%mineFav !$= "INVALID") && !($InvBanList[%cmt, Mine])) %client.player.incInventory($NameToInv[%mineFav], AmmoPack.max[$NameToInv[%mineFav]]); to this: for (%i=0; $InvMine[%i] !$= ""; %i++) { %mine = $NameToInv[$InvMine[%i]]; for (%i1=0; %i1 < getFieldCount(%client.mineIndex); %i1++) if ( $InvMine[%i] $= %client.favorites[getField( %client.mineIndex, %i1 )] ) %player.incInventory(%mine, ammoPack.max[%mine]); } Pre - Step #3 // ------------------------------------------ // ammoPack.cs // ------------------------------------------ in Function AmmoPack::onPickup, change these lines: %mineFav = %player.client.favorites[getField(%player.client.mineIndex, 0)]; if ( ( $InvBanList[$CurrentMissionType, "Mine"] !$= "1" ) && !( ( %mineFav $= "EMPTY" ) || ( %mineFav $= "INVALID" ) ) ) { // player has selected mines, and they are legal in this mission type if(%pack.inv[Mine] > 0) { // and the pack has some mines in it! bonus! %player.incInventory(Mine, %pack.getInventory(Mine)); %pack.setInventory(Mine, 0); } else if(%pack.inv[Mine] == -1) { // no mines left in the pack. do nothing. } else { // assume it's full of mines if no inventory has been assigned %player.incInventory(Mine,%this.max[Mine]); } } to this: for (%i=0; $InvMine[%i] !$= ""; %i++) { %mine = $NameToInv[$InvMine[%i]]; if(%player.inv[%mine] > 0) { %Found = true; if(%pack.inv[%mine] > 0) { %player.incInventory(%mine, %pack.getInventory(%mine)); %pack.setInventory(%mine, 0); } } } if(!%Found) { %given = false; for (%i=0; $InvMine[%i] !$= ""; %i++) { %mine = $NameToInv[$InvMine[%i]]; for (%i1=0; %i1 < getFieldCount(%client.mineIndex); %i1++) { if ($InvMine[%i] $= %client.favorites[getField( %client.mineIndex, %i1 )]) { if(%pack.inv[%mine] > 0) { %player.incInventory(%mine, %pack.getInventory(%mine)); %pack.setInventory(%mine, 0); %given = true; break; } else if(%pack.inv[%mine] != -1) { %player.incInventory(%mine, %this.max[%mine]); %given = true; } if(%given) break; } } } } and in Function dropAmmoPack, change these lines: if(%player.getInventory(Mine) > %player.getDatablock().max[Mine]) { // if player has more mines than datablock's max... if(%packObj > 0) { // put mines that player can't carry anymore in pack %packObj.setInventory(Mine, %player.getInventory(Mine) - %player.getDatablock().max[Mine]); } // set player to max mines %player.setInventory(Mine, %player.getDatablock().max[Mine]); } else { if(%packObj > 0) { // the pack gets -1 for mines -- else it'll assume it's full // can't use setInventory() because it won't allow values less than 1 %packObj.inv[Mine] = -1; } } to this: for (%i=0; $InvMine[%i] !$= ""; %i++) { %mine = $NameToInv[$InvMine[%i]]; if(%player.inv[%mine] > 0) { %pAmmo = %player.getInventory(%mine); %pMax = %player.getDatablock().max[%mine]; if(%pAmmo > %pMax) { if(%packObj > 0) %packObj.setInventory(%mine, %pAmmo - %pMax); %player.setInventory(%mine, %pMax); } else if(%packObj > 0) %packObj.inv[%mine] = -1; } else if(%packObj > 0) %packObj.inv[%mine] = -1; } -------------------------------------------------------------------------------------------- Now we're ready to add the mine. Step #1 // ------------------------------------------ // InventoryHud.cs // ------------------------------------------ $InvMine[1] = "Magnetic Air Mine"; $NameToInv["Magnetic Air Mine"] = "MagneticMine"; Step #2 // ------------------------------------------ // Inventory.cs // ------------------------------------------ In function ShapeBase::clearInventory, add this: %this.setInventory(MagneticMine,0); Step #3 // ------------------------------------------ // Player.cs // ------------------------------------------ In each of the player datablocks, add this: max[MagneticMine] = 3; Step #4 // ------------------------------------------ // Weapons.cs // ------------------------------------------ Add this: exec("scripts/weapons/MagneticMine.cs"); Step #5 // ------------------------------------------ // DefaultGame.cs // ------------------------------------------ In Function DefaultGame::clearDeployableMaxes, add this: $TeamDeployedCount[%i, MagneticMineDeployed] = 0; Step #6 // ------------------------------------------ // AmmoPack.cs // ------------------------------------------ In the ammoPack datablock, add this: max[MagneticMine] = 5; Step #7 // ------------------------------------------ // MagneticMine.cs // ------------------------------------------ Finially, create a file in the scripts/weapons directory called MagneticMine.cs and add all this to it: $TeamDeployableMax[MagneticMineDeployed] = 20; datablock ItemData(MagneticMineThrown) { className = Weapon; shapeFile = "mine.dts"; mass = 0.225; 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 = 10.0; proximity = 2.5; armTime = 2200; maxDepCount = 9; computeCRC = true; sticky = true; }; datablock StaticShapeData(MagneticMineDeployed) { className = Weapon; shapeFile = "mine.dts"; mass = 0.15; 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 = 10.0; proximity = 40; armTime = 2200; maxDepCount = 9; computeCRC = true; sticky = true; }; datablock ItemData(MagneticMine) { className = HandInventory; catagory = "Handheld"; shapeFile = "ammo_mine.dts"; mass = 1; elasticity = 0.2; friction = 0.7; pickupRadius = 2; thrownItem = MagneticMineThrown; pickUpName = "some magnetic air mines"; computeCRC = true; }; datablock SeekerProjectileData(MagneticMineMissile) { projectileShapeName = "mine.dts"; hasDamageRadius = true; indirectDamage = 0.4; damageRadius = 6.0; radiusDamageType = $DamageType::Mine; kickBackStrength = 1500; explosion = "MineExplosion"; velInheritFactor = 0.0; lifetimeMS = 8000; muzzleVelocity = 0.0; maxVelocity = 85.0; turningSpeed = 110.0; acceleration = 75.0; proximityRadius = 2.5; terrainAvoidanceSpeed = 180; terrainScanAhead = 25; terrainHeightFail = 12; terrainAvoidanceRadius = 100; hasLight = false; explodeOnWaterImpact = false; }; function MagenticMineGoAfterTarget(%mine, %target) { if (!isObject(%mine)) return; if (!isObject(%target)) explodeMine(%mine, true); else { %pos = posFromTransform(%mine.getTransform()); %pos2 = posFromTransform(%target.getTransform()); %vec = VectorSub(%pos2, %pos); %vec = vectorNormalize(%vec); $TeamDeployedCount[%mine.sourceObject.team, MagneticMineDeployed]--; %mine.schedule(50, delete); if (isObject(%mine.sourceObject)) %source = %mine.sourceObject; else if(isObject(%mine.theClient.player)) %source = %mine.theClient.player; else %source = 0; %p = new SeekerProjectile() { dataBlock = MagneticMineMissile; initialDirection = %vec; initialPosition = %pos; sourceObject = %source; sourceSlot = %slot; vehicleObject = %vehicle; }; MissionCleanup.add(%p); %p.setObjectTarget(%target); } } function MagneticMineThrown::onThrow(%this, %mine, %thrower) { %mine.armed = false; %mine.damaged = 0; %mine.detonated = false; %mine.depCount = 0; %mine.theClient = %thrower.client; schedule(1500, %mine, "deployMagneticMineCheck", %mine, %thrower); } function MagneticMineThrown::onStickyCollision(%data, %mine) { explodeMine(%mine, true); } function MagneticMineThrown::onCollision(%data, %mine) { explodeMine(%mine, true); } function deployMagneticMineCheck(%mineObj2, %player) { if (!isObject(%mineObj2)) return; if(%mineObj2.depCount > MineDeployed.maxDepCount) explodeMine(%mineObj2, true); if(%mineObj2.getVelocity() $= "0 0 0") explodeMine(%mineObj2, true); else { %mineObj = new StaticShape() { dataBlock = MagneticMineDeployed; sourceObject = %player; armed = false; damaged = 0; detonated = false; depCount = 0; team = %player.team; theClient = %player.client; }; %trans = %mineObj2.getTransform(); %mineObj2.schedule(1, delete); %mineObj.setTransform(%trans); InitContainerRadiusSearch(%mineObj.getWorldBoxCenter(), %mineObj.getDatablock().spacing, $TypeMasks::StaticShapeObjectType); while((%itemObj = containerSearchNext()) != 0) { if(%itemObj == %mineObj) continue; %ioType = %itemObj.getDatablock().getName(); if(%ioType $= "MagneticMineDeployed" || %ioType $= "MineDeployed") schedule(100, %mineObj, "explodeMine", %mineObj, true); else continue; } serverPlay3D(MineDeploySound, %mineObj.getTransform()); %mineTeam = %mineObj.sourceObject.team; $TeamDeployedCount[%mineTeam, MagneticMineDeployed]++; if($TeamDeployedCount[%mineTeam, MagneticMineDeployed] > $TeamDeployableMax[MagneticMineDeployed]) { messageClient( %player.client, '', 'Maximum allowable magnetic mines deployed.' ); schedule(100, %mineObj, "explodeMine", %mineObj, true); } else { MagneticMineCheckVicinity(%mineObj); AIDeployMine(%mineObj); Game.notifyMineDeployed(%mineObj); } } } function MagneticMineCheckVicinity(%mine) { if(!%mine.boom) { %mineLoc = %mine.getWorldBoxCenter(); %masks = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType; %detonateRange = %mine.getDatablock().proximity; InitContainerRadiusSearch(%mineLoc, %detonateRange, %masks); while((%tgt = containerSearchNext()) != 0) { if (%tgt.team != %mine.team) { %mine.detonated = true; schedule(50, %mine, "MagenticMineGoAfterTarget", %mine, %tgt); break; } } } if(!%mine.detonated) schedule(300, %mine, "MagneticMineCheckVicinity", %mine); } //Need's to be damaged- Added in function MagneticMineDeployed::damageObject(%data, %targetObject, %sourceObject, %position, %amount, %damageType) { if(%targetObject.boom) return; %targetObject.damaged += %amount; if(%targetObject.damaged >= %data.maxDamage) %targetObject.setDamageState(Destroyed); } //End Needing Damage coded- Add in -End function MagneticMineDeployed::onCollision(%data, %obj, %col) { if(%obj.boom) return; %struck = %col.getClassName(); explodeMine(%obj, false); } function MagneticMineDeployed::onDestroyed(%data, %obj, %lastState) { %obj.boom = true; %mineTeam = %obj.team; $TeamDeployedCount[%mineTeam, MagneticMineDeployed]--; if(!%obj.noDamage) RadiusExplosion(%obj, %obj.getPosition(), %data.damageRadius, %data.indirectDamage, %data.kickBackStrength, %obj.sourceObject, %data.radiusDamageType); %obj.schedule(600, "delete"); } function MagneticMineThrown::onDestroyed(%data, %obj, %lastState) { %obj.boom = true; %mineTeam = %obj.team; RadiusExplosion(%obj, %obj.getPosition(), %data.damageRadius, %data.indirectDamage, %data.kickBackStrength, %obj.sourceObject, %data.radiusDamageType); %obj.schedule(600, "delete"); }