
datablock SensorData(SkyBotSensor)
{
   detects = true;
   detectsUsingLOS = true;
   detectsPassiveJammed = false;
   detectsCloaked = false;
   detectionPings = true;
   detectRadius = 250;
};

datablock StaticShapeData(ParkedSkyBot) : StaticShapeDamageProfile
{
   className = Sensor;
   shapeFile = "deploy_sensor_pulse.dts";
   maxDamage = 0.2;
   destroyedLevel = 0.2;
   disabledLevel = 0.2;
   explosion = DeployablesExplosion;
   dynamicType = $TypeMasks::SensorObjectType;

   deployedObject = true;

   item = SensorBotDeployable;
   name = "Hovering Sensor Bot";

   cmdCategory = "DSupport";
   cmdIcon = CMDSensorIcon;
   cmdMiniIconName = "commander/MiniIcons/com_deploypulsesensor";

   targetNameTag = 'Hovering';
   targetTypeTag = 'Sensor Bot';

   sensorData = SkyBotSensor;
   sensorRadius = SkyBotSensor.detectRadius;
   sensorColor = "255 194 9";

   deployAmbientThread = true;

   debrisShapeName = "debris_generic_small.dts";
   debris = DeployableDebris;
   heatSignature = 0.6;
};

// This function creates a small cloud around the sky bot.
function ParkedSkyBot::onAdd(%Data, %SkyBot, %Position)
{
   parent::onAdd(%Data, %SkyBot, %Position);

   %Emitter = new ParticleEmissionDummy()
   {
      position = %Position;
      scale = "1.4 1.4 1.4";
      dataBlock = "defaultEmissionDummy";
      emitter = "CloudEmitter";
   };
   MissionCleanup.add(%Emitter);

   %SkyBot.Emitter = %Emitter;
   %Emitter.SkyBot = %SkyBot;
}

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

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

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

   $TeamDeployedCount[%Object.team, %Item]--;

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

   %Object.delete();

   %NewItem.schedulePop();
}

// This function tries to launch a deployed SkyBot, if it can't it will repack.
function LaunchSkyBot(%SkyBot)
{
   // Get the SkyBot's Current position and rotation
   %Transform = %SkyBot.getTransform();

   %Position = posFromTransform(%Transform);
   %Rotation = rotFromTransform(%Transform);

   // Get the owners information 
   // as the direction of take off.
   %Player = %SkyBot.owner.player;

   %PlayerTransform = %Player.getTransform();

   %PlayerPosition = posFromTransform(%PlayerTransform);
   %PlayerRotation = rotFromTransform(%PlayerTransform);

   // Get the 2D vector between the SkyBot and owner
   %VectorBetween = VectorSub(%PlayerPosition, %Position);
   %VectorBetween2D = getWords(%VectorBetween, 0, 1);

   // Add a vertical component in order to give it a 30 degree take off
   %LaunchVector = VectorNormalize(VectorAdd(%VectorBetween2D, "0 0 0.333"));

   // Check for any obstruction in the way.
   %CenterPosition = %SkyBot.getWorldBoxCenter();
   %EndPosition = VectorAdd(%CenterPosition, VectorScale(%LaunchVector, 350));
   %Result = ContainerRayCast(%CenterPosition, %EndPosition, $EverythingMask, %SkyBot);

   // If there is something in the way, attempt a 45 degree take off
   if (%Result !$= "")
   {
      // Add a vertical component in order to give it a 30 degree take off
      %LaunchVector = VectorNormalize(VectorAdd(%VectorBetween2D, "0 0 0.5"));

      // Check for any obstruction in the way.
      %EndPosition = VectorAdd(%CenterPosition, VectorScale(%LaunchVector, 300));
      %Result = ContainerRayCast(%CenterPosition, %EndPosition, $EverythingMask, %SkyBot);

      // If there is still something in the way, attempt a 60 degree take off
      if (%Result !$= "")
      {
         // Add a vertical component in order to give it a 30 degree take off
         %LaunchVector = VectorNormalize(VectorAdd(%VectorBetween2D, "0 0 0.667"));

         // Check for any obstruction in the way.
         %EndPosition = VectorAdd(%CenterPosition, VectorScale(%LaunchVector, 250));
         %Result = ContainerRayCast(%CenterPosition, %EndPosition, $EverythingMask, %SkyBot);

         // If there is still something in the way, abort take off.
         if (%Result !$= "")
         {
            // Draw a line for the player to see what the problem is
            %Beam = new TargetProjectile()
            {
               dataBlock = BasicTargeter;
               initialDirection = %LaunchVector;
               initialPosition  = %CenterPosition;
               sourceObject     = %Player;
            }
            MissionCleanUp.Add(%Beam);

            %Beam.schedule(2500, delete);

            %Message = "An obstruction has been detected in the launch path, aborting launch.";
            messageClient(%Player.client, '', %Message);

            %SkyBot.getDataBlock().schedule(2650, ItemSwap, %SkyBot);

            return;
         }
      }
   }

   // Have the wings on the SkyBot pop out (put them on)
   %Scale = SkyBotWings.Scale;
   if (%Scale $= "")
      %Scale = "1 1 1";

   %Wings = new Item()
   {
      dataBlock = SkyBotWings;
      scale = %Scale;
      position = "0 0 -10000";
   };
   %SkyBot.mountObject(%Wings, 1);

   // Start some special effects around the take off
   SkyBotTakeOffEffects(%Position);

   // Record information about the launch
   %SkyBot.LaunchVector = %LaunchVector;
   %SkyBot.LaunchPosition = %Position;

   // Send it into the sky.
   %LaunchingVector = VectorScale(%LaunchVector, 2400);
   %SkyBot.schedule(2500, applyImpulse, %Position, %LaunchingVector);

   schedule(3250, 0, MonitorSkyBotLaunch, %SkyBot);
}

