// ------------------------------------------------------------------------ // Havoc Teleporter Addin for Base/other mod servers // // This code is meant to be called from a map file and will scan through the // map replacing the MPB Teleporter that can be placed from the map editor // with a valid one from the Havoc mod. It contains enough code to place // a teleporter from code, but not to buy and deploy by players. There is // a session ID which is randomly generated that is needed to create the // teleporter. The following code issues it properly, however those using // this function from the command line or inside a mod will have difficulty. // ------------------------------------------------------------------------ // If this is a Havoc Server, don't execute this code. // The onMissionChange will exec the TeleporterScanMission() itself. if ($HavocID > 0 || $HavocID !$= "") return(0); // ------------------------------------------------------------------------ // Give some credit. // ------------------------------------------------------------------------ error("Special Thanks to the Havoc 2 DEV team."); // ------------------------------------------------------------------------ // Initialize/Reinitialize Global Teleporter Arrays // ------------------------------------------------------------------------ // These are globals that set how many and which teleporters a team has. $TeamTeleporterMax = 6; // Team 0 - Universal $Team0Teleporter[1] = 0; $Team0Teleporter[2] = 0; $Team0Teleporter[3] = 0; $Team0Teleporter[4] = 0; $Team0Teleporter[5] = 0; $Team0Teleporter[6] = 0; $Team0TeleporterCount = 0; // Team 1 $Team1Teleporter[1] = 0; $Team1Teleporter[2] = 0; $Team1Teleporter[3] = 0; $Team1Teleporter[4] = 0; $Team1Teleporter[5] = 0; $Team1Teleporter[6] = 0; $Team1TeleporterCount = 0; // Team 2 $Team2Teleporter[1] = 0; $Team2Teleporter[2] = 0; $Team2Teleporter[3] = 0; $Team2Teleporter[4] = 0; $Team2Teleporter[5] = 0; $Team2Teleporter[6] = 0; $Team2TeleporterCount = 0; $HavocTeleporterID = mFloor(getRandom(1000)) + 1.0; // ------------------------------------------------------------------------ // Trigger // ------------------------------------------------------------------------ datablock TriggerData(HavocTeleporterTrigger) { tickPeriodMS = 200; }; function HavocTeleporterTrigger::onTickTrigger(%this, %Trigger) { // Stops Console Spamming } function HavocTeleporterTrigger::onEnterTrigger(%Data, %Trigger, %Player) { //make sure it's a player object, and that that object is still alive if (%Player.getDataBlock().className !$= "Armor" || %Player.getState() $= "Dead") return; %Player.inStation = true; if (%Player.CantTeleport == true) return; %Teleporter = %Trigger.Teleporter; %Player.Teleporter = %Teleporter; %TeleporterData = %Teleporter.getDataBlock(); if (%Teleporter.NeedsPower == true && %Teleporter.isPowered() == false) { messageClient(%Player.client, 'msgStationDenied', '\c2Teleport Station is not powered!'); return; } // Mark the teleporter as occupied if (%Teleporter.UsedBy $= "") %Teleporter.UsedBy = 0; %Teleporter.UsedBy++; %Player.inStation = true; commandToClient(%Player.client,'setStationKeys', true); //verify station.team is team associated and isn't on player's team if (TriggerCheck(%Trigger, %Player) == false) { %Teleporter.playAudio(2, StationAccessDeniedSound); messageClient(%Player.client, 'msgStationDenied', '\c2Access Denied -- Wrong team.'); } else if (%Teleporter.getDamageLevel() > %TeleporterData.disabledLevel) { messageClient(%Player.client, 'msgStationDisabled', '\c2Teleporter is disabled.'); return; } else { %NextTeleporter = FindNextTeleporter(%Teleporter); if (%NextTeleporter == 0) { messageClient(%Player.client, 'msgStationDisabled', '\c2No available Teleporters found.'); return; } // Everything is good, teleport player. // Stop the Players Movement and fix them to the center of the teleport pad %Player.setVelocity("0 0 0"); %Player.setMoveState(true); %Position = posFromTransform(%Teleporter.getTransform()); %Player.setTransform(%Position); %Player.setVelocity("0 0 0"); %Player.lastWeapon = %Player.getMountedImage($WeaponSlot); %Player.unmountImage($WeaponSlot); %Player.CantTeleport = true; %Teleporter.UsedBy += 10; %NextTeleporter.UsedBy += 10; %Teleporter.playAudio($PlaySound, StationTeleportAcitvateSound); %Teleporter.playThread($ActivateThread,"activate"); %Teleporter.setThreadDir($ActivateThread, false); %Player.Teleporter = %Teleporter; %Teleporter.getDataBlock().TeleportPlayer(%Player, %NextTeleporter); } } // Clear the Players Teleporter Setting so that it is not decremented when they die. function HavocTeleporterTrigger::onLeaveTrigger(%Data, %Trigger, %Player) { %Player.inStation = false; commandToClient(%Player.client,'setStationKeys', false); %Player.Teleporter = ""; %Teleporter = %Trigger.Teleporter; %Teleporter.UsedBy --; if (%Teleporter.UsedBy < 0) %Teleporter.UsedBy = 0; } // ------------------------------------------------------------------------ // Effects // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ // Deployed Object // ------------------------------------------------------------------------ datablock StaticShapeData(HavocTeleporter) : StaticShapeDamageProfile { className = Station; catagory = "Stations"; shapeFile = "station_teleport.dts"; maxDamage = 1.20; destroyedLevel = 1.20; disabledLevel = 0.84; deployedObject = true; explosion = ShapeExplosion; expDmgRadius = 10.0; expDamage = 0.4; expImpulse = 1500.0; dynamicType = $TypeMasks::StationObjectType; doesRepair = true; isShielded = true; energyPerDamagePoint = 50; maxEnergy = 200; rechargeRate = 0.31; debrisShapeName = "debris_generic.dts"; debris = StationDebris; humSound = StationTeleportHumSound; targetNameTag = 'Teleporter'; targetTypeTag = 'Teleport Station'; teleporter = true; TeleportTime = 2000; TeleportDelay = 850; }; datablock StaticShapeData(HavocTeleporterCapActive) : StaticShapeDamageProfile { shapeFile = "beacon.dts"; explosion = DeployablesExplosion; maxDamage = 10000; disabledLevel = 10000; destroyedLevel = 10000; debrisShapeName = "debris_generic_small.dts"; debris = SmallShapeDebris; deployAmbientThread = true; lightType = "PulsingLight"; lightColor = "0.95 0.82 0.48 0.4"; lightTime = "4000"; lightRadius = "1.75"; }; datablock StaticShapeData(HavocTeleporterCapDisabled) : StaticShapeDamageProfile { shapeFile = "beacon.dts"; explosion = DeployablesExplosion; maxDamage = 10000; disabledLevel = 10000; destroyedLevel = 10000; debrisShapeName = "debris_generic_small.dts"; debris = SmallShapeDebris; deployAmbientThread = false; lightType = "PulsingLight"; lightColor = "0.95 0.82 0.48 0.4"; lightTime = "4000"; lightRadius = "1.75"; }; function HavocTeleporter::onDestroyed(%this, %Teleporter, %prevState) { // Mark the teleporter slot as available and decrement team count switch (%Teleporter.team) { case 0 : $Team0TeleporterCount --; $Team0Teleporter[%Teleporter.TeleporterNo] = 0; case 0 : $Team1TeleporterCount --; $Team1Teleporter[%Teleporter.TeleporterNo] = 0; case 0 : $Team2TeleporterCount --; $Team2Teleporter[%Teleporter.TeleporterNo] = 0; } if (%Teleporter.Cap > 0) %Teleporter.Cap.delete(); // We have not said to not delete it, then we delete it. if (%Teleporter.DontDelete == false) { %Teleporter.schedule(250, delete); $TeamDeployedCount[%Teleporter.team, %Teleporter.item]--; if ($TeamDeployedCount[%Teleporter.team, %Teleporter.item] < 0) $TeamDeployedCount[%Teleporter.team, %Teleporter.item] = 0; } else { // Replace the flashing cap with the disabled one. %Position = posFromTransform(%Teleporter.getTransform()); %PositionXY = getWords(%Position, 0, 1); %PositionZ = getWord(%Position, 2); %Position = %PositionXY @ " " @ %PositionZ + 0.22; %Item = new ScopeAlwaysShape() { dataBlock = "HavocTeleporterCapDisabled"; position = %Position; }; MissionCleanup.add(%Item); // Relink the non-flashing cap. %Item.Teleporter = %Teleporter; %Teleporter.Cap = %Item; %Teleporter.TeleFixCheck = %Teleporter.schedule(1000, TeleFixCheck, %Teleporter); } } // This starts the teleporter special effect and also makes it usable. function HavocTeleporter::Init(%Data, %Teleporter) { %Position = posFromTransform(%Teleporter.getTransform()); %PositionXY = getWords(%Position, 0, 1); %PositionZ = getWord(%Position, 2); %Position = %PositionXY @ " " @ %PositionZ + 0.22; %Item = new ScopeAlwaysShape() { dataBlock = "HavocTeleporterCapActive"; position = %Position; }; MissionCleanup.add(%Item); %Item.Teleporter = %Teleporter; %Teleporter.Cap = %Item; %Teleporter.UsedBy -= 10; if (%Teleporter.UsedBy < 0) %Teleporter.UsedBy = 0; %Teleporter.Cap.playThread(0, "deploy"); %Teleporter.Init = ""; } function HavocTeleporter::createTrigger(%this, %Teleporter) { %Group = %Teleporter.Group; %Transform = %Teleporter.getTransform(); %Trigger = new Trigger() { dataBlock = HavocTeleporterTrigger; polyhedron = "-0.125 0.0 0.1 0.25 0.0 0.0 0.0 -0.7 0.0 0.0 0.0 1.0"; position = %Transform; }; %Group.add(%trigger); %Trigger.Teleporter = %Teleporter; %Teleporter.Trigger = %Trigger; } function HavocTeleporter::TeleportPlayer(%Data, %Player, %NextTeleporter) { %Client = %Player.client; messageClient(%Client, 'MsgCantSitHere', 'Initiating Teleportation Sequence.'); %TeleporterTransform = %Player.getTransform(); %TeleporterPosition = posFromTransform(%TeleporterTransform); %NewTeleporterTransform = %NextTeleporter.getTransform(); %NewTeleporterPosition = posFromTransform(%NewTeleporterTransform); %VectorBetween = VectorSub(%TeleporterPosition, %NewTeleporterPosition); %Distance = VectorLen(%VectorBetween); // Load the Teleporters Properties %FirstTeleportTime = %Data.TeleportTime / 2; %SecondTeleportTime = %Data.TeleportTime / 2; // Make the Teleport Time a factor of Distance %FirstTeleportTime += %Distance / 2; %SecondTeleportTime += %Distance / 2; // Make the Teleport Time a factor of Mass %MassFactor = 1 + ((%Player.getDataBlock().Mass - 90) / 180); %Pack = %Player.getMountedImage($BackpackSlot); if(%Pack.isLarge) %MassFactor = %MassFactor + 0.2; %FirstTeleportTime *= %MassFactor; %SecondTeleportTime *= %MassFactor; %Delay = %Data.TeleportDelay; %FirstTeleportDelay = %FirstTeleportTime - %Delay; %SecondTeleportDelay = %SecondTeleportTime - %Delay; // Take Control from the player %Client.camera.setTransform(%TeleporterTransform); %Client.camera.setOrbitMode(%Player, %TeleporterTransform, 0.5, 4.5, 4.5); // schedule special effects %Player.schedule(%FirstTeleportDelay, playAudio, $PlaySound, TeleportSound); %Player.schedule(%FirstTeleportTime + 50, playAudio, $PlaySound, UnTeleportSound); // Schedule the Teleportation, Cloaking, and UnCloaking %Player.schedule(%FirstTeleportDelay, "setCloaked", true); %Player.schedule(%FirstTeleportTime, "setCloaked", false); %Player.schedule(%FirstTeleportTime, setTransform, %NewTeleporterTransform); // Schedule the Resuming Control of Players body %Player.EndTeleport = schedule(%FirstTeleportTime + %SecondTeleportTime, 0, EndTeleport, %Client); // Schedule the Teleport Reset schedule(%FirstTeleportTime + %SecondTeleportTime + 4000, %NextTeleporter, ResetTeleporter, %NextTeleporter); schedule(%FirstTeleportTime + %SecondTeleportTime + 4000, %Player.Teleporter, ResetTeleporter, %Player.Teleporter); %NextTeleporter.playThread($ActivateThread, "activate"); %NextTeleporter.setThreadDir($ActivateThread, false); } function HavocTeleporter::TeleFixCheck(%Data, %Teleporter) { if (%Teleporter.getDamageLevel() > %Data.disabledLevel) { %Teleporter.TeleFixCheck = %Teleporter.schedule(1000, TeleFixCheck, %Teleporter); return; } // Delete the inactive cap if (%Teleporter.Cap > 0) %Teleporter.Cap.delete(); // Place the active one. %Position = posFromTransform(%Teleporter.getTransform()); %PositionXY = getWords(%Position, 0, 1); %PositionZ = getWord(%Position, 2); %Position = %PositionXY @ " " @ %PositionZ + 0.22; %Item = new ScopeAlwaysShape() { dataBlock = "HavocTeleporterCapActive"; position = %Position; }; MissionCleanup.add(%Item); // Relink the Cap %Item.Teleporter = %Teleporter; %Teleporter.Cap = %Item; %Item.playThread(0, "deploy"); } // ------------------------------------------------------------------------ // Associated Functions // ------------------------------------------------------------------------ // This function makes a teleporter where specified and then // returns the Object reference to the new teleporter function createTeleporter(%Position, %Team, %HavocID, %Group) { if (%HavocID != $HavocTeleporterID) return; // If nothing was passed for Team we make it universal. if (%Team $= "" || %Team > 2) %Team = 0; // If too many teleporters are in Use, then ignore this and let the player know switch(%Team) { case 0 : if ($Team0TeleporterCount >= $TeamTeleporterMax) { error("Too many teleporters."); return(0); } $Team0TeleporterCount++; case 1 : if ($Team1TeleporterCount >= $TeamTeleporterMax) { error("Too many teleporters."); return(0); } $Team1TeleporterCount++; case 2 : if ($Team2TeleporterCount >= $TeamTeleporterMax) { error("Too many teleporters."); return(0); } $Team2TeleporterCount++; } %Teleporter = new StaticShape() { dataBlock = "HavocTeleporter"; team = %Team; position = %Position; }; %Group.add(%Teleporter); %Teleporter.Group = %Group; %Teleporter.UsedBy = 10; %Teleporter.Init = %Teleporter.getDataBlock().schedule(2500, Init, %Teleporter, %Player.client); %Teleporter.setRechargeRate(%Teleporter.getDatablock().rechargeRate); %Teleporter.getDataBlock().createTrigger(%Teleporter); %Teleporter.TeleporterNo = RegisterTeleporter(%Teleporter, %Team); return(%Teleporter); } // This function assigns the newest teleporter to the team in question. function RegisterTeleporter(%Teleporter, %Team) { %i = 1; %TeleportersChecked = 1; switch(%Team) { case 0 : while (%i <= $TeamTeleporterMax) { // Check to see if it deployed if ($Team0Teleporter[%i] <= 0) { $Team0Teleporter[%i] = %Teleporter; return(%i); } %i++; } $Team0TeleporterCount--; return(0); case 1 : while (%i <= $TeamTeleporterMax) { // Check to see if it deployed if ($Team1Teleporter[%i] <= 0) { $Team1Teleporter[%i] = %Teleporter; return(%i); } %i++; } $Team1TeleporterCount--; return(0); case 2 : while (%i <= $TeamTeleporterMax) { // Check to see if it deployed if ($Team2Teleporter[%i] <= 0) { $Team2Teleporter[%i] = %Teleporter; return(%i); } %i++; } $Team2TeleporterCount--; return(0); } } // This function locates the latest teleporter which can be used and returns either // 0 for not found or the Teleporter Object number if found. function FindNextTeleporter(%CurrentTeleporter) { %Team = %CurrentTeleporter.team; %TeleporterNo = %CurrentTeleporter.TeleporterNo; %i = %TeleporterNo; %TeleportersChecked = 1; switch(%Team) { case 0 : while (%TeleportersChecked <= $TeamTeleporterMax) { %TeleportersChecked++; %i++; if (%i > $TeamTeleporterMax) %i = 1; %Teleporter = $Team0Teleporter[%i]; // Check to see if it deployed, disabled, or inUse if (%Teleporter <= 0 || %Teleporter.isDisabled() == true || %Teleporter.UsedBy > 0) continue; // Check to see if it is powered. if (%Teleporter.NeedsPower == true && %Teleporter.isPowered() == false) continue; // Otherwise return the teleporter return($Team0Teleporter[%i]); } // None Found return(0); case 1 : while (%TeleportersChecked <= $TeamTeleporterMax) { %TeleportersChecked++; %i++; if (%i > $TeamTeleporterMax) %i = 1; %Teleporter = $Team1Teleporter[%i]; // Check to see if it deployed, disabled, or inUse if (%Teleporter <= 0 || %Teleporter.isDisabled() == true || %Teleporter.UsedBy > 0) continue; // Check to see if it is powered. if (%Teleporter.NeedsPower == true && %Teleporter.isPowered() == false) continue; // Otherwise return the teleporter return($Team1Teleporter[%i]); } // None Found return(0); case 2 : while (%TeleportersChecked <= $TeamTeleporterMax) { %TeleportersChecked++; %i++; if (%i > $TeamTeleporterMax) %i = 1; %Teleporter = $Team2Teleporter[%i]; // Check to see if it deployed, disabled, or inUse if (%Teleporter <= 0 || %Teleporter.isDisabled() == true || %Teleporter.UsedBy > 0) continue; // Check to see if it is powered. if (%Teleporter.NeedsPower == true && %Teleporter.isPowered() == false) continue; // Otherwise return the teleporter return($Team2Teleporter[%i]); } // None Found return(0); } } // This function determines wheither a player can active the trigger based // on the team of the player and trigger. function TriggerCheck(%Trigger, %Player) { if (%Trigger.Teleporter.team == 0) return(true); if (%Trigger.Teleporter.team == %Player.team) return(true); return(false); } // This function restores the players movement. function EndTeleport(%Client) { // If the player is dead, then don't bother if (%Client.player.getDamageState() $= "Destroyed") return; messageClient(%Client, 'MsgCantSitHere', 'Teleportation Complete.'); %Client.EndTeleport = 0; %Client.Player.setMoveState(false); %Client.player.mountImage(%Client.player.lastWeapon, $WeaponSlot); schedule(2500, 0, ResetPlayer, %Client.player); } // This function makes the player able to teleport again function ResetPlayer(%Player) { %Player.CantTeleport = false; } // This function makes the teleporter available again. function ResetTeleporter(%Teleporter) { %Teleporter.stopThread($ActivateThread); %Teleporter.UsedBy -= 10; if (%Teleporter.UsedBy < 0) %Teleporter.UsedBy = 0; } // Scans through a given group looking for a teleporter and recurses down // through other groups if possible. function TeleporterScanGroup(%Group) { %i = 0; %GroupCount = %Group.getCount(); while (%i <= %GroupCount) { %Object = %Group.getObject(%i); %Name = %Object.getName(); if (%Name $= "") %Name = %Object.getDataBlock().getName(); if (%Name $= "MPBTeleporter") { // If a teleporter then replace it. %Position = posFromTransform(%Object.getTransform()); %Team = %Object.team; %Teleporter = CreateTeleporter(%Position, %Team, $HavocTeleporterID, %Group); %Teleporter.NeedsPower = %Object.NeedsPower; if (%Object.DontDelete == 0) %Teleporter.DontDelete = false; else %Teleporter.DontDelete = true; %Object.delete(); } else { // Try to scan further if (%Object.isObject() == false) { %Count = %Object.getCount(); if (%Count > 0) TeleporterScanGroup(%Object); } } %i++; } return; } // Because we must launch this code after the mission has loaded and // the game is started, we wait for $MissionRunning to be set true. function TeleporterStartCheck() { if ($missionRunning == false) { schedule(5000, 0, TeleporterStartCheck); return; } schedule(5000, 0, TeleporterStart); } // Latest patch requires this to be seperate. function TeleporterStart() { InitializeHavocTeleporters(); error("Special Thanks to the Havoc 2 DEV team."); } // Scan through the Mission Group and then transmit the new teleporter info to the clients function InitializeHavocTeleporters() { // Scan the mission group now. TeleporterScanGroup(MissionGroup); // Transmit DataBlocks to the Clients currently connected to the server. %ClientCount = clientGroup.getCount(); %i = 0; %Client = clientGroup.getObject(%i); while (%Client > %ClientCount) { %Client.transmitDataBlocks(1); %i++; %Client = clientGroup.getObject(%i); } } TeleporterStartCheck();