--------------------------------------------------------------------------------------------------------------- Deployable Bunker Tutorial --------------------------------------------------------------------------------------------------------------- This tutorial makes a deployable bunker that has 3 walls, a floor, and ceiling (made with a lot of blastwalls). On the backside wall is a team slow forcefield. On top is a turret base pre-loaded with a missile barrel. And inside is a full sized inventory station. When any of the walls, floor or ceiling get's destroyed, the whole bunker get's destroyed (note: no explosions on destruction have been added, you may want to add them yourself). The bunker will block most outside explosions from damaging people inside. There's an alternate bunker which has all forcefields for walls listed in Step #7 alternate. Also, there's optional code which would allow you to deploy other deployables on/in the bunker at the bottom. Step #1 // ------------------------------------------ // defaultGame.cs // ------------------------------------------ function DefaultGame::clearDeployableMaxes(%game) { $TeamDeployedCount[%i, BunkerDeployable] = 0; } Step #2 // ------------------------------------------ // projectile.cs // ------------------------------------------ This part makes the walls of the bunker prevent people and the inventory inside from taking damage from explosions outside. In function RadiusExplosion, find: if (%coverage == 0) continue; and make it if (%coverage == 1) %coverage = calcBunkerInWay(%position, %targetObject); if (%coverage == 0) continue; Step #3 // ------------------------------------------ // inventoryHud.cs // ------------------------------------------ Add this near the top of the file: $InvPack[19] = "Bunker"; $NameToInv["Bunker"] = "BunkerDeployable"; Step #4 // ------------------------------------------ // pack.cs // ------------------------------------------ exec("scripts/packs/Bunker.cs"); Step #5 // ------------------------------------------ // player.cs // ------------------------------------------ In each player datablock add this. Due to it's size, you may want to give it only to heavies. max[BunkerDeployable] = 1; Step #6 // ------------------------------------------ // deployables.cs // ------------------------------------------ Near the top of the file add this: $TeamDeployableMax[BunkerDeployable] = 3; Step #7 // ------------------------------------------ // Bunker.cs // ------------------------------------------ This creates the bunker that uses blastwalls for all walls, floor, and ceiling. Add all this into a file called Bunker.cs in your packs directory: //-------------------------------------------------------------------------- // Large Bunker // // //-------------------------------------------------------------------------- datablock StaticShapeData(DeployedBunker) : StaticShapeDamageProfile { className = Bunker; shapeFile = "Pmiscf.dts"; // dmiscf.dts, alternate maxDamage = 40.0; destroyedLevel = 40.0; disabledLevel = 30.0; dynamicType = $TypeMasks::StaticShapeObjectType; deployedObject = true; cmdCategory = "DSupport"; cmdIcon = CMDSensorIcon; cmdMiniIconName = "commander/MiniIcons/com_deploymotionsensor"; targetNameTag = 'Large'; targetTypeTag = 'Bunker'; deployAmbientThread = true; heatSignature = 0; damageEmitter[0] = LightDamageSmoke; damageEmitter[1] = HeavyDamageSmoke; damageEmitterOffset[0] = "1.0 1.0 1.0 "; damageLevelTolerance[0] = 2.0; damageLevelTolerance[1] = 5.0; numDmgEmitterAreas = 1; }; datablock StaticShapeData(DeployedBunker2) : StaticShapeDamageProfile { className = Bunker; shapeFile = "Pmiscf.dts"; // dmiscf.dts, alternate maxDamage = 40.0; destroyedLevel = 40.0; disabledLevel = 30.0; dynamicType = $TypeMasks::StaticShapeObjectType; deployedObject = true; targetNameTag = 'Large'; targetTypeTag = 'Bunker'; deployAmbientThread = true; heatSignature = 0; damageEmitter[0] = LightDamageSmoke; damageEmitter[1] = HeavyDamageSmoke; damageEmitterOffset[0] = "1.0 1.0 1.0 "; damageLevelTolerance[0] = 2.0; damageLevelTolerance[1] = 5.0; numDmgEmitterAreas = 1; }; datablock ShapeBaseImageData(BunkerDeployableImage) { mass = 20; emap = true; shapeFile = "Stackable1s.dts"; item = BunkerDeployable; mountPoint = 1; offset = "0 0 0"; deployed = DeployedBunker; heatSignature = 0; stateName[0] = "Idle"; stateTransitionOnTriggerDown[0] = "Activate"; stateName[1] = "Activate"; stateScript[1] = "onActivate"; stateTransitionOnTriggerUp[1] = "Idle"; isLarge = true; maxDepSlope = 360; // 30 deploySound = ItemPickupSound; minDeployDis = 0.5; maxDeployDis = 5.0; }; datablock ItemData(BunkerDeployable) { className = Pack; catagory = "Deployables"; shapeFile = "Stackable1s.dts"; mass = 5.0; elasticity = 0.2; friction = 0.6; pickupRadius = 1; rotate = true; image = "BunkerDeployableImage"; pickUpName = "a large bunker"; heatSignature = 0; emap = true; }; datablock ForceFieldBareData(BunkerForceField) : StaticShapeDamageProfile { fadeMS = 1000; baseTranslucency = 0.5; powerOffTranslucency = 0.0; teamPermiable = true; otherPermiable = false; color = "0.0 0.7 0.99"; powerOffColor = "0.0 0.0 0.0"; cmdIcon = CMDSwitchIcon; cmdCategory = "DSupport"; cmdMiniIconName = "commander/MiniIcons/com_switch_grey"; targetNameTag = 'Deployed'; targetTypeTag = 'ForceField'; texture[0] = "skins/forcef1"; texture[1] = "skins/forcef2"; texture[2] = "skins/forcef3"; texture[3] = "skins/forcef4"; texture[4] = "skins/forcef5"; framesPerSec = 10; numFrames = 5; scrollSpeed = 15; umapping = 1.0; vmapping = 0.15; }; function BunkerDeployable::onPickup(%this, %obj, %shape, %amount) { // created to prevent console errors } function BunkerDeployableImage::onDeploy(%item, %plyr, %slot) { %plyr.unmountImage(%slot); %plyr.decInventory(%item.item, 1); %rot = %item.getInitialRotation(%plyr); %vec = %plyr.getEyeVector(); %vec = getWord(%vec, 0) SPC getWord(%vec, 1) SPC "0"; %classname = "StaticShape"; %d2 = -1 * getWord(%rot, 2) * getWord(%rot, 3); %rot2 = "0 1.57 " @ %d2 + 1.57; %mat = MatrixCreateFromEuler(%rot2); %pointone = VectorAdd(%item.surfacePt, VectorScale(%vec, 7.5)); %rot2 = "0 1.57 " @ %d2; %mat2 = MatrixCreateFromEuler(%rot2); %x2 = getWord(%vec, 0); %y2 = getWord(%vec, 1); %vec2 = %y2 SPC %x2 * -1 SPC "0"; %pointtwo = VectorAdd(%item.surfacePt, VectorScale(%vec2, 7.5)); %rot2 = "0 1.57 " @ %d2 + 3.14; %mat3 = MatrixCreateFromEuler(%rot2); %vec3 = %y2 * -1 SPC %x2 SPC "0"; %pointthree = VectorAdd(%item.surfacePt, VectorScale(%vec3, 7.5)); %rot2 = "0 0 " @ %d2; %mat4 = MatrixCreateFromEuler(%rot2); %x2 = getWord(%vec, 0); %y2 = getWord(%vec, 1); %vec4 = "0 0 6.6"; %pointfour = VectorAdd(%item.surfacePt, %vec4); %vec5 = "0 0 7.1"; %pointfive = VectorAdd(%item.surfacePt, %vec5); %pointsix = VectorAdd(%item.surfacePt, VectorScale(%vec, -7.5)); %pointseven = VectorAdd(%item.surfacePt, VectorScale(%vec, 4.5)); %pointseven = VectorAdd(%pointseven, "0 0 0.5"); %fieldpos = VectorAdd(%pointthree, VectorScale(%vec, -7.4)); %width = VectorDist(%pointthree, %pointtwo); %length = VectorDist(%pointone, %pointsix); %height = VectorDist(%item.surfacePt, %pointfour); %deplObj = new (%className)() //Front Wall { dataBlock = %item.deployed; scale = %height / 3.6 SPC %width / 2.95 SPC "1"; }; %deplObj2 = new (%className)() //Right Wall { dataBlock = DeployedBunker2; scale = %height / 3.6 SPC %length / 2.95 SPC "1"; }; %deplObj3 = new (%className)() //Left Wall { dataBlock = DeployedBunker2; scale = %height / 3.6 SPC %length / 2.95 SPC "1"; }; %deplObj4 = new (%className)() //Ceiling { dataBlock = DeployedBunker2; scale = %width / 3.7 SPC %length / 2.95 SPC "1"; }; %deplObj5 = new (%className)() //Floor { dataBlock = DeployedBunker2; scale = %width / 3.7 SPC %length / 2.95 SPC "1"; }; %deplObj6 = new Turret() //TurretBase { dataBlock = TurretBaseLarge; }; %x1 = getWord(%vec, 0); %y1 = getWord(%vec, 1); if ((%x1 > 0) && (%y1 >= 0)) { %zone = 0; %rad = mAtan(%x1, %y1); } else if((%x1 >= 0) && (%y1 < 0)) { %zone = 1; %y1 *= -1; %rad = mAtan(%y1, %x1); } else if((%x1 < 0) && (%y1 <= 0)) { %zone = 2; %y1 *= -1; %x1 *= -1; %rad = mAtan(%x1, %y1); } else if((%x1 <= 0) && (%y1 > 0)) { %zone = 3; %x1 *= -1; %rad = mAtan(%y1, %x1); } %angle = mRadtoDeg(%rad); if (%zone == 1) %angle += 90; else if (%zone == 2) %angle += 180; else if (%zone == 3) %angle += 270; %fieldrot = " 0 0 1 " @ %angle; %deplObj.setTransform(VectorAdd(%pointone, "0 0 3.5") SPC getWord(%mat, 3) SPC getWord(%mat, 4) SPC GetWord(%mat, 5) SPC getWord(%mat, 6)); %deplObj2.setTransform(VectorAdd(%pointtwo, "0 0 3.5") SPC getWord(%mat2, 3) SPC getWord(%mat2, 4) SPC GetWord(%mat2, 5) SPC getWord(%mat2, 6)); %deplObj3.setTransform(VectorAdd(%pointthree, "0 0 3.5") SPC getWord(%mat3, 3) SPC getWord(%mat3, 4) SPC GetWord(%mat3, 5) SPC getWord(%mat3, 6)); %deplObj4.setTransform(%pointfour SPC getWord(%mat4, 3) SPC getWord(%mat4, 4) SPC GetWord(%mat4, 5) SPC getWord(%mat4, 6)); %deplObj5.setTransform(%item.surfacePt SPC getWord(%mat4, 3) SPC getWord(%mat4, 4) SPC GetWord(%mat4, 5) SPC getWord(%mat4, 6)); %deplObj6.setTransform(%pointfive SPC %rot); %deplObj7 = new (%className)() //Inventory Station { dataBlock = StationInventory; position = %pointseven; rotation = %fieldrot; }; %deplObj.field = new ForceFieldBare() //ForceField { position = %fieldpos; rotation = %fieldrot; scale = %width @ " 0.02 6.6"; dataBlock = "BunkerForceField"; owner = %deplObj; team = %plyr.team; }; %deplObj.field.active = true; %deplObj6.mountImage(MissileBarrelLarge, 0, false); %deplObj6.setSelfPowered(); %deplObj6.playThread($PowerThread,"Power"); %deplObj7.setSelfPowered(); %deplObj7.playThread($PowerThread,"Power"); MissionCleanup.add(%deplObj.field); %deplObj.team = %plyr.client.Team; %deplObj.owner = %plyr.client; %deplObj2.team = %plyr.client.Team; %deplObj2.owner = %plyr.client; %deplObj3.team = %plyr.client.Team; %deplObj3.owner = %plyr.client; %deplObj4.team = %plyr.client.Team; %deplObj4.owner = %plyr.client; %deplObj5.team = %plyr.client.Team; %deplObj5.owner = %plyr.client; %deplObj6.team = %plyr.client.Team; %deplObj6.owner = %plyr.client; %deplObj7.team = %plyr.client.Team; %deplObj7.owner = %plyr.client; %deplObj.field.team = %plyr.client.Team; %deplObj.field.pzone.team = %plyr.client.Team; // set the sensor group if it needs one if(%deplObj.getTarget() != -1) setTargetSensorGroup(%deplObj.getTarget(), %plyr.client.team); if(%deplObj2.getTarget() != -1) setTargetSensorGroup(%deplObj2.getTarget(), %plyr.client.team); if(%deplObj3.getTarget() != -1) setTargetSensorGroup(%deplObj3.getTarget(), %plyr.client.team); if(%deplObj4.getTarget() != -1) setTargetSensorGroup(%deplObj4.getTarget(), %plyr.client.team); if(%deplObj5.getTarget() != -1) setTargetSensorGroup(%deplObj5.getTarget(), %plyr.client.team); if(%deplObj6.getTarget() != -1) setTargetSensorGroup(%deplObj6.getTarget(), %plyr.client.team); if(%deplObj7.getTarget() != -1) setTargetSensorGroup(%deplObj7.getTarget(), %plyr.client.team); if(%deplObj.field.getTarget() != -1) setTargetSensorGroup(%deplObj.field.getTarget(), %plyr.client.team); // place the deployable in the MissionCleanup/Deployables group (AI reasons) addToDeployGroup(%deplObj); addToDeployGroup(%deplObj2); addToDeployGroup(%deplObj3); addToDeployGroup(%deplObj4); addToDeployGroup(%deplObj5); addToDeployGroup(%deplObj6); addToDeployGroup(%deplObj7); //let the AI know as well... AIDeployObject(%plyr.client, %deplObj); AIDeployObject(%plyr.client, %deplObj2); AIDeployObject(%plyr.client, %deplObj3); AIDeployObject(%plyr.client, %deplObj4); AIDeployObject(%plyr.client, %deplObj5); AIDeployObject(%plyr.client, %deplObj6); AIDeployObject(%plyr.client, %deplObj7); //Associate all the bunker parts together for damage/repair purposes. %deplObj.mainbunker = 1; %deplObj2.mainbunker = 0; %deplObj3.mainbunker = 0; %deplObj4.mainbunker = 0; %deplObj5.mainbunker = 0; %deplObj6.mainbunker = 0; %deplObj.right = %deplObj2; %deplObj.left = %deplObj3; %deplObj.top = %deplObj4; %deplObj.bottom = %deplObj5; %deplObj.baseturret = %deplObj6; %deplObj.inventoryst = %deplObj7; %deplObj2.parentbunker = %deplObj; %deplObj3.parentbunker = %deplObj; %deplObj4.parentbunker = %deplObj; %deplObj5.parentbunker = %deplObj; %deplObj6.parentbunker = %deplObj; // play the deploy sound serverPlay3D(%item.deploySound, %deplObj.getTransform()); // increment the team count for this deployed object $TeamDeployedCount[%plyr.team, %item.item]++; %deplObj.deploy(); echo (%deplObj); return %deplObj; } function BunkerForceField::onAdd(%data, %obj) { Parent::onAdd(%data, %obj); for (%i=0; %i < PZones.getCount(); %i++) { if (PZones.getObject(%i).ffield == %obj) %obj.pzone = PZones.getObject(%i); } } function DeployedBunker::onDestroyed(%this, %obj, %prevState) { Parent::onDestroyed(%this, %obj, %prevState); $TeamDeployedCount[%obj.team, BunkerDeployable]--; %obj.right.schedule(500, "delete"); %obj.left.schedule(500, "delete"); %obj.top.schedule(500, "delete"); %obj.bottom.schedule(500, "delete"); %obj.field.pzone.schedule(490, "delete"); %obj.field.schedule(500, "delete"); %obj.baseturret.schedule(500, "delete"); %obj.inventoryst.trigger.schedule(490, "delete"); %obj.inventoryst.schedule(500, "delete"); %obj.schedule(510, "delete"); } function DeployedBunker2::onDestroyed(%this, %obj, %prevState) { Parent::onDestroyed(%this, %obj, %prevState); $TeamDeployedCount[%obj.team, BunkerDeployable]--; %obj2 = %obj.parentbunker; %obj2.right.schedule(500, "delete"); %obj2.left.schedule(500, "delete"); %obj2.top.schedule(500, "delete"); %obj2.bottom.schedule(500, "delete"); %obj2.field.pzone.schedule(490, "delete"); %obj2.field.schedule(500, "delete"); %obj2.baseturret.schedule(500, "delete"); %obj2.inventoryst.trigger.schedule(490, "delete"); %obj2.inventoryst.schedule(500, "delete"); %obj2.schedule(510, "delete"); } function BunkerDeployableImage::testObjectTooClose(%item) { %mask = ($TypeMasks::VehicleObjectType | $TypeMasks::MoveableObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType | $TypeMasks::TurretObjectType | $TypeMasks::InteriorObjectType); InitContainerRadiusSearch( %item.surfacePt, 20, %mask ); %test = containerSearchNext(); if(!%test) { InitContainerRadiusSearch( %item.surfacePt, 20, $TypeMasks::PlayerObjectType ); %test = containerSearchNext(); if (%test) %test = containerSearchNext(); } return %test; } function BunkerDeployableImage::testNoTerrainFound(%item) { return %item.surface.getClassName() !$= TerrainBlock; } function calcBunkerInWay(%position, %targetObject) { %mask = $TypeMasks::StaticObjectType; %found = containerRayCast(%position, posFromTransform(%targetObject.getTransform()), %mask); if (%found) { if ((%found.getClassName() $= InteriorInstance) || (%found.getClassName() $= TerrainBlock) || (%found.getClassName() $= TSStatic)) return 1; if (%found == %targetObject) return 1; if (%found.getDataBlock().className $= "Bunker" || %found.getDataBlock().className $= "Wall") return 0; else { %found = containerRayCast(%position, posFromTransform(%targetObject.getTransform()), %mask, %found); if (%found) { if ((%found.getClassName() $= InteriorInstance) || (%found.getClassName() $= TerrainBlock) || (%found.getClassName() $= TSStatic)) return 1; if (%found == %targetObject) return 1; if (%found.getDataBlock().className $= "Bunker" || %found.getDataBlock().className $= "Wall") return 0; } } } return 1; } |----------------------------------------------------------------------------------------------| |==============================================================================================| |----------------------------------------------------------------------------------------------| Step #7 Alternate // ------------------------------------------ // Bunker.cs // ------------------------------------------ This is an alternate bunker. It still uses blastfloors for the floor and ceiling. But, all walls are Forcefields. Add all this into a file called Bunker.cs in your packs directory (replace everything from Step #7 with this): //-------------------------------------------------------------------------- // Large Bunker #2 // // All walls are forcefields. Floor/Ceiling Blastfloors. Turret on top. Inventory inside. //-------------------------------------------------------------------------- datablock StaticShapeData(DeployedBunker) : StaticShapeDamageProfile { className = Bunker; shapeFile = "Pmiscf.dts"; // dmiscf.dts, alternate maxDamage = 40.0; destroyedLevel = 40.0; disabledLevel = 30.0; dynamicType = $TypeMasks::StaticShapeObjectType; deployedObject = true; cmdCategory = "DSupport"; cmdIcon = CMDSensorIcon; cmdMiniIconName = "commander/MiniIcons/com_deploymotionsensor"; targetNameTag = 'Large'; targetTypeTag = 'Bunker'; deployAmbientThread = true; heatSignature = 0; damageEmitter[0] = LightDamageSmoke; damageEmitter[1] = HeavyDamageSmoke; damageEmitterOffset[0] = "1.0 1.0 1.0 "; damageLevelTolerance[0] = 2.0; damageLevelTolerance[1] = 5.0; numDmgEmitterAreas = 1; }; datablock StaticShapeData(DeployedBunker2) : StaticShapeDamageProfile { className = Bunker; shapeFile = "Pmiscf.dts"; // dmiscf.dts, alternate maxDamage = 40.0; destroyedLevel = 40.0; disabledLevel = 30.0; dynamicType = $TypeMasks::StaticShapeObjectType; deployedObject = true; targetNameTag = 'Large'; targetTypeTag = 'Bunker'; deployAmbientThread = true; heatSignature = 0; damageEmitter[0] = LightDamageSmoke; damageEmitter[1] = HeavyDamageSmoke; damageEmitterOffset[0] = "1.0 1.0 1.0 "; damageLevelTolerance[0] = 2.0; damageLevelTolerance[1] = 5.0; numDmgEmitterAreas = 1; }; datablock ShapeBaseImageData(BunkerDeployableImage) { mass = 20; emap = true; shapeFile = "Stackable1s.dts"; item = BunkerDeployable; mountPoint = 1; offset = "0 0 0"; deployed = DeployedBunker; heatSignature = 0; stateName[0] = "Idle"; stateTransitionOnTriggerDown[0] = "Activate"; stateName[1] = "Activate"; stateScript[1] = "onActivate"; stateTransitionOnTriggerUp[1] = "Idle"; isLarge = true; maxDepSlope = 360; // 30 deploySound = ItemPickupSound; minDeployDis = 0.5; maxDeployDis = 5.0; }; datablock ItemData(BunkerDeployable) { className = Pack; catagory = "Deployables"; shapeFile = "Stackable1s.dts"; mass = 5.0; elasticity = 0.2; friction = 0.6; pickupRadius = 1; rotate = true; image = "BunkerDeployableImage"; pickUpName = "a large bunker"; heatSignature = 0; emap = true; }; datablock ForceFieldBareData(BunkerWallField) : StaticShapeDamageProfile { fadeMS = 1000; baseTranslucency = 0.5; powerOffTranslucency = 0.0; teamPermiable = true; otherPermiable = false; color = "0.0 0.7 0.99"; powerOffColor = "0.0 0.0 0.0"; cmdIcon = CMDSwitchIcon; cmdCategory = "DSupport"; cmdMiniIconName = "commander/MiniIcons/com_switch_grey"; targetNameTag = 'Deployed'; targetTypeTag = 'ForceField'; texture[0] = "skins/forcef1"; texture[1] = "skins/forcef2"; texture[2] = "skins/forcef3"; texture[3] = "skins/forcef4"; texture[4] = "skins/forcef5"; framesPerSec = 10; numFrames = 5; scrollSpeed = 15; umapping = 1.0; vmapping = 0.15; }; function BunkerDeployable::onPickup(%this, %obj, %shape, %amount) { // created to prevent console errors } function BunkerDeployableImage::onDeploy(%item, %plyr, %slot) { %plyr.unmountImage(%slot); %plyr.decInventory(%item.item, 1); %rot = %item.getInitialRotation(%plyr); %vec = %plyr.getEyeVector(); %vec = getWord(%vec, 0) SPC getWord(%vec, 1) SPC "0"; %x2 = getWord(%vec, 0); %y2 = getWord(%vec, 1); %vec2 = %y2 SPC %x2 * -1 SPC "0"; %vec3 = %y2 * -1 SPC %x2 SPC "0"; %classname = "StaticShape"; %d2 = -1 * getWord(%rot, 2) * getWord(%rot, 3); %rot2 = "0 0 " @ %d2; %mat4 = MatrixCreateFromEuler(%rot2); %pointone = VectorAdd(%item.surfacePt, VectorScale(%vec, 10)); %pointone = VectorAdd(%pointone, VectorScale(%vec3, 10)); //Bottom Front Right %pointtwo = VectorAdd(%item.surfacePt, VectorScale(%vec2, 10)); %pointtwo = VectorAdd(%pointtwo, VectorScale(%vec, -10)); //Bottom Back Left %pointthree = VectorAdd(%pointtwo, "0 0 7.5"); //Top Back Left %pointthree = VectorAdd(%pointthree, VectorScale(%vec, 20)); //Top Front Left %pointfour = VectorAdd(%item.surfacePt, "0 0 8"); //Turret Point %pointfive = VectorAdd(%item.surfacePt, VectorScale(%vec, 5)); %pointfive = VectorAdd(%pointfive, "0 0 0.5"); //Inventory Point %pointsix = VectorAdd(%item.surfacePt, VectorScale(%vec, -10)); %pointsix = VectorAdd(%pointsix, "0 0 3.75"); //Parent Point %pointseven = VectorAdd(%pointthree, "0 0 -7.5"); //Bottom Front Left %pointeight = VectorAdd(%item.surfacePt, "0 0 7.5"); //Middle Top Ceiling %length = VectorDist(%pointseven, %pointtwo); %width = VectorDist(%pointseven, %pointone); %x1 = getWord(%vec, 0); %y1 = getWord(%vec, 1); if ((%x1 > 0) && (%y1 >= 0)) { %zone = 0; %rad = mAtan(%x1, %y1); } else if((%x1 >= 0) && (%y1 < 0)) { %zone = 1; %y1 *= -1; %rad = mAtan(%y1, %x1); } else if((%x1 < 0) && (%y1 <= 0)) { %zone = 2; %y1 *= -1; %x1 *= -1; %rad = mAtan(%x1, %y1); } else if((%x1 <= 0) && (%y1 > 0)) { %zone = 3; %x1 *= -1; %rad = mAtan(%y1, %x1); } %angle = mRadtoDeg(%rad); if (%zone == 1) %angle += 90; else if (%zone == 2) %angle += 180; else if (%zone == 3) %angle += 270; %fieldrot = "0 0 1 " @ %angle; %angle = %angle - 180; if (%angle < 0) %angle = %angle + 360; %fieldrot2 = "0 0 1 " @ %angle; %angle = %angle - 90; if (%angle < 0) %angle = %angle + 360; %fieldrot3 = "0 0 1 " @ %angle; %angle = %angle - 180; if (%angle < 0) %angle = %angle + 360; %fieldrot4 = "0 0 1 " @ %angle; %deplObj = new (%className)() //Ceiling { dataBlock = DeployedBunker; scale = %width / 3.7 SPC %length / 2.8 SPC "1"; }; %deplObj2 = new ForceFieldBare() //Front Wall { dataBlock = BunkerWallField; scale = %width SPC "0.02 7.5"; position = %pointone; rotation = %fieldrot; owner = %deplObj; team = %plyr.team; }; %deplObj3 = new ForceFieldBare() //Right Wall { dataBlock = BunkerWallField; scale = %length SPC "0.02 7.5"; position = %pointone; rotation = %fieldrot3; owner = %deplObj; team = %plyr.team; }; %deplObj4 = new ForceFieldBare() //Left Wall { dataBlock = BunkerWallField; scale = %length SPC "0.02 7.5"; position = %pointtwo; rotation = %fieldrot4; owner = %deplObj; team = %plyr.team; }; %deplObj5 = new ForceFieldBare() //BackWall { position = %pointtwo; rotation = %fieldrot2; scale = %width SPC "0.02 7.5"; dataBlock = "BunkerWallField"; owner = %deplObj; team = %plyr.team; }; %deplObj6 = new (%className)() //Floor { dataBlock = DeployedBunker2; scale = %width / 3.7 SPC %length / 2.8 SPC "1"; }; %deplObj7 = new Turret() //TurretBase { dataBlock = TurretBaseLarge; }; %deplObj.setTransform(%pointeight SPC getWords(%mat4, 3, 6)); %deplObj6.setTransform(%item.surfacePt SPC getWords(%mat4, 3, 6)); %deplObj7.setTransform(%pointfour SPC %rot); %deplObj8 = new (%className)() //Inventory Station { dataBlock = StationInventory; position = %pointfive; rotation = %fieldrot; }; %deplObj2.active = true; %deplObj3.active = true; %deplObj4.active = true; %deplObj5.active = true; %deplObj2.setSelfPowered(); %deplObj3.setSelfPowered(); %deplObj4.setSelfPowered(); %deplObj5.setSelfPowered(); %deplObj7.mountImage(MissileBarrelLarge, 0, false); %deplObj7.setSelfPowered(); %deplObj7.playThread($PowerThread,"Power"); %deplObj8.setSelfPowered(); %deplObj8.playThread($PowerThread,"Power"); MissionCleanup.add(%deplObj2); MissionCleanup.add(%deplObj3); MissionCleanup.add(%deplObj4); MissionCleanup.add(%deplObj5); %deplObj.team = %plyr.client.Team; %deplObj.owner = %plyr.client; %deplObj2.team = %plyr.client.Team; %deplObj2.pzone.team = %plyr.client.Team; %deplObj3.team = %plyr.client.Team; %deplObj3.pzone.team = %plyr.client.Team; %deplObj4.team = %plyr.client.Team; %deplObj4.pzone.team = %plyr.client.Team; %deplObj5.team = %plyr.client.Team; %deplObj5.pzone.team = %plyr.client.Team; %deplObj6.team = %plyr.client.Team; %deplObj6.owner = %plyr.client; %deplObj7.team = %plyr.client.Team; %deplObj7.owner = %plyr.client; %deplObj8.team = %plyr.client.Team; %deplObj8.owner = %plyr.client; // set the sensor group if it needs one if(%deplObj.getTarget() != -1) setTargetSensorGroup(%deplObj.getTarget(), %plyr.client.team); if(%deplObj2.getTarget() != -1) setTargetSensorGroup(%deplObj2.getTarget(), %plyr.client.team); if(%deplObj3.getTarget() != -1) setTargetSensorGroup(%deplObj3.getTarget(), %plyr.client.team); if(%deplObj4.getTarget() != -1) setTargetSensorGroup(%deplObj4.getTarget(), %plyr.client.team); if(%deplObj5.getTarget() != -1) setTargetSensorGroup(%deplObj5.getTarget(), %plyr.client.team); if(%deplObj6.getTarget() != -1) setTargetSensorGroup(%deplObj6.getTarget(), %plyr.client.team); if(%deplObj7.getTarget() != -1) setTargetSensorGroup(%deplObj7.getTarget(), %plyr.client.team); if(%deplObj8.getTarget() != -1) setTargetSensorGroup(%deplObj8.getTarget(), %plyr.client.team); // place the deployable in the MissionCleanup/Deployables group (AI reasons) addToDeployGroup(%deplObj); addToDeployGroup(%deplObj6); addToDeployGroup(%deplObj7); addToDeployGroup(%deplObj8); //let the AI know as well... AIDeployObject(%plyr.client, %deplObj); AIDeployObject(%plyr.client, %deplObj6); AIDeployObject(%plyr.client, %deplObj7); AIDeployObject(%plyr.client, %deplObj8); //Associate all the bunker parts together for damage/repair purposes. %deplObj.front = %deplObj2; %deplObj.right = %deplObj3; %deplObj.left = %deplObj4; %deplObj.back = %deplObj5; %deplObj.bottom = %deplObj6; %deplObj.baseturret = %deplObj7; %deplObj.inventoryst = %deplObj8; %deplObj2.parentbunker = %deplObj; %deplObj3.parentbunker = %deplObj; %deplObj4.parentbunker = %deplObj; %deplObj5.parentbunker = %deplObj; %deplObj6.parentbunker = %deplObj; // play the deploy sound serverPlay3D(%item.deploySound, %deplObj.getTransform()); // increment the team count for this deployed object $TeamDeployedCount[%plyr.team, %item.item]++; %deplObj.deploy(); return %deplObj; } function BunkerWallField::onAdd(%data, %obj) { Parent::onAdd(%data, %obj); for (%i=0; %i < PZones.getCount(); %i++) { if (PZones.getObject(%i).ffield == %obj) %obj.pzone = PZones.getObject(%i); } } function DeployedBunker::onDestroyed(%this, %obj, %prevState) { Parent::onDestroyed(%this, %obj, %prevState); $TeamDeployedCount[%obj.team, BunkerDeployable]--; %obj.right.pzone.schedule(490, "delete"); %obj.right.schedule(500, "delete"); %obj.left.pzone.schedule(490, "delete"); %obj.left.schedule(500, "delete"); %obj.front.pzone.schedule(490, "delete"); %obj.front.schedule(500, "delete"); %obj.back.pzone.schedule(490, "delete"); %obj.back.schedule(500, "delete"); %obj.bottom.schedule(500, "delete"); %obj.baseturret.schedule(500, "delete"); %obj.inventoryst.trigger.schedule(490, "delete"); %obj.inventoryst.schedule(500, "delete"); %obj.schedule(510, "delete"); } function DeployedBunker2::onDestroyed(%this, %obj, %prevState) { Parent::onDestroyed(%this, %obj, %prevState); $TeamDeployedCount[%obj.team, BunkerDeployable]--; %obj2 = %obj.parentbunker; %obj2.right.pzone.schedule(490, "delete"); %obj2.right.schedule(500, "delete"); %obj2.left.pzone.schedule(490, "delete"); %obj2.left.schedule(500, "delete"); %obj2.front.pzone.schedule(490, "delete"); %obj2.front.schedule(500, "delete"); %obj2.back.pzone.schedule(490, "delete"); %obj2.back.schedule(500, "delete"); %obj2.bottom.schedule(500, "delete"); %obj2.baseturret.schedule(500, "delete"); %obj2.inventoryst.trigger.schedule(490, "delete"); %obj2.inventoryst.schedule(500, "delete"); %obj2.schedule(510, "delete"); } function BunkerDeployableImage::testObjectTooClose(%item) { %mask = ($TypeMasks::VehicleObjectType | $TypeMasks::MoveableObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::ItemObjectType | $TypeMasks::TurretObjectType | $TypeMasks::InteriorObjectType); InitContainerRadiusSearch( %item.surfacePt, 20, %mask ); %test = containerSearchNext(); if(!%test) { InitContainerRadiusSearch( %item.surfacePt, 20, $TypeMasks::PlayerObjectType ); %test = containerSearchNext(); if (%test) %test = containerSearchNext(); } return %test; } function BunkerDeployableImage::testNoTerrainFound(%item) { return %item.surface.getClassName() !$= TerrainBlock; } function calcBunkerInWay(%position, %targetObject) { %mask = $TypeMasks::StaticObjectType; %found = containerRayCast(%position, posFromTransform(%targetObject.getTransform()), %mask); if (%found) { if ((%found.getClassName() $= InteriorInstance) || (%found.getClassName() $= TerrainBlock) || (%found.getClassName() $= TSStatic)) return 1; if (%found == %targetObject) return 1; if (%found.getDataBlock().className $= "Bunker" || %found.getDataBlock().className $= "Wall") return 0; else { %found = containerRayCast(%position, posFromTransform(%targetObject.getTransform()), %mask, %found); if (%found) { if ((%found.getClassName() $= InteriorInstance) || (%found.getClassName() $= TerrainBlock) || (%found.getClassName() $= TSStatic)) return 1; if (%found == %targetObject) return 1; if (%found.getDataBlock().className $= "Bunker" || %found.getDataBlock().className $= "Wall") return 0; } } } return 1; } --------------------------------------------------------------- Optional --------------------------------------------------------------- This will allow other deployables to be placed on/in the bunker. All items placed on the bunker will be destroyed when the bunker is destroyed. Step #8 // ------------------------------------------ // Deployables.cs // ------------------------------------------ 8a) In function Deployables::searchView, change these lines: %searchResult = containerRayCast(%eyePos, %eyeEnd, %mask, 0); return %searchResult; to this: %searchResult = containerRayCast(%eyePos, %eyeEnd, %mask, 0); if (%searchResult) %pos2 = getWords(%searchResult, 1, 3); else %pos2 = %eyeEnd; %searchResult2 = containerRayCast(%eyePos, %pos2, $TypeMasks::StaticShapeObjectType, 0); if (%searchResult2) { if (%searchResult2.getDataBlock().className $= "Bunker") return %searchResult2; } return %searchResult; 8b) In function ShapeBaseImageData::testObjectTooClose, change these lines: %test = containerSearchNext(); return %test; To This: while ((%test = containerSearchNext()) != 0) { if (%test.getType() & $TypeMasks::StaticShapeObjectType) { if (%test.getDataBlock().className !$= "Bunker") return %test; } else return %test; } return 0; 8c) In function ShapeBaseImageData::onDeploy, above this line: return %deplObj; Add This: %deplObj.deployedOnSurface = %item.surface; Step #9 // ------------------------------------------ // Bunker.cs // ------------------------------------------ 9a) In function DeployedBunker::onDestroyed, add this to the bottom of the function: for (%i=0;%i < Deployables.getCount();%i++) { %dep = Deployables.getObject(%i); if (%dep.deployedOnSurface == %obj.top || %dep.deployedOnSurface == %obj.bottom) %dep.setDamageState("Destroyed"); } 9b) In function DeployedBunker2::onDestroyed, add this to the bottom of the function: for (%i=0;%i < Deployables.getCount();%i++) { %dep = Deployables.getObject(%i); if (%dep.deployedOnSurface == %obj2.top || %dep.deployedOnSurface == %obj2.bottom) %dep.setDamageState("Destroyed"); } Extra note, if you're using the bunker that has all forcefields as the wall (Step #7 alternate), chage the two above functions as such. Where it says: %dep.deployedOnSurface == %obj.top and %dep.deployedOnSurface == %obj2.top it should be: %dep.deployedOnSurface == %obj and %dep.deployedOnSurface == %obj2 All this does is remove the .top after %obj and %obj2, since on the second bunker, %obj and %obj2 are the top of the bunker.