function MonitorSkyBotLaunch(%SkyBot)
{
   // If no longer an object, just abort.
   if (isObject(%SkyBot) == false)
      return;

   // Get the Current Position of the spy bot
   %Position = posFromTransform(%SkyBot.getTransform());

   // Check under the SkyBot for any form of terrain or structure
   %EndPosition = VectorAdd(%Position, "0 0 -350");
   %Result = ContainerRayCast(%CenterPosition, %EndPosition, $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType | 16, %SkyBot);

   // If nothing was found, we may have gone too high
   if (%Result $= "")
   {
      // Check to see if anything at all is within 250 meters (our sensor's range);
      %Found = false;

      InitContainerRadiusSearch(%position, %radius, $EverythingMask);

      while ((%TargetObject = containerSearchNext()) != 0)
      {
         if (%TargetObject == %SkyBot)
            continue;

         %Found = true;
      }

      // There is something in range to monitor, attempt to park
      if (%Found == true)
      {
         StopSkyBot(%SkyBot);
         return;
      }
   }

   // Check the location and distance to the terrain, water, structure that was found.
   %ResultPosition = getWords(%Result, 1, 3);
   %Distance = VectorLen(VectorSub(%ResultPosition, %Position));

   // If the Distance is greater than 200 then we attempt to park the SkyBot.
   if (%Distance > 200)
   {
      StopSkyBot(%SkyBot);
      return;
   }

   // If the SkyBot has moved more than 500 meters from it's launch site, it should attempt to park
   %Distance = VectorLen(VectorSub(%Position, %SkyBot.LaunchPosition));
   if (%Distance > 500)
   {   
      StopSkyBot(%SkyBot);
      return;
   }

   // If it is still moving, push it some more
   %Vector = VectorScale(%SkyBot.LaunchVector, 650);
   %SkyBot.ApplyImpulse(%Position, %Vector);

   // Schedule another check
   schedule(850, 0, MonitorSkyBotLaunch, %SkyBot);
}

// This function attempts to stop the SkyBot by applying a backwards and slightly upwards thrust.
function StopSkyBot(%SkyBot)
{
   %Velocity = %SkyBot.getVelocity();

   %Speed = VectorLen(%Velocity);
   if (%Speed < 8)
   {
      ParkSkyBot(%SkyBot);
      return;
   }
   %ReverseVector = VectorScale(%Velocity, -0.8);
   %ReverseVector2D = getWords(%ReverseVector, 0, 1) @ " 0";
   %ForceVector = VectorAdd(%ReverseVector2D, "0 0 4");

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

   %SkyBot.ApplyImpulse(%Position, %ForceVector);

   schedule(650, 0, StopSkyBot, %SkyBot);
}

function ParkSkyBot(%SkyBot)
{
   // Freeze the movement of the bot so all future calculations are accurate.
   %SkyBot.setFrozenState(true);

   // Get the location of the movable bot
   %Transform = %SkyBot.getTransform();

   %NewBot = new StaticShape()
   {
      dataBlock = ParkedSkyBot;
   }
   MissionCleanUp.Add(%NewBot);

   %NewBot.setTransform(%Transform);

   %SkyBot.schedule(2500, delete);
}