
// ------------------------------------------------------------------------
// Deployed Object
// ------------------------------------------------------------------------

datablock ShapeBaseImageData(TeleporterImage)
{
   mass = 25;
   emap = true;

   shapeFile = "stackable4l.dts";
   item = TeleporterPack;
   deployed = MidTeleporter;

   mountPoint = 1;
   offset = "0 -0.2 -0.75";

   stateName[0] = "Idle";
   stateTransitionOnTriggerDown[0] = "Activate";

   stateName[1] = "Activate";
   stateScript[1] = "onActivate";
   stateTransitionOnTriggerUp[1] = "Idle";

   isLarge = true;
   maxDepSlope = 15;
   deploySound = StationDeploySound;
};

datablock ItemData(TeleporterPack)
{
   className = Pack;
   catagory = "Deployables";
   shapeFile = "stackable4l.dts";

   scale = "1.0 1.0 0.8";

   mass = 25;
   elasticity   = 0.2;
   friction     = 0.6;
   pickupRadius = 2;
   rotate       = true;
   image        = "TeleporterImage";
   pickUpName = "an undeployed teleporter pad";

   computeCRC = true;
};

datablock StaticShapeData(MidTeleporter)
{
   className = Pack;
   catagory = "Deployables";
   shapeFile = "stackable4l.dts";

   scale = "1.85 1.85 0.4";

   mass = 25;
   elasticity   = 0.2;
   friction     = 0.6;
   pickupRadius = 0;
   rotate       = true;

   deployedObject = true;

   image = TeleporterImage;
   item = TeleporterPack;

   computeCRC = true;
};

function MidTeleporter::onAdd(%data, %Item, %Position)
{
   // Signal the creation of the new Teleporter
   schedule(450, 0, MakeTeleporter, %Item);

   // Delete the mid point deploy place holder
   %Item.schedule(900, delete);
}

function MakeTeleporter(%BasedOn)
{
   %Client = %BasedOn.owner;
   %Player = %Client.player;
   %Team = %Client.team;

   %Position = posFromTransform(%BasedOn.getTransform());

   // Try to place the teleporter, if you can then do it.
   %Teleporter = createTeleporter(%Position, %Team, %Player, "");
   if (%Teleporter == 0)
   {
      // If you can't make a new one then repack the object and keep it on the ground.
      %NewItem = new Item()
      {
         dataBlock = TeleporterPack;
         position = %Position;
      };
      MissionCleanup.add(%NewItem);

      %NewItem.ApplyImpulse(%Position, "0 0 10");

      $TeamDeployedCount[%Team, TeleporterPack]--;

      return;
   }

   // take the deployable off the player's back and out of inventory
   %Player.unmountImage(%slot);
   %Player.decInventory(%BasedOn.Item, 1);  

   %Teleporter.Beacon = MakeTeamWaypoint(%Teleporter.getWorldBoxCenter(), %Team, 0, false);
   
   // play the deploy sound
   serverPlay3D(%BasedOn.deploySound, %Teleporter.getTransform());

   %Teleporter.target = createTarget(%Teleporter, "", "", "", %Teleporter.getDataBlock().targetTypeTag, %Teleporter.Team, 0);
   setTargetSensorGroup(%Teleporter.getTarget(), %Teleporter.Team);

   %Teleporter.owner = %client;

   return(%Teleporter);
}



datablock StaticShapeData(Teleporter) : StaticShapeDamageProfile
{  
   className = Station;
   catagory = "Stations";
   shapeFile = "station_teleport.dts";

   image = TeleporterImage;
   item = TeleporterPack;

   Name = "teleport pad";

   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;

   scale = "0.8 0.8 1.2";

   doesRepair = true;
 
   isShielded = true;
   energyPerDamagePoint = 60;
   maxEnergy = 100;
   rechargeRate = 0.05;

   debrisShapeName = "debris_generic.dts";
   debris = StationDebris;
 
   humSound = StationTeleportHumSound;

   targetNameTag = 'Teleporter';
   targetTypeTag = 'Teleport Pad';
   teleporter = true;

   TeleportTime = 2000;
   TeleportDelay = 850;
};

datablock StaticShapeData(TeleporterCapActive) : 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.8";
   lightTime = "4000";
   lightRadius = "1.75";
};

datablock StaticShapeData(TeleporterCapDisabled) : 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.8";
   lightTime = "4000";
   lightRadius = "0.1";
};

