--------------------------------------------------------------------------------------------------------------- RepairGun / RepairRifle Tutorial --------------------------------------------------------------------------------------------------------------- This tutorial will make two different repair guns. The first, is just like the repair pack, except it's a weapon. It refills health twice as fast as the pack, so is recommended for only Engineers/Mediums. The second gun, is a long range repair rifle. It fills energy at half the speed of the repair pack, and requires the energy pack, but it can shoot up to a 1000 meters. ----------------------------------------------------------------------------- Engineer Repair Gun Step #1 // ------------------------------------------ // inventoryHud.cs // ------------------------------------------ $InvWeapon[12] = "Repair Gun"; $NameToInv["Repair Gun"] = "Repairgun2"; Step #2 // ------------------------------------------ // weapons.cs // ------------------------------------------ $WeaponsHudData[12, bitmapName] = "gui/hud_new_packrepair"; $WeaponsHudData[12, itemDataName] = "Repairgun2"; //no Ammo $WeaponsHudData[12, reticle] = "gui/hud_ret_targlaser"; $WeaponsHudData[12, visible] = "false"; $WeaponsHudCount = 13; exec("scripts/weapons/Repairgun.cs"); Step #3 // ------------------------------------------ // inventory.cs // ------------------------------------------ 3a) function ShapeBase::clearInventory(%this) { %this.setInventory(Repairgun2,0); } 3b) function serverCmdGiveAll(%client) { if($TestCheats) { %player.setInventory(Repairgun2,1); } } Step #4 // ------------------------------------------ // player.cs // ------------------------------------------ 4a) Add these to the player datablocks. Recommend only Engineers/Mediums. max [RepairGun2] = 1; 4b) Add these to function armor::applyConcussion if( %weaps[12] = %player.getInventory("Repairgun2") > 0 ) %numWeapons++; and case 12: %player.use("Repairgun2"); Step #5 // ------------------------------------------ // RepairGun.cs // ------------------------------------------ Make a file called RepairGun.cs in your weapons directory and add all this: //-------------------------------------------------------------------------- //Repair Gun // // //-------------------------------------------------------------------------- datablock ItemData(RepairGun2) { className = Weapon; catagory = "Spawn Items"; shapeFile = "weapon_repair.dts"; image = RepairGunImage2; mass = 1; elasticity = 0.2; friction = 0.6; pickupRadius = 2; pickUpName = "a repair gun"; computeCRC = true; emap = true; }; //-------------------------------------------------------------------------- // Repair Gun datablock ShapeBaseImageData(RepairGunImage2) { className = WeaponImage; shapeFile = "weapon_repair.dts"; offset = "0 0 0"; item = Repairgun2; showname = "Repair Gun"; usesEnergy = true; minEnergy = 3; cutOffEnergy = 3.1; emap = true; repairFactorPlayer = 0.004; // <--- Double RepairPack repairFactorObject = 0.008; // <--- Double RepairPack stateName[0] = "Activate"; stateTransitionOnTimeout[0] = "ActivateReady"; stateTimeoutValue[0] = 0.25; stateName[1] = "ActivateReady"; stateScript[1] = "onActivateReady"; stateSpinThread[1] = Stop; stateTransitionOnAmmo[1] = "Ready"; stateTransitionOnNoAmmo[1] = "ActivateReady"; stateName[2] = "Ready"; stateSpinThread[2] = Stop; stateTransitionOnNoAmmo[2] = "Deactivate"; stateTransitionOnTriggerDown[2] = "Validate"; stateName[3] = "Validate"; stateTransitionOnTimeout[3] = "Validate"; stateTimeoutValue[3] = 0.2; stateEnergyDrain[3] = 3; stateSpinThread[3] = SpinUp; stateScript[3] = "onValidate"; stateIgnoreLoadedForReady[3] = true; stateTransitionOnLoaded[3] = "Repair"; stateTransitionOnNoAmmo[3] = "Deactivate"; stateTransitionOnTriggerUp[3] = "Deactivate"; stateName[4] = "Repair"; stateSound[4] = RepairPackFireSound; stateScript[4] = "onRepair"; stateSpinThread[4] = FullSpeed; stateAllowImageChange[4] = false; stateSequence[4] = "activate"; stateFire[4] = true; stateEnergyDrain[4] = 9; stateTimeoutValue[4] = 0.2; stateTransitionOnTimeOut[4] = "Repair"; stateTransitionOnNoAmmo[4] = "Deactivate"; stateTransitionOnTriggerUp[4] = "Deactivate"; stateTransitionOnNotLoaded[4] = "Validate"; stateName[5] = "Deactivate"; stateScript[5] = "onDeactivate"; stateSpinThread[5] = SpinDown; stateSequence[5] = "activate"; stateDirection[5] = false; stateTimeoutValue[5] = 0.2; stateTransitionOnTimeout[5] = "ActivateReady"; }; function RepairGunImage2::onUnmount(%this,%obj,%slot) { // called when player switches to another weapon // stop repairing whatever player was repairing if(%obj.repairing) stopRepairing(%obj); %obj.setImageTrigger(%slot, false); // "turn off" the repair pack -- player needs to hit the "pack" key to // activate the repair gun again } function RepairGunImage2::onActivateReady(%this,%obj,%slot) { %obj.errMsgSent = false; %obj.selfRepairing = false; %obj.repairing = 0; %obj.setImageLoaded(%slot, false); } function RepairGunImage2::onValidate(%this,%obj,%slot) { // this = repairgunimage datablock // obj = player wielding the repair gun // slot = weapon slot if(%obj.getEnergyLevel() <= %this.cutOffEnergy) { stopRepairing(%obj); return; } %repGun = %obj.getMountedImage(%slot); // muzVec is the vector coming from the repair gun's "muzzle" %muzVec = %obj.getMuzzleVector(%slot); // muzNVec = normalized muzVec %muzNVec = VectorNormalize(%muzVec); %repairRange = DefaultRepairBeam.beamRange; // scale muzNVec to the range the repair beam can reach %muzScaled = VectorScale(%muzNVec, %repairRange); // muzPoint = the actual point of the gun's "muzzle" %muzPoint = %obj.getMuzzlePoint(%slot); // rangeEnd = muzzle point + length of beam %rangeEnd = VectorAdd(%muzPoint, %muzScaled); // search for just about anything that can be damaged as well as interiors %searchMasks = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::TurretObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ItemObjectType | $TypeMasks::ForceFieldObjectType; // search for objects within the beam's range that fit the masks above %scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj); // screen out interiors if (%scanTarg) { if (%scanTarg.getType() & $TypeMasks::ForceFieldObjectType) { if (%scanTarg.getDataBlock().getName() $= "DeployedForceField2") %scanTarg = %scanTarg.parent; else %scanTarg = "0"; } } if(%scanTarg && !(%scanTarg.getType() & $TypeMasks::InteriorObjectType)) { // a target in range was found %repTgt = firstWord(%scanTarg); // is the prospective target damaged? if(%repTgt.getDamageLevel()) { // yes, it's damaged if(%repTgt != %obj.repairing) { if(isObject(%obj.repairing)) stopRepairing(%obj); %obj.repairing = %repTgt; } // setting imageLoaded to true sends us to repair state (function onRepair) %obj.setImageLoaded(%slot, true); } else { // there is a target in range, but it's not damaged if(!%obj.errMsgSent) { // if the target isn't damaged, send a message to that effect only once messageClient(%obj.client, 'MsgRepairPackNotDamaged', '\c2Target is not damaged.', %repTgt); %obj.errMsgSent = true; } // if player was repairing something, stop the repairs -- we're done if(%obj.repairing) stopRepairing(%obj); } } //AI hack - too many things influence the aiming, so I'm going to force the repair object for bots only else if (%obj.client.isAIControlled() && isObject(%obj.client.repairObject)) { %repTgt = %obj.client.repairObject; %repPoint = %repTgt.getAIRepairPoint(); if (%repPoint $= "0 0 0") %repPoint = %repTgt.getWorldBoxCenter(); %repTgtVector = VectorNormalize(VectorSub(%muzPoint, %repPoint)); %aimVector = VectorNormalize(VectorSub(%muzPoint, %rangeEnd)); //if the dot product is very close (ie. we're aiming in the right direction) if (VectorDot(%repTgtVector, %aimVector) > 0.85) { //do an LOS to make sure nothing is in the way... %scanTarg = ContainerRayCast(%muzPoint, %repPoint, %searchMasks, %obj); if (firstWord(%scanTarg) == %repTgt) { // yes, it's damaged if(isObject(%obj.repairing)) stopRepairing(%obj); %obj.repairing = %repTgt; // setting imageLoaded to true sends us to repair state (function onRepair) %obj.setImageLoaded(%slot, true); } } } else if(%obj.getDamageLevel()) { // there is no target in range, but the player is damaged // check to see if we were repairing something before -- if so, stop repairing old target if(%obj.repairing != 0) if(%obj.repairing != %obj) stopRepairing(%obj); if(isObject(%obj.repairing)) stopRepairing(%obj); %obj.repairing = %obj; // quick, to onRepair! %obj.setImageLoaded(%slot, true); } else { // there is no target in range, and the player isn't damaged if(!%obj.errMsgSent) { // send an error message only once messageClient(%obj.client, 'MsgRepairPackNoTarget', '\c2No target to repair.'); %obj.errMsgSent = true; } stopRepairing(%obj); } } function RepairGunImage2::onRepair(%this,%obj,%slot) { // this = repairgunimage datablock // obj = player wielding the repair gun // slot = weapon slot if(%obj.getEnergyLevel() <= %this.cutOffEnergy) { stopRepairing(%obj); return; } // reset the flag that indicates an error message has been sent %obj.errMsgSent = false; %target = %obj.repairing; if(!%target) { // no target -- whoops! never mind stopRepairing(%obj); } else { %target.repairedBy = %obj.client; //keep track of who last repaired this item if(%obj.repairing == %obj) { // player is self-repairing if(%obj.getDamageLevel()) { if(!%obj.selfRepairing) { // no need for a projectile, just send a message and up the repair rate messageClient(%obj.client, 'MsgRepairPackPlayerSelfRepair', '\c2Repairing self.'); %obj.selfRepairing = true; startRepairing3(%obj, true); } } else { messageClient(%obj.client, 'MsgRepairPackSelfDone', '\c2Repairs completed on self.'); stopRepairing(%obj); %obj.errMsgSent = true; } } else { // make sure we still have a target -- more vector fun!!! %muzVec = %obj.getMuzzleVector(%slot); %muzNVec = VectorNormalize(%muzVec); %repairRange = DefaultRepairBeam.beamRange; %muzScaled = VectorScale(%muzNVec, %repairRange); %muzPoint = %obj.getMuzzlePoint(%slot); %rangeEnd = VectorAdd(%muzPoint, %muzScaled); %searchMasks = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::TurretObjectType | $TypeMasks::ItemObjectType | $TypeMasks::ForceFieldObjectType; //AI hack to help "fudge" the repairing stuff... if (%obj.client.isAIControlled() && isObject(%obj.client.repairObject) && %obj.client.repairObject == %obj.repairing) { %repTgt = %obj.client.repairObject; %repPoint = %repTgt.getAIRepairPoint(); if (%repPoint $= "0 0 0") %repPoint = %repTgt.getWorldBoxCenter(); %repTgtVector = VectorNormalize(VectorSub(%muzPoint, %repPoint)); %aimVector = VectorNormalize(VectorSub(%muzPoint, %rangeEnd)); //if the dot product is very close (ie. we're aiming in the right direction) if (VectorDot(%repTgtVector, %aimVector) > 0.85) %scanTarg = ContainerRayCast(%muzPoint, %repPoint, %searchMasks, %obj); } else %scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj); if (%scanTarg) { if (%scanTarg.getType() & $TypeMasks::ForceFieldObjectType) { if (%scanTarg.getDataBlock().getName() $= "DeployedForceField2") { %pos = getWords(%scanTarg, 1, 3); %scanTarg = %scanTarg.parent SPC %pos; } else %scanTarg = "0"; } } if (%scanTarg) { %pos = getWords(%scanTarg, 1, 3); %obstructMask = $TypeMasks::InteriorObjectType | $TypeMasks::TerrainObjectType; %obstruction = ContainerRayCast(%muzPoint, %pos, %obstructMask, %obj); if (%obstruction) %scanTarg = "0"; } if (%scanTarg && %scanTarg2) %scanTarg = %scanTarg2; if(%scanTarg) { // there's still a target out there %repTgt = firstWord(%scanTarg); // is the target damaged? if(%repTgt.getDamageLevel()) { if(%repTgt != %obj.repairing) { // the target is not the same as the one we were just repairing // stop repairing old target, start repairing new target stopRepairing(%obj); if(isObject(%obj.repairing)) stopRepairing(%obj); %obj.repairing = %repTgt; // extract the name of what player is repairing based on what it is // if it's a player, it's the player's name (duh) // if it's an object, look for a nametag // if object has no nametag, just say what it is (e.g. generatorLarge) if(%repTgt.getClassName() $= Player) %tgtName = getTaggedString(%repTgt.client.name); else if(%repTgt.getGameName() !$= "") %tgtName = %repTgt.getGameName(); else %tgtName = %repTgt.getDatablock().getName(); messageClient(%obj.client, 'MsgRepairPackRepairingObj', '\c2Repairing %1.', %tgtName, %repTgt); startRepairing3(%obj, false); } else { // it's the same target as last time // changed to fix "2 players can't repair same object" bug if(%obj.repairProjectile == 0) { if(%repTgt.getClassName() $= Player) %tgtName = getTaggedString(%repTgt.client.name); else if(%repTgt.getGameName() !$= "") %tgtName = %repTgt.getGameName(); else %tgtName = %repTgt.getDatablock().getName(); messageClient(%obj.client, 'MsgRepairPackRepairingObj', '\c2Repairing %1.', %tgtName, %repTgt); startRepairing3(%obj, false); } } } else { %rateOfRepair = %this.repairFactorObject; if(%repTgt.getClassName() $= Player) { %tgtName = getTaggedString(%repTgt.client.name); %rateOfRepair = %this.repairFactorPlayer; } else if(%repTgt.getGameName() !$= "") %tgtName = %repTgt.getGameName(); else %tgtName = %repTgt.getDatablock().getName(); if(%repTgt != %obj.repairing) { // it isn't the same object we were repairing previously messageClient(%obj.client, 'MsgRepairPackNotDamaged', '\c2%1 is not damaged.', %tgtName); } else { // same target, but not damaged -- we must be done messageClient(%obj.client, 'MsgRepairPackDone', '\c2Repairs completed.'); Game.objectRepaired(%repTgt, %tgtName); } %obj.errMsgSent = true; stopRepairing(%obj); } } else { // whoops, we lost our target messageClient(%obj.client, 'MsgRepairPackLostTarget', '\c2Repair target no longer in range.'); stopRepairing(%obj); } } } } function startRepairing3(%player, %self) { // %player = the player who was using the repair pack // %self = boolean -- is player repairing him/herself? if(%self) { // one repair, hold the projectile %player.setRepairRate(%player.getRepairRate() + RepairGunImage2.repairFactorPlayer); %player.selfRepairing = true; %player.repairingRate = RepairGunImage2.repairFactorPlayer; } else { //if(%player.repairing.beingRepaired $= "") // %player.repairing.beingRepaired = 1; //else // %player.repairing.beingRepaired++; //AI hack... if (%player.client.isAIControlled() && %player.client.repairObject == %player.repairing) { %initialPosition = %player.getMuzzlePoint($WeaponSlot); %initialDirection = VectorSub(%initialPosition, %player.repairing.getWorldBoxCenter()); } else { %initialDirection = %player.getMuzzleVector($WeaponSlot); %initialPosition = %player.getMuzzlePoint($WeaponSlot); } if(%player.repairing.getClassName() $= Player) %repRate = RepairGunImage2.repairFactorPlayer; else %repRate = RepairGunImage2.repairFactorObject; %player.repairing.setRepairRate(%player.repairing.getRepairRate() + %repRate); %player.repairingRate = %repRate; if (%player.repairing.getDataBlock().getName() $= "DeployedForceField") %targetObject = %player.repairing.field; else %targetObject = %player.repairing; %player.repairProjectile = new RepairProjectile() { dataBlock = DefaultRepairBeam; initialDirection = %initialDirection; initialPosition = %initialPosition; sourceObject = %player; sourceSlot = $WeaponSlot; targetObject = %targetObject; }; MissionCleanup.add(%player.repairProjectile); } } function RepairGunImage2::onDeactivate(%this,%obj,%slot) { stopRepairing(%obj); } function RepairGunImage2::onPickup(%this, %obj, %shape, %amount) { // created to prevent console errors } ----------------------------------------------------------------------------- Sniper Repair Rifle Step #1 // ------------------------------------------ // inventoryHud.cs // ------------------------------------------ 1a) $InvWeapon[13] = "Repair Rifle"; $NameToInv["Repair Rifle"] = "RepairRifle"; 1b) In function InventoryScreen::updateHud, These lines: else if ( "SniperRifle" $= $NameToInv[%client.favorites[getField( %client.weaponIndex,%i )]] ) { %noSniperRifle = false; %packList = "noSelect\tEnergy Pack\tEnergy Pack must be used when \tLaser Rifle is selected!"; %client.favorites[getField(%client.packIndex,0)] = "Energy Pack"; } should become: else if ( "SniperRifle" $= $NameToInv[%client.favorites[getField( %client.weaponIndex,%i )]] ) { %noSniperRifle = false; %packList = "noSelect\tEnergy Pack\tEnergy Pack must be used when \tLaser Rifle is selected!"; %client.favorites[getField(%client.packIndex,0)] = "Energy Pack"; } else if ( "RepairRifle" $= $NameToInv[%client.favorites[getField( %client.weaponIndex,%i )]] ) { %noSniperRifle = false; %packList = "noSelect\tEnergy Pack\tEnergy Pack must be used when \tRepair Rifle is selected!"; %client.favorites[getField(%client.packIndex,0)] = "Energy Pack"; } 1c) function checkPackValidity(%pack, %equipment, %item) { %require["Repair Rifle"] = "Pack" TAB "Energy Pack"; } Step #2 // ------------------------------------------ // weapons.cs // ------------------------------------------ $WeaponsHudData[13, bitmapName] = "gui/hud_new_packrepair"; $WeaponsHudData[13, itemDataName] = "RepairRifle"; //no Ammo $WeaponsHudData[13, reticle] = "gui/hud_ret_targlaser"; $WeaponsHudData[13, visible] = "false"; $WeaponsHudCount = 14; exec("scripts/weapons/RepairRifle.cs"); Step #3 // ------------------------------------------ // inventory.cs // ------------------------------------------ 3a) function ShapeBase::clearInventory(%this) { %this.setInventory(RepairRifle,0); } 3b) function serverCmdGiveAll(%client) { if($TestCheats) { %player.setInventory(RepairRifle,1); } } Step #4 // ------------------------------------------ // player.cs // ------------------------------------------ 4a) Add this to player datablocks. Recommend only Snipers/Lights. max [RepairRifle] = 1; 4b) Add these to function armor::applyConcussion if( %weaps[13] = %player.getInventory("RepairRifle") > 0 ) %numWeapons++; and case 12: %player.use("RepairRifle"); Step #5 // ------------------------------------------ // RepairRifle.cs // ------------------------------------------ Create a file called RepairRifle.cs in your weapons directory. Add all this into it: //-------------------------------------------------------------------------- // Repair Rifle // //-------------------------------------------------------------------------- datablock EffectProfile(RepairRifleSwitchEffect) { effectname = "weapons/generic_switch"; minDistance = 2.5; maxDistance = 2.5; }; datablock EffectProfile(RepairRiflePaintEffect) { effectname = "weapons/targetinglaser_paint"; minDistance = 2.5; maxDistance = 2.5; }; datablock AudioProfile(RepairRifleSwitchSound) { filename = "fx/weapons/generic_switch.wav"; description = AudioClosest3d; preload = true; effect = RepairRifleSwitchEffect; }; datablock AudioProfile(RepairRiflePaintSound) { filename = "fx/weapons/targetinglaser_paint.wav"; description = CloseLooping3d; preload = true; effect = RepairRiflePaintEffect; }; //-------------------------------------- // Projectile //-------------------------------------- datablock TargetProjectileData(RepairLaser) { directDamage = 0.0; hasDamageRadius = false; indirectDamage = 0.0; damageRadius = 0.0; velInheritFactor = 1.0; maxRifleRange = 1000; beamColor = "1.0 0.1 0.1"; startBeamWidth = 0.20; pulseBeamWidth = 0.15; beamFlareAngle = 3.0; minFlareSize = 0.0; maxFlareSize = 400.0; pulseSpeed = 6.0; pulseLength = 0.150; textureName[0] = "special/nonlingradient"; textureName[1] = "special/redflare"; textureName[2] = "special/pulse"; textureName[3] = "special/expFlare"; textureName[4] = "special/redbump2"; }; //-------------------------------------- // Rifle and item... //-------------------------------------- datablock ItemData(RepairRifle) { className = Weapon; catagory = "Spawn Items"; shapeFile = "weapon_targeting.dts"; image = RepairRifleImage; mass = 1; elasticity = 0.2; friction = 0.6; pickupRadius = 2; pickUpName = "a repair rifle"; computeCRC = true; }; datablock ShapeBaseImageData(RepairRifleImage) { className = WeaponImage; shapeFile = "weapon_repair.dts"; offset = "0 0 0"; item = RepairRifle; showname = "Repair Rifle"; usesEnergy = true; minEnergy = 3; cutOffEnergy = 3.1; emap = true; repairFactorPlayer = 0.001; // <--- attention DaveG! repairFactorObject = 0.002; // <--- attention DaveG! stateName[0] = "Activate"; stateTransitionOnTimeout[0] = "ActivateReady"; stateTimeoutValue[0] = 0.25; stateName[1] = "ActivateReady"; stateScript[1] = "onActivateReady"; stateSpinThread[1] = Stop; stateTransitionOnAmmo[1] = "Ready"; stateTransitionOnNoAmmo[1] = "ActivateReady"; stateName[2] = "Ready"; stateSpinThread[2] = Stop; stateTransitionOnNoAmmo[2] = "Deactivate"; stateTransitionOnTriggerDown[2] = "Validate"; stateName[3] = "Validate"; stateTransitionOnTimeout[3] = "Validate"; stateTimeoutValue[3] = 0.2; stateEnergyDrain[3] = 3; stateSpinThread[3] = SpinUp; stateScript[3] = "onValidate"; stateIgnoreLoadedForReady[3] = true; stateTransitionOnLoaded[3] = "Repair"; stateTransitionOnNoAmmo[3] = "Deactivate"; stateTransitionOnTriggerUp[3] = "Deactivate"; stateName[4] = "Repair"; stateSound[4] = RepairPackFireSound; stateScript[4] = "onRepair"; stateSpinThread[4] = FullSpeed; stateAllowImageChange[4] = false; stateSequence[4] = "activate"; stateFire[4] = true; stateEnergyDrain[4] = 9; stateTimeoutValue[4] = 0.2; stateTransitionOnTimeOut[4] = "Repair"; stateTransitionOnNoAmmo[4] = "Deactivate"; stateTransitionOnTriggerUp[4] = "Deactivate"; stateTransitionOnNotLoaded[4] = "Validate"; stateName[5] = "Deactivate"; stateScript[5] = "onDeactivate"; stateSpinThread[5] = SpinDown; stateSequence[5] = "activate"; stateDirection[5] = false; stateTimeoutValue[5] = 0.2; stateTransitionOnTimeout[5] = "ActivateReady"; }; function RepairRifleImage::onUnmount(%this,%obj,%slot) { // called when player switches to another weapon // stop repairing whatever player was repairing if(%obj.repairing) stopRepairing(%obj); %obj.setImageTrigger(%slot, false); // "turn off" the repair pack -- player needs to hit the "pack" key to // activate the repair gun again } function RepairRifleImage::onActivateReady(%this,%obj,%slot) { %obj.errMsgSent = false; %obj.selfRepairing = false; %obj.repairing = 0; %obj.setImageLoaded(%slot, false); } function RepairRifleImage::onValidate(%this,%obj,%slot) { // this = repairgunimage datablock // obj = player wielding the repair gun // slot = weapon slot if(!%obj.hasEnergyPack) { // siddown Junior, you can't use it stopRepairing(%obj); return; } if(%obj.getEnergyLevel() <= %this.cutOffEnergy) { stopRepairing(%obj); return; } %repGun = %obj.getMountedImage(%slot); // muzVec is the vector coming from the repair gun's "muzzle" %muzVec = %obj.getMuzzleVector(%slot); // muzNVec = normalized muzVec %muzNVec = VectorNormalize(%muzVec); %repairRange = RepairLaser.maxRifleRange; // scale muzNVec to the range the repair beam can reach %muzScaled = VectorScale(%muzNVec, %repairRange); // muzPoint = the actual point of the gun's "muzzle" %muzPoint = %obj.getMuzzlePoint(%slot); // rangeEnd = muzzle point + length of beam %rangeEnd = VectorAdd(%muzPoint, %muzScaled); // search for just about anything that can be damaged as well as interiors %searchMasks = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::TurretObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ItemObjectType | $TypeMasks::ForceFieldObjectType; // search for objects within the beam's range that fit the masks above %scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj); // screen out interiors if (%scanTarg) { if (%scanTarg.getType() & $TypeMasks::ForceFieldObjectType) { if (%scanTarg.getDataBlock().getName() $= "DeployedForceField2") %scanTarg = %scanTarg.parent; else %scanTarg = "0"; } } if(%scanTarg && !(%scanTarg.getType() & $TypeMasks::InteriorObjectType)) { // a target in range was found %repTgt = firstWord(%scanTarg); // is the prospective target damaged? if(%repTgt.getDamageLevel()) { // yes, it's damaged if(%repTgt != %obj.repairing) { if(isObject(%obj.repairing)) stopRepairing(%obj); %obj.repairing = %repTgt; } // setting imageLoaded to true sends us to repair state (function onRepair) %obj.setImageLoaded(%slot, true); } else { // there is a target in range, but it's not damaged if(!%obj.errMsgSent) { // if the target isn't damaged, send a message to that effect only once messageClient(%obj.client, 'MsgRepairPackNotDamaged', '\c2Target is not damaged.', %repTgt); %obj.errMsgSent = true; } // if player was repairing something, stop the repairs -- we're done if(%obj.repairing) stopRepairing(%obj); } } //AI hack - too many things influence the aiming, so I'm going to force the repair object for bots only else if (%obj.client.isAIControlled() && isObject(%obj.client.repairObject)) { %repTgt = %obj.client.repairObject; %repPoint = %repTgt.getAIRepairPoint(); if (%repPoint $= "0 0 0") %repPoint = %repTgt.getWorldBoxCenter(); %repTgtVector = VectorNormalize(VectorSub(%muzPoint, %repPoint)); %aimVector = VectorNormalize(VectorSub(%muzPoint, %rangeEnd)); //if the dot product is very close (ie. we're aiming in the right direction) if (VectorDot(%repTgtVector, %aimVector) > 0.85) { //do an LOS to make sure nothing is in the way... %scanTarg = ContainerRayCast(%muzPoint, %repPoint, %searchMasks, %obj); if (firstWord(%scanTarg) == %repTgt) { // yes, it's damaged if(isObject(%obj.repairing)) stopRepairing(%obj); %obj.repairing = %repTgt; // setting imageLoaded to true sends us to repair state (function onRepair) %obj.setImageLoaded(%slot, true); } } } else if(%obj.getDamageLevel()) { // there is no target in range, but the player is damaged // check to see if we were repairing something before -- if so, stop repairing old target if(%obj.repairing != 0) if(%obj.repairing != %obj) stopRepairing(%obj); if(isObject(%obj.repairing)) stopRepairing(%obj); %obj.repairing = %obj; // quick, to onRepair! %obj.setImageLoaded(%slot, true); } else { // there is no target in range, and the player isn't damaged if(!%obj.errMsgSent) { // send an error message only once messageClient(%obj.client, 'MsgRepairPackNoTarget', '\c2No target to repair.'); %obj.errMsgSent = true; } stopRepairing(%obj); } } function RepairRifleImage::onRepair(%this,%obj,%slot) { // this = repairgunimage datablock // obj = player wielding the repair gun // slot = weapon slot if(!%obj.hasEnergyPack) { // siddown Junior, you can't use it stopRepairing(%obj); return; } if(%obj.getEnergyLevel() <= %this.cutOffEnergy) { stopRepairing(%obj); return; } // reset the flag that indicates an error message has been sent %obj.errMsgSent = false; %target = %obj.repairing; if(!%target) { // no target -- whoops! never mind stopRepairing(%obj); } else { %target.repairedBy = %obj.client; //keep track of who last repaired this item if(%obj.repairing == %obj) { // player is self-repairing if(%obj.getDamageLevel()) { if(!%obj.selfRepairing) { // no need for a projectile, just send a message and up the repair rate messageClient(%obj.client, 'MsgRepairPackPlayerSelfRepair', '\c2Repairing self.'); %obj.selfRepairing = true; startRepairing2(%obj, true); } } else { messageClient(%obj.client, 'MsgRepairPackSelfDone', '\c2Repairs completed on self.'); stopRepairing(%obj); %obj.errMsgSent = true; } } else { // make sure we still have a target -- more vector fun!!! %muzVec = %obj.getMuzzleVector(%slot); %muzNVec = VectorNormalize(%muzVec); %repairRange = RepairLaser.maxRifleRange; %muzScaled = VectorScale(%muzNVec, %repairRange); %muzPoint = %obj.getMuzzlePoint(%slot); %rangeEnd = VectorAdd(%muzPoint, %muzScaled); %searchMasks = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::TurretObjectType | $TypeMasks::ItemObjectType | $TypeMasks::ForceFieldObjectType; //AI hack to help "fudge" the repairing stuff... if (%obj.client.isAIControlled() && isObject(%obj.client.repairObject) && %obj.client.repairObject == %obj.repairing) { %repTgt = %obj.client.repairObject; %repPoint = %repTgt.getAIRepairPoint(); if (%repPoint $= "0 0 0") %repPoint = %repTgt.getWorldBoxCenter(); %repTgtVector = VectorNormalize(VectorSub(%muzPoint, %repPoint)); %aimVector = VectorNormalize(VectorSub(%muzPoint, %rangeEnd)); //if the dot product is very close (ie. we're aiming in the right direction) if (VectorDot(%repTgtVector, %aimVector) > 0.85) %scanTarg = ContainerRayCast(%muzPoint, %repPoint, %searchMasks, %obj); } else %scanTarg = ContainerRayCast(%muzPoint, %rangeEnd, %searchMasks, %obj); if (%scanTarg) { if (%scanTarg.getType() & $TypeMasks::ForceFieldObjectType) { if (%scanTarg.getDataBlock().getName() $= "DeployedForceField2") { %pos = getWords(%scanTarg, 1, 3); %scanTarg = %scanTarg.parent SPC %pos; } else %scanTarg = "0"; } } if (%scanTarg) { %pos = getWords(%scanTarg, 1, 3); %obstructMask = $TypeMasks::InteriorObjectType | $TypeMasks::TerrainObjectType; %obstruction = ContainerRayCast(%muzPoint, %pos, %obstructMask, %obj); if (%obstruction) %scanTarg = "0"; } if (%scanTarg && %scanTarg2) %scanTarg = %scanTarg2; if(%scanTarg) { // there's still a target out there %repTgt = firstWord(%scanTarg); // is the target damaged? if(%repTgt.getDamageLevel()) { if(%repTgt != %obj.repairing) { // the target is not the same as the one we were just repairing // stop repairing old target, start repairing new target stopRepairing(%obj); if(isObject(%obj.repairing)) stopRepairing(%obj); %obj.repairing = %repTgt; // extract the name of what player is repairing based on what it is // if it's a player, it's the player's name (duh) // if it's an object, look for a nametag // if object has no nametag, just say what it is (e.g. generatorLarge) if(%repTgt.getClassName() $= Player) %tgtName = getTaggedString(%repTgt.client.name); else if(%repTgt.getGameName() !$= "") %tgtName = %repTgt.getGameName(); else %tgtName = %repTgt.getDatablock().getName(); messageClient(%obj.client, 'MsgRepairPackRepairingObj', '\c2Repairing %1.', %tgtName, %repTgt); startRepairing2(%obj, false); } else { // it's the same target as last time // changed to fix "2 players can't repair same object" bug if(%obj.repairProjectile == 0) { if(%repTgt.getClassName() $= Player) %tgtName = getTaggedString(%repTgt.client.name); else if(%repTgt.getGameName() !$= "") %tgtName = %repTgt.getGameName(); else %tgtName = %repTgt.getDatablock().getName(); messageClient(%obj.client, 'MsgRepairPackRepairingObj', '\c2Repairing %1.', %tgtName, %repTgt); startRepairing2(%obj, false); } } } else { %rateOfRepair = %this.repairFactorObject; if(%repTgt.getClassName() $= Player) { %tgtName = getTaggedString(%repTgt.client.name); %rateOfRepair = %this.repairFactorPlayer; } else if(%repTgt.getGameName() !$= "") %tgtName = %repTgt.getGameName(); else %tgtName = %repTgt.getDatablock().getName(); if(%repTgt != %obj.repairing) { // it isn't the same object we were repairing previously messageClient(%obj.client, 'MsgRepairPackNotDamaged', '\c2%1 is not damaged.', %tgtName); } else { // same target, but not damaged -- we must be done messageClient(%obj.client, 'MsgRepairPackDone', '\c2Repairs completed.'); Game.objectRepaired(%repTgt, %tgtName); } %obj.errMsgSent = true; stopRepairing(%obj); } } else { // whoops, we lost our target messageClient(%obj.client, 'MsgRepairPackLostTarget', '\c2Repair target no longer in range.'); stopRepairing(%obj); } } } } function startRepairing2(%player, %self) { // %player = the player who was using the repair pack // %self = boolean -- is player repairing him/herself? if(%self) { // one repair, hold the projectile %player.setRepairRate(%player.getRepairRate() + RepairRifleImage.repairFactorPlayer); %player.selfRepairing = true; %player.repairingRate = RepairRifleImage.repairFactorPlayer; } else { //if(%player.repairing.beingRepaired $= "") // %player.repairing.beingRepaired = 1; //else // %player.repairing.beingRepaired++; //AI hack... if (%player.client.isAIControlled() && %player.client.repairObject == %player.repairing) { %initialPosition = %player.getMuzzlePoint($WeaponSlot); %initialDirection = VectorSub(%initialPosition, %player.repairing.getWorldBoxCenter()); } else { %initialDirection = %player.getMuzzleVector($WeaponSlot); %initialPosition = %player.getMuzzlePoint($WeaponSlot); } if(%player.repairing.getClassName() $= Player) %repRate = RepairRifleImage.repairFactorPlayer; else %repRate = RepairRifleImage.repairFactorObject; %player.repairing.setRepairRate(%player.repairing.getRepairRate() + %repRate); %player.repairingRate = %repRate; %player.repairProjectile = new TargetProjectile() { dataBlock = RepairLaser; initialDirection = %initialDirection; initialPosition = %initialPosition; sourceObject = %player; sourceSlot = $WeaponSlot; }; MissionCleanup.add(%player.repairProjectile); } } function RepairRifleImage::onDeactivate(%this,%obj,%slot) { stopRepairing(%obj); } function RepairRifleImage::onPickup(%this, %obj, %shape, %amount) { // created to prevent console errors }