//---------------------------------------------------------------------------- // When first mounted (assuming there is ammo): // SingleShot activate -> ready // Spinning activate -> idle (spin 0) // Sustained activate -> ready // DiscLauncher activate -> reload -> spinup -> ready // // Normal operation: // SingleShot ready -> fire -> reload -> ready // Spinning idle (spin 0) -> spinup -> ready -> fire -> spindown -> idle // Sustained ready -> fire -> reload -> ready // DiscLauncher ready -> fire -> reload -> spinup -> ready // Image properties // emap // preload // shapeFile // mountPoint // offset // rotation // firstPerson // mass // usesEnergy // minEnergy // accuFire // lightType // lightTime // lightRadius // lightColor // Image state variables // stateName // stateTransitionOnLoaded // stateTransitionOnNotLoaded // stateTransitionOnAmmo // stateTransitionOnNoAmmo // stateTransitionOnTriggerUp // stateTransitionOnTriggerDown // stateTransitionOnTimeout // stateTimeoutValue // stateFire // stateEnergyDrain // stateAllowImageChange // stateScaleAnimation // stateDirection // stateLoadedFlag // stateSpinThread // stateRecoil // stateSequence // stateSound // stateScript // stateEmitter // stateEmitterTime // stateEmitterNode //---------------------------------------------------------------------------- $ItemRespawnTime = 30000; $ItemPopTime = 30 * 1000; // 30 seconds $WeaponSlot = 0; $AuxiliarySlot = 1; $BackpackSlot = 2; $FlagSlot = 3; //---------------------------------------------------------------------------- datablock EffectProfile(ItemPickupEffect) { effectname = "packs/packs.pickupPack"; minDistance = 2.5; }; datablock AudioProfile(ItemPickupSound) { filename = "fx/packs/packs.pickuppack.wav"; description = AudioClosest3d; effect = ItemPickupEffect; preload = true; }; datablock AudioProfile(ItemThrowSound) { filename = "fx/packs/packs.throwpack.wav"; description = AudioClosest3d; preload = true; }; datablock AudioProfile(RepairPatchSound) { filename = "fx/misc/health_patch.wav"; description = AudioClosest3d; preload = true; effect = ItemPickupEffect; preload = true; }; function ItemData::create(%block) { if(%block $= "flag") %obj = new Item() { className = FlagObj; dataBlock = %block; static = false; rotate = false; }; else %obj = new Item() { dataBlock = %block; static = true; //rotate = true; // don't make "placed items" rotate rotate = false; }; return(%obj); } //-------------------------------------------------------------------------- function Item::schedulePop(%this) { %itemFadeTime = 1000; // items will take 1 second (1000 milliseconds) to fade out %this.startFade(%itemFadeTime, $ItemPopTime - %itemFadeTime, true); %this.schedule($ItemPopTime, "delete"); } function Item::respawn(%this) { %this.startFade(0, 0, true); %this.schedule($ItemRespawnTime + 100, "startFade", 1000, 0, false); %this.hide(true); %this.schedule($ItemRespawnTime, "hide", false); } //-------------------------------------------------------------------------- function ItemData::onThrow(%data,%obj,%shape) { serverPlay3D(ItemThrowSound, %obj.getTransform()); // don't schedule a delete for satchelCharges when they're deployed if(!%data.noTimeout) %obj.schedulePop(); } function ItemData::onInventory(%data,%shape,%value) { if (!%value) { // If we don't have any more of these items, make sure // we don't have an image mounted. %slot = %shape.getMountSlot(%data.image); if (%slot != -1) %shape.unmountImage(%slot); } } function ItemData::onEnterLiquid(%data, %obj, %coverage, %type) { if(%data.isInvincible) return; switch(%type) { case 0: //Water case 1: //Ocean Water case 2: //River Water case 3: //Stagnant Water case 4: //Lava %obj.delete(); case 5: //Hot Lava %obj.delete(); case 6: //Crusty Lava %obj.delete(); case 7: //Quick Sand } } function ItemData::onLeaveLiquid(%data, %obj, %type) { // dummy } function ItemData::onCollision(%data,%obj,%col) { // Default behavior for items is to get picked // by the colliding object. if (%col.getDataBlock().className $= Armor && %col.getState() !$= "Dead") { if (%col.isMounted()) return; if (%col.pickup(%obj, 1)) { if (%col.client) { messageClient(%col.client, 'MsgItemPickup', '\c0You picked up %1.', %data.pickUpName); serverPlay3D(ItemPickupSound, %col.getTransform()); } if (%obj.isStatic()) %obj.respawn(); else %obj.delete(); } } } //---------------------------------------------------------------------------- datablock ItemData(RepairKit) { className = HandInventory; catagory = "Misc"; shapeFile = "repair_kit.dts"; mass = 1; elasticity = 0.2; friction = 0.6; pickupRadius = 2.0; pickUpName = "a repair kit"; alwaysAmbient = true; computeCRC = true; emap = true; }; function RepairKit::onUse(%data,%obj) { // Don't use the kit unless we're damaged if (%obj.getDamageLevel() != 0) { %obj.decInventory(%data,1); %obj.applyRepair(0.2); messageClient(%obj.client, 'MsgRepairKitUsed', '\c2Repair Kit Used.'); } } //---------------------------------------------------------------------------- datablock ItemData(RepairPatch) { catagory = "Misc"; shapeFile = "repair_patch.dts"; mass = 1; elasticity = 0.2; friction = 0.6; pickupRadius = 2.0; pickUpName = "a repair patch"; alwaysAmbient = true; computeCRC = true; emap = true; }; function RepairPatch::onCollision(%data,%obj,%col) { if ( %col.getDataBlock().className $= Armor && %col.getDamageLevel() != 0 && %col.getState() !$= "Dead" ) { if (%col.isMounted()) return; %col.playAudio(0, RepairPatchSound); %col.applyRepair(0.125); %obj.respawn(); if (%col.client > 0) messageClient(%col.client, 'MsgItemPickup', '\c0You picked up %1.', %data.pickUpName); } } //---------------------------------------------------------------------------- // Flag: //---------------------------------------------------------------------------- datablock ShapeBaseImageData(FlagImage) { shapeFile = "flag.dts"; item = Flag; mountPoint = 2; offset = "0 0 0"; lightType = "PulsingLight"; lightColor = "0.5 0.5 0.5 1.0"; lightTime = "1000"; lightRadius = "3"; cloakable = false; }; datablock ItemData(Flag) { catagory = "Objectives"; shapefile = "flag.dts"; mass = 55; elasticity = 0.2; friction = 0.6; pickupRadius = 3; pickUpName = "a flag"; computeCRC = true; lightType = "PulsingLight"; lightColor = "0.5 0.5 0.5 1.0"; lightTime = "1000"; lightRadius = "3"; isInvincible = true; cmdCategory = "Objectives"; cmdIcon = CMDFlagIcon; cmdMiniIconName = "commander/MiniIcons/com_flag_grey"; targetTypeTag = 'Flag'; //used in CTF to mark the flag during a stalemate... hudImageNameFriendly[1] = "commander/MiniIcons/com_flag_grey"; hudImageNameEnemy[1] = "commander/MiniIcons/com_flag_grey"; hudRenderModulated[1] = true; hudRenderAlways[1] = true; hudRenderCenter[1] = true; hudRenderDistance[1] = true; hudRenderName[1] = true; }; //---------------------------------------------------------------------------- function Flag::onThrow(%data,%obj,%src) { Game.playerDroppedFlag(%src); } function Flag::onAdd(%this, %obj) { // make sure flags play "flapping" ambient thread Parent::onAdd(%this, %obj); %obj.playThread($AmbientThread, "ambient"); %blocker = new VehicleBlocker() { position = %obj.position; rotation = %obj.rotation; dimensions = "2 2 4"; }; MissionCleanup.add(%blocker); } function Flag::onCollision(%data,%obj,%col) { if (%col.getDataBlock().className $= Armor) { if (%col.isMounted()) return; // a player hit the flag Game.playerTouchFlag(%col, %obj); } } //---------------------------------------------------------------------------- // HuntersFlag: //---------------------------------------------------------------------------- datablock ShapeBaseImageData(HuntersFlagImage) { shapeFile = "Huntersflag.dts"; item = Flag; mountPoint = 2; offset = "0 0 0"; lightType = "PulsingLight"; lightColor = "0.5 0.5 0.5 1.0"; lightTime = "1000"; lightRadius = "3"; }; // 1: red // 2: blue // 4: yellow // 8: green datablock ItemData(HuntersFlag1) { className = HuntersFlag; shapefile = "Huntersflag.dts"; mass = 75; elasticity = 0.2; friction = 0.6; pickupRadius = 3; isInvincible = true; pickUpName = "a flag"; computeCRC = true; lightType = "PulsingLight"; lightColor = "0.8 0.2 0.2 1.0"; lightTime = "1000"; lightRadius = "3"; }; datablock ItemData(HuntersFlag2) : HuntersFlag1 { lightColor = "0.2 0.2 0.8 1.0"; }; datablock ItemData(HuntersFlag4) : HuntersFlag1 { lightColor = "0.8 0.8 0.2 1.0"; }; datablock ItemData(HuntersFlag8) : HuntersFlag1 { lightColor = "0.2 0.8 0.2 1.0"; }; function HuntersFlag::onRemove(%data, %obj) { // dont want target removed... } function HuntersFlag::onThrow(%data,%obj,%src) { Game.playerDroppedFlag(%src); } function HuntersFlag::onCollision(%data,%obj,%col) { if (%col.getDataBlock().className $= Armor) { if (%col.isMounted()) return; // a player hit the flag Game.playerTouchFlag(%col, %obj); } } //---------------------------------------------------------------------------- // Nexus: //---------------------------------------------------------------------------- datablock ItemData(Nexus) { catagory = "Objectives"; shapefile = "nexus_effect.dts"; mass = 10; elasticity = 0.2; friction = 0.6; pickupRadius = 2; icon = "CMDNexusIcon"; targetTypeTag = 'Nexus'; computeCRC = true; }; datablock ParticleData(NexusParticleDenied) { dragCoeffiecient = 0.4; gravityCoefficient = 3.0; inheritedVelFactor = 0.0; lifetimeMS = 1200; lifetimeVarianceMS = 400; textureName = "particleTest"; useInvAlpha = false; spinRandomMin = -200.0; spinRandomMax = 200.0; colors[0] = "0.3 0.0 0.0 1.0"; colors[1] = "0.5 0.0 0.0 0.5"; colors[2] = "0.7 0.0 0.0 0.0"; sizes[0] = 0.2; sizes[1] = 0.1; sizes[2] = 0.0; times[0] = 0.0; times[1] = 0.5; times[2] = 1.0; }; datablock ParticleEmitterData(NexusParticleDeniedEmitter) { ejectionPeriodMS = 2; ejectionOffset = 0.2; periodVarianceMS = 0.5; ejectionVelocity = 10.0; velocityVariance = 4.0; thetaMin = 0.0; thetaMax = 30.0; lifetimeMS = 0; particles = "NexusParticleDenied"; }; datablock ParticleData(NexusParticleCap) { dragCoeffiecient = 0.4; gravityCoefficient = 3.0; inheritedVelFactor = 0.0; lifetimeMS = 1200; lifetimeVarianceMS = 400; textureName = "particleTest"; useInvAlpha = false; spinRandomMin = -200.0; spinRandomMax = 200.0; colors[0] = "0.5 0.8 0.2 1.0"; colors[1] = "0.6 0.9 0.3 1.0"; colors[2] = "0.7 1.0 0.4 1.0"; sizes[0] = 0.2; sizes[1] = 0.1; sizes[2] = 0.0; times[0] = 0.0; times[1] = 0.5; times[2] = 1.0; }; datablock ParticleEmitterData(NexusParticleCapEmitter) { ejectionPeriodMS = 2; ejectionOffset = 0.5; periodVarianceMS = 0.5; ejectionVelocity = 10.0; velocityVariance = 4.0; thetaMin = 0.0; thetaMax = 30.0; lifetimeMS = 0; particles = "NexusParticleCap"; }; //---------------------------------------------------------------------------- function getVector(%string, %num) { %start = %num * 3; return getWords(%string,%start, %start + 2); } // -------------------------------------------- // explosion datablock // -------------------------------------------- datablock EffectProfile(DeployableExplosionEffect) { effectname = "explosions/explosion.xpl10"; minDistance = 10; maxDistance = 50; }; datablock AudioProfile(DeployablesExplosionSound) { filename = "fx/explosions/deployables_explosion.wav"; description = AudioExplosion3d; preload = true; effect = DeployableExplosionEffect; }; datablock ExplosionData(DeployablesExplosion) { soundProfile = DeployablesExplosionSound; faceViewer = true; explosionShape = "effect_plasma_explosion.dts"; sizes[0] = "0.2 0.2 0.2"; sizes[1] = "0.3 0.3 0.3"; }; $TeamDeployableMax[TargetBeacon] = 10; $TeamDeployableMax[MarkerBeacon] = 20; datablock ItemData(Beacon) { className = HandInventory; catagory = "Misc"; shapeFile = "beacon.dts"; mass = 1; elasticity = 0.2; friction = 0.8; pickupRadius = 1; pickUpName = "a deployable beacon"; computeCRC = true; }; datablock StaticShapeData(DeployedBeacon) : StaticShapeDamageProfile { shapeFile = "beacon.dts"; explosion = DeployablesExplosion; maxDamage = 0.45; disabledLevel = 0.45; destroyedLevel = 0.45; beacon = true; targetNameTag = 'beacon'; deployedObject = true; dynamicType = $TypeMasks::SensorObjectType; debrisShapeName = "debris_generic_small.dts"; debris = SmallShapeDebris; }; function DeployedBeacon::onDestroyed(%data, %obj, %prevState) { if(%obj.isBeaconType(friend)) %bType = "MarkerBeacon"; else %bType = "TargetBeacon"; $TeamDeployedCount[%obj.team, %bType]--; %obj.schedule(500, delete); } function Beacon::onUse(%data, %obj) { // look for 3 meters along player's viewpoint for interior or terrain %searchRange = 3.0; %mask = $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType; // get the eye vector and eye transform of the player %eyeVec = %obj.getEyeVector(); %eyeTrans = %obj.getEyeTransform(); // extract the position of the player's camera from the eye transform (first 3 words) %eyePos = posFromTransform(%eyeTrans); // normalize the eye vector %nEyeVec = VectorNormalize(%eyeVec); // scale (lengthen) the normalized eye vector according to the search range %scEyeVec = VectorScale(%nEyeVec, %searchRange); // add the scaled & normalized eye vector to the position of the camera %eyeEnd = VectorAdd(%eyePos, %scEyeVec); // see if anything gets hit %searchResult = containerRayCast(%eyePos, %eyeEnd, %mask, 0); if(!%searchResult ) { // no terrain/interior collision within search range if(%obj.inv[%data.getName()] > 0) messageClient(%obj.client, 'MsgBeaconNoSurface', '\c2Cannot place beacon. Too far from surface.'); return 0; } else { %searchObj = GetWord(%searchResult, 0); if(%searchObj.getType() & ($TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType) ) { // if there's already a beacon where player is aiming, switch its type // otherwise, player can't deploy a beacon there if(%searchObj.getDataBlock().getName() $= DeployedBeacon) switchBeaconType(%searchObj); else messageClient(%obj.client, 'MsgBeaconNoSurface', '\c2Cannot place beacon. Not a valid surface.'); return 0; } else if(%obj.inv[%data.getName()] <= 0) return 0; } // newly deployed beacons default to "target" type if($TeamDeployedCount[%obj.team, TargetBeacon] >= $TeamDeployableMax[TargetBeacon]) { messageClient(%obj.client, 'MsgDeployFailed', '\c2Your team\'s control network has reached its capacity for this item.~wfx/misc/misc.error.wav'); return 0; } %terrPt = posFromRaycast(%searchResult); %terrNrm = normalFromRaycast(%searchResult); %intAngle = getTerrainAngle(%terrNrm); // getTerrainAngle() function found in staticShape.cs %rotAxis = vectorNormalize(vectorCross(%terrNrm, "0 0 1")); if (getWord(%terrNrm, 2) == 1 || getWord(%terrNrm, 2) == -1) %rotAxis = vectorNormalize(vectorCross(%terrNrm, "0 1 0")); %rotation = %rotAxis @ " " @ %intAngle; %obj.decInventory(%data, 1); %depBeac = new ScopeAlwaysShape() { dataBlock = "DeployedBeacon"; position = VectorAdd(%terrPt, VectorScale(%terrNrm, 0.05)); rotation = %rotation; }; $TeamDeployedCount[%obj.team, TargetBeacon]++; %depBeac.playThread($AmbientThread, "ambient"); %depBeac.team = %obj.team; %depBeac.sourceObject = %obj; // give it a team target %depBeac.setTarget(%depBeac.team); MissionCleanup.add(%depBeac); } function switchBeaconType(%beacon) { if(%beacon.isBeaconType(friend)) { // switch from marker beacon to target beacon if($TeamDeployedCount[%beacon.team, TargetBeacon] >= $TeamDeployableMax[TargetBeacon]) { messageClient(%beacon.sourceObject.client, 'MsgDeployFailed', '\c2Your team\'s control network has reached its capacity for this item.~wfx/misc/misc.error.wav'); return 0; } %beacon.setBeaconType(enemy); $TeamDeployedCount[%beacon.team, MarkerBeacon]--; $TeamDeployedCount[%beacon.team, TargetBeacon]++; } else { // switch from target beacon to marker beacon if($TeamDeployedCount[%beacon.team, MarkerBeacon] >= $TeamDeployableMax[MarkerBeacon]) { messageClient(%beacon.sourceObject.client, 'MsgDeployFailed', '\c2Your team\'s control network has reached its capacity for this item.~wfx/misc/misc.error.wav'); return 0; } %beacon.setBeaconType(friend); $TeamDeployedCount[%beacon.team, TargetBeacon]--; $TeamDeployedCount[%beacon.team, MarkerBeacon]++; } }