function Teleporter::onDestroyed(%this, %Teleporter, %prevState)
{
   if (%Teleporter.Cap > 0)
       %Teleporter.Cap.delete();

   // We have not said to not delete it, then we delete it.
   if (%Teleporter.DontDelete == false || %Teleporter.DontDelete $= "")
   {
     $TeamDeployedCount[%Teleporter.team, TeleporterPack]--;
     if ($TeamDeployedCount[%Teleporter.team, TeleporterPack] < 0)
        $TeamDeployedCount[%Teleporter.team, TeleporterPack] = 0;

      // Mark the teleporter slot as available and decrement team count
      switch (%Teleporter.team)
      {
         case 0 :
            $Team0TeleporterCount--;
            $Team0Teleporter[%Teleporter.TeleporterNo] = 0;

         case 1 :
            $Team1TeleporterCount--;
            $Team1Teleporter[%Teleporter.TeleporterNo] = 0;

         case 2 :
            $Team2TeleporterCount--;
            $Team2Teleporter[%Teleporter.TeleporterNo] = 0;
      }

      if (%Teleporter.HackerTrigger !$= "")
         %Teleporter.HackerTrigger.delete();

      if (%Teleporter.Trigger !$= "")
         %Teleporter.Trigger.delete();

      if (%Teleporter.Beacon !$= "")
         %Teleporter.Beacon.delete();

     %Teleporter.schedule(450, delete);
   } 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 = "TeleporterCapDisabled";
         position = %Position;
      };
      MissionCleanup.add(%Item);

      // Relink the non-flashing cap.
      %Item.Teleporter = %Teleporter;
      %Teleporter.Cap = %Item;

      %Teleporter.TeleFixCheck = %Teleporter.schedule(1000, TeleFixCheck, %Teleporter);
   }

   if (%Teleporter.Beacon !$= "")
      %Teleporter.Beacon.delete();

   // If destroyed before it could be initialized, don't bother initializing.
   if (%Teleporter.Init !$= "")
      Cancel(%Teleporter.Init);
}

function Teleporter::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 = "TeleporterCapActive";
      position = %Position;
   };
   MissionCleanup.add(%Item);

   // Relink the Cap
   %Item.Teleporter = %Teleporter;
   %Teleporter.Cap = %Item;

   %Item.playThread(0, "deploy");
}

// This function makes a teleporter where specified and then
// returns the Object reference to the new teleporter
function createTeleporter(%Position, %Team, %Player, %Group)
{
   if (%Player.InWater == true)
   {
      messageClient(%Player.client, 'msgStationDisabled', '\c2Teleporter may not be submerged!');
      return(0);
   }

   // If nothing was passed for Team we make it universal.
   if (%Team $= "" || %Team > 2)
      %Team = 0;

   if (FindClosestTeleporter(%Position, %Team) <= 20)
   {
      if (%Player.client > 0)
         messageClient(%Player.client, 'msgStationDisabled', '\c2You can not place it that close to another teleporter!');
      return(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++;
   }

   if (%Group $= "")
   {
      %DeployableGroup = nameToID("MissionCleanup/Deployables");
      if (%DeployableGroup <= 0)
      {
         %DeployableGroup = new SimGroup("Deployables");
         MissionCleanup.add(%DeployableGroup);
      }

      %Group = %DeployableGroup;
   }

   %Teleporter = new StaticShape()
   {
      dataBlock = "Teleporter";
      team = %Team;
      position = %Position;
      owner = %Player.client;
   };                
   %Group.add(%Teleporter);
   %Teleporter.Group = %Group;

   if (%Player = 0 || %Player $= "")
      %Teleporter.CantRepack = true;

   %Teleporter.UsedBy = 10;
   %Teleporter.Init = %Teleporter.getDataBlock().schedule(2500, Init, %Teleporter, %Player.client);
   %Teleporter.getDataBlock().createTrigger(%Teleporter);
   %Teleporter.TeleporterNo = RegisterTeleporter(%Teleporter, %Team);

   if (%Teleporter.TeleporterNo > 0 && %Teleporter.Name $= "")
      %Teleporter.Name = "Teleporter " @ %Teleporter.TeleporterNo;  

   %Teleporter.NoRepack = true;
   schedule(2000, 0, ClearRepack, %Teleporter);

   return(%Teleporter);
}

// This starts the teleporter special effect and also makes it usable.
function Teleporter::Init(%Data, %Teleporter, %Client)
{
   %Position = posFromTransform(%Teleporter.getTransform());
   %PositionXY = getWords(%Position, 0, 1);
   %PositionZ = getWord(%Position, 2);
   %Position = %PositionXY @ " " @ %PositionZ + 0.22;
   %Item = new ScopeAlwaysShape()
   {
      dataBlock = "TeleporterCapActive";
      position = %Position;
   };
   MissionCleanup.add(%Item);

   %Item.Teleporter = %Teleporter;
   %Teleporter.Cap = %Item;

   %Teleporter.UsedBy -= 12;
   
   if (%Teleporter.UsedBy < 0)
      %Teleporter.UsedBy = 0;

   %Teleporter.Cap.playThread(0, "deploy");

   %Teleporter.setRechargeRate(%Data.rechargeRate);

   // Notify whoever placed it that thier teleporter is ready.
   if (%Client > 0)
   {
      messageClient(%Client, 'msgStationDisabled', '\c2Teleporter Ready!');
   }

   %Teleporter.Init = "";
}

// This function assigns the newest teleporter to the team in question.
function RegisterTeleporter(%Teleporter, %Team)
{
   %i = 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);

   }
}

function Teleporter::createTrigger(%this, %Teleporter)
{
   %Group = %Teleporter.Group;

   %Transform = %Teleporter.getTransform();
   %Trigger = new Trigger()
   {
      dataBlock = TeleporterTrigger;
      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;

   %HackerTrigger = new Trigger()
   {
      dataBlock = HackersTeleportTrigger;
      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(%HackerTrigger);

   %HackerTrigger.Teleporter = %Teleporter;
   %Teleporter.HackerTrigger = %HackerTrigger;
}

// This function returns the distance of the closest teleporter for the team
function FindClosestTeleporter(%Position, %Team)
{
   %Distance = 99999;

   %i = %TeleporterNo;
   %TeleportersChecked = 1;
   switch(%Team)
   {
      case 0 :
         while (%TeleportersChecked <= $TeamTeleporterMax)
         {
            %TeleportersChecked++;
            %i++;
            if (%i > $TeamTeleporterMax)
               %i = 1;

            // Check to see if it deployed
            if ($Team0Teleporter[%i] <= 0)
               continue;

            // Check the distance between here and the teleporter
            %Teleporter = $Team0Teleporter[%i];
            %TeleporterPosition = posFromTransform(%Teleporter.getTransform());

            %VectorBetween = VectorSub(%Position ,%TeleporterPosition);
            %TeleporterDistance = VectorLen(%VectorBetween);

            if (%TeleporterDistance <= %Distance)
               %Distance = %TeleporterDistance;
         }

      case 1 :
         while (%TeleportersChecked <= $TeamTeleporterMax)
         {
            %TeleportersChecked++;
            %i++;
            if (%i > $TeamTeleporterMax)
               %i = 1;

            // Check to see if it deployed
            if ($Team1Teleporter[%i] <= 0)
               continue;

            // Check the distance between here and the teleporter
            %Teleporter = $Team1Teleporter[%i];
            %TeleporterPosition = posFromTransform(%Teleporter.getTransform());

            %VectorBetween = VectorSub(%Position ,%TeleporterPosition);
            %TeleporterDistance = VectorLen(%VectorBetween);

            if (%TeleporterDistance <= %Distance)
               %Distance = %TeleporterDistance;
         }

      case 2 :
         while (%TeleportersChecked <= $TeamTeleporterMax)
         {
            %TeleportersChecked++;
            %i++;
            if (%i > $TeamTeleporterMax)
               %i = 1;

            // Check to see if it deployed
            if ($Team2Teleporter[%i] <= 0)
               continue;

            // Check the distance between here and the teleporter
            %Teleporter = $Team2Teleporter[%i];
            %TeleporterPosition = posFromTransform(%Teleporter.getTransform());

            %VectorBetween = VectorSub(%Position ,%TeleporterPosition);
            %TeleporterDistance = VectorLen(%VectorBetween);

            if (%TeleporterDistance <= %Distance)
               %Distance = %TeleporterDistance;
         }
   }

   // Return distance found
   return(%Distance);
}


// 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;

   %Data = %CurrentTeleporter.getDataBlock();

   %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.getDamageLevel() > %Data.disabledLevel) || %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.getDamageLevel() > %Data.disabledLevel) || %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.getDamageLevel() > %Data.disabledLevel) || %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);
   }
}

function Teleporter::AttemptTeleport(%Data, %Player, %Teleporter, %Caught)
{
   if (%Caught $= "")
      %Caught = false;

   // Everything is good, teleport player.
   // Stop the Players Movement and fix them to the center of the teleport pad
   %Player.setVelocity("0 0 0");
   %Position = posFromTransform(%Teleporter.getTransform());
   %Player.setTransform(%Position);

   %NextTeleporter = FindNextTeleporter(%Teleporter);
   if (%NextTeleporter == 0 && %Caught == false)
   {
      messageClient(%Player.client, 'msgStationDisabled', '\c2No available Teleporters found.');
      return;
   }

   // Lock thier movement
   %Player.setMoveState(true);

   %Player.lastWeapon = %Player.getMountedImage($WeaponSlot);
   %Player.unmountImage($WeaponSlot);

   %Player.CantTeleport = true;
   %Teleporter.UsedBy = 10;
   if (%Caught == false)
      %NextTeleporter.UsedBy = 10;

   %Teleporter.setThreadDir($ActivateThread, True);
   %Teleporter.playThread($ActivateThread,"activate");	
   %Teleporter.playAudio($PlaySound, StationTeleportAcitvateSound);

   %Player.Teleporter = %Teleporter;

   if (%Caught == true)
      %Teleporter.getDataBlock().TeleportKill(%Player);
   else
      %Teleporter.getDataBlock().TeleportPlayer(%Player, %NextTeleporter, %Teleporter);
}

function Teleporter::TeleportKill(%Data, %Player)
{
   %Client = %Player.client;

   messageClient(%Client, 'MsgCantSitHere', 'Initiating Teleportation Sequence.');

   %Teleporter = %Player.Teleporter;
   %TeleporterTransform = %Player.getTransform(); 
   %TeleporterPosition = posFromTransform(%TeleporterTransform);

   // 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(500, playAudio, $PlaySound, TeleportSound);

   // Schedule the Teleportation, Cloaking, and UnCloaking
   %Player.schedule(500, "setCloaked", true);

   // Schedule the explosion of sparks
   schedule(800, 0, TeleporterSparks, %TeleporterPosition);

   // schedule the death of the player
   %Player.getDataBlock().schedule(1500, damageObject, %Player, 0, 0, 10000, 0, 0);
   %Player.schedule(1750, applyImpluse, %TeleporterPosition, "0 0 3500");

   // Schedule the Teleport Reset
   schedule(2500, %Player.Teleporter, ResetTeleporter, %Teleporter);

   // Schedule the sounding of the alarm
   schedule(1000, 0, TeamHackNotify, %Teleporter);

   %Teleporter.setEnergyLevel(%Energy - 8);
}

function Teleporter::TeleportPlayer(%Data, %Player, %NextTeleporter, %Teleporter)
{
   %Client = %Player.client;

   %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 - 60) / 120);

   %Pack = %Player.getMountedImage($BackpackSlot);
   if(%Pack.isLarge == true)
      %MassFactor = %MassFactor + 0.2;

   %FirstTeleportTime *= %MassFactor;
   %SecondTeleportTime *= %MassFactor;

   %Delay = %Data.TeleportDelay;
   %FirstTeleportDelay = %FirstTeleportTime - %Delay;
   %SecondTeleportDelay = %SecondTeleportTime - %Delay;

   %Energy = %Teleporter.getEnergyLevel();
   %EnergyNeeded = (%FirstTeleportTime + %SecondTeleportTime) / 100;
   if (%EnergyNeeded > %Energy)
   {
      if (%EnergyNeeded > %Teleporter.getDataBlock().maxEnergy)
         messageClient(%Player.client, 'msgStationDisabled', '\c2Teleporter does not have enough power to teleport you that far, even with full power!');
      else
      {
         messageClient(%Player.client, 'msgStationDisabled', '\c2Teleporter does not have enough power to teleport you that far, you need to wait for it to recharge!');

         if (%Teleporter.NotifySchedule !$= "")
            Cancel(%Teleporter.NotifySchedule);

         %Teleporter.NotifySchedule = %Teleporter.getDataBlock().schedule(2500, NotifyPlayer, %Player, %Teleporter, %EnergyNeeded);
      }

      %Player.CantTeleport = "";
      %Teleporter.UsedBy -= 12;
      %NextTeleporter.UsedBy -= 12;

      serverCmdUnlockPlayer(%Player.client);

      return;
   } else {
      messageClient(%Client, '', 'Initiating Teleportation Sequence.');
   }

   %Teleporter.setEnergyLevel(%Energy - %EnergyNeeded);

   %TeleporterPositionXY = getWords(%TeleporterPosition, 0, 1);
   %TeleporterPositionZ = getWord(%TeleporterPosition, 2) + 1.5;
   %TeleporterPosition2 = %TeleporterPositionXY @ " " @ %TeleporterPositionZ;

   %NewTeleporterPositionXY = getWords(%NewTeleporterPosition, 0, 1);
   %NewTeleporterPositionZ = getWord(%NewTeleporterPosition, 2) + 1.5;
   %NewTeleporterPosition2 = %NewTeleporterPositionXY @ " " @ %NewTeleporterPositionZ;

   // 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 effects
   schedule(350, 0, MakeTeleporterEffect, %TeleporterPosition, %FirstTeleportTime - 350);
   schedule(850, 0, MakeTeleporterEffect, %NewTeleporterPosition, %FirstTeleportTime - 850);
   schedule(%FirstTeleportTime - 700, 0, TeleporterSparks, %TeleporterPosition);
   schedule(%FirstTeleportTime - 700, 0, TeleporterSparks, %NewTeleporterPosition);

   // 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.setThreadDir($ActivateThread, True);
   %NextTeleporter.playThread($ActivateThread,"activate");	
}

function Teleporter::NotifyPlayer(%Data, %Player, %Teleporter, %EnergyNeeded)
{
   %Energy = %Teleporter.getEnergyLevel();
   if (%Energy > %EnergyNeeded)
   {
      if (isObject(%Player.client) == true)
      {
          messageClient(%Player.client, 'msgStationDisabled', '\c2The teleport pad now has enough power to teleport you.');         
          %Teleporter.NotifySchedule = "";
      }

      return;
   }

   %Teleporter.NotifySchedule = %Teleporter.getDataBlock().schedule(2500, NotifyPlayer, %Player, %Teleporter, %EnergyNeeded);
}

function EndTeleport(%Client)
{
   %Player = %Client.Player;

   // If the player is dead, then don't bother
   if (%Player.getDamageState() $= "Destroyed")
      return;

   messageClient(%Client, 'MsgCantSitHere', 'Teleportation Complete.');

   // Restore the Control of the Player's body (One of These will work);
   %Client.setControlObject(%Player);

   %this.EndTeleport = 0;

   // Let them move again
   %Player.setMoveState(false);

   %Player.schedule(4500, allowTeleport);

   %Player.Teleporter = "";
}

function Player::AllowTeleport(%Player)
{
   %Player.CantTeleport = "";
}

function ResetTeleporter(%Teleporter)
{
   %Teleporter.stopThread($ActivateThread);

   %Teleporter.UsedBy -= 12;

   if (%Teleporter.UsedBy < 0)
      %Teleporter.UsedBy = 0;
}

function Teleporter::ItemSwap(%Data, %Object)
{
   %Transform = %Object.getTransform();
   %Position = posFromTransform(%Transform);

   %Item = %Object.getDataBlock().item;

   %NewItem = new Item()
   {
      dataBlock = MidTeleporter;
      position = %Position;
   };
   MissionCleanup.add(%NewItem);
   %NewItem.schedule(1250, delete);

   %NewItem = new Item()
   {
      dataBlock = %Item;
      position = %Position;
   };
   MissionCleanup.add(%NewItem);

   if (%Object.Beacon !$= "")
      %Object.Beacon.delete();

   %Data.onDestroyed(%Object);

   %NewItem.schedulePop();
}

// This function sends information to the client about each teleporter
// and they are stored in a global array.
function serverCmdGetTeleporterList(%client)
{
   %Team = %client.team;

   %Teleporters = 0;
   %AtTeleporter = false;

   %i = 1;

   while (%i <= $TeamTeleporterMax)
   {
      if (%Team == 1)
         %Teleporter = $Team1Teleporter[%i];
      else
         %Teleporter = $Team2Teleporter[%i];
   
      // If the teleporter no longer exists or never did, send a signal to ignore it.
      // If the teleporter they are on is the same as the one the player is on, ignore it.
      if (isObject(%Teleporter) == false)
      {
         commandToClient(%client, 'SetTeleporterStatus', %i, "", "", "Destroyed", 0);

         %i++;

         continue;
      }

      %Energy = %Teleporter.getEnergyLevel();
      %MaxEnergy = %Teleporter.getDataBlock().maxEnergy;
      %PowerLevel = %Energy / %MaxEnergy * 100;

      %Owner = getTaggedString(%Teleporter.owner.name);

      // Tell the system to ignore the one we are on and set it as the current one.
      if (%client.player.Teleporter == %Teleporter)
      {
         %Name = %Teleporter.getName();
         if (%Name $= "")
            %Name = "Teleporter " @ %i;

         commandToClient(%client, 'SetCurrentTeleporter', %Name, %Owner, %PowerLevel);
         commandToClient(%client, 'SetTeleporterStatus', %i, %Name, %Owner, "Occupied", %PowerLevel);

         %AtTeleporter = true;

         %i++;

         continue;
      }

      %Name = %Teleporter.getName();
      if (%Name $= "")
         %Name = "Teleporter " @ %i;

      %Teleporters++;

      %Status = "Disabled";
      if (%Teleporter.getDamageLevel() < %Teleporter.getDataBlock().disabledLevel)
      {
         if (%Teleporter.UsedBy <= 0)
            %Status = "Ready";
         else
            %Status = "Occupied";
      }

      commandToClient(%client, 'SetTeleporterStatus', %i, %Name, %Owner, %Status, %PowerLevel);

      %i++;
   }

   if (%AtTeleporter == true)
   {
      // If the player always wants to see the Destination GUI, then go ahead and tell them to look
      // If the player only wants to see it if there is more than 1 teleport destination, let them look
      if (%Client.ChooseTeleport == 2 || (%Client.ChooseTeleport == 1 && %Teleporters == 1))
         commandToClient(%client, 'OpenTeleporterMenu');

      commandToClient(%Client, 'UpdateTeleportMenu');

      schedule(2250, 0, serverCmdGetTeleporterList, %client);
   }
}

function serverCmdSelectTeleporter(%Client, %TeleporterNo)
{
   %Player = %Client.player;

   // If the player is dead and has selected a teleport pad, ignore them
   // If the player is not permitted to teleport, then change that now
   if (%Player.getState() $= "Dead" || %Player.CantTeleport == true)
      return;

   %Teleporter = %Player.Teleporter;
   if (isObject(%Teleporter) == false)
      return;

   if (%Player.team == 1)
      %TargetTeleporter = $Team1Teleporter[%TeleporterNo];
   else
      %TargetTeleporter = $Team2Teleporter[%TeleporterNo];

   if (isObject(%TargetTeleporter) == false || %TargetTeleporter.getDamageLevel() > %TargetTeleporter.getDataBlock().disabledLevel)
   {
      messageClient(%Player.client, 'msgStationDisabled', '\c2Teleporter is disabled.');
      return;
   }

   if (%TargetTeleporter.NeedsPower == true && %TargetTeleporter.isPowered() == false)
   {
      messageClient(%Player.client, 'msgStationDenied', '\c2Teleport Station is not powered!');
      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");
   %Position = posFromTransform(%Teleporter.getTransform());
   %Player.setTransform(%Position);

   %Player.CantTeleport = true;

   // Lock thier movement
   %Player.setMoveState(true);

   %Player.lastWeapon = %Player.getMountedImage($WeaponSlot);
   %Player.unmountImage($WeaponSlot);

   %Teleporter.UsedBy = 10;

   %TargetTeleporter.UsedBy = 10;

   %Teleporter.setThreadDir($ActivateThread, True);
   %Teleporter.playThread($ActivateThread,"activate");	
   %Teleporter.playAudio($PlaySound, StationTeleportActivateSound);

   %Teleporter.getDataBlock().TeleportPlayer(%Player, %TargetTeleporter, %Teleporter);
}

function serverCmdUnlockPlayer(%Client)
{
   %Player = %Client.Player;

   // If the player is dead and has selected a teleport pad, ignore them
   if (%Player.getState() $= "Dead")
      return;

   // If the player is not permitted to teleport, then change that now
   if (%Player.CantTeleport == true)
      %Player.CantTeleport = "";

   %Teleporter = %Player.Teleporter;
   if (isObject(%Teleporter) == false)
      return;

   %Player.setMoveState(false);
}