---------------------------------------------------------------------------------------------------------------
Spy Satellite Tutorial
---------------------------------------------------------------------------------------------------------------
This creates a deployable spy satellite (camera) that sits way up in the air invisible. When you aim at the ground and fire, it repositions itself above where you aimed at. Can be used for early warning, spying on enemy base, coordinating attacks, ect.
Step #1
// ------------------------------------------
// defaultGame.cs
// ------------------------------------------

function DefaultGame::clearDeployableMaxes(%game)
{

      $TeamDeployedCount[%i, SpySatelliteDeployable] = 0;

}

Step #2
// ------------------------------------------
// deployables.cs
// ------------------------------------------

2a)Near the top of the file add this:

$TeamDeployableMax[SpySatelliteDeployable] = 2;


Step #3
// ------------------------------------------
// inventoryHud.cs
// ------------------------------------------
Add this near the top of the file:

$InvPack[18] = "Spy Satellite";
$NameToInv["Spy Satellite"] = "SpySatelliteDeployable";


Step #4
// ------------------------------------------
// pack.cs
// ------------------------------------------
exec("scripts/packs/SpySatellite.cs");


Step #5
// ------------------------------------------
// player.cs
// ------------------------------------------

6a) In each player datablock add this. Since it's a deployable, only mediums and heavies need it.
   max[SpySatelliteDeployable] = 1;

Step #6
// ------------------------------------------
// SpySatellite.cs
// ------------------------------------------
Add all this into a file called SpySatellite.cs in your packs directory.


datablock TurretData(DeployedSpySatellite) : TurretDamageProfile
{
   shapeFile = "turret_indoor_deployc.dts";
   heatSignature = 0.0;
   deployedObject = true;
   primaryAxis = revzaxis;
   className = DeployedTurret;
   mass = 0.7;
   maxDamage = 0.2;
   destroyedLevel = 0.2;
   disabledLevel = 0.2;
   explosion      = CameraGrenadeExplosion;
   repairRate = 0;
   heatSignature = 0.0;
   deployedObject = true;
   thetaMin = 120;
   thetaMax = 180;
   thetaNull = 180;
   primaryAxis = zaxis;
   isShielded = false;
   energyPerDamagePoint = 40;
   maxEnergy = 30;
   rechargeRate = 0.05;
   barrel = SpySatelliteBarrel;
   canControl = true;
   canObserve = true;
   cmdCategory = "DSupport";
   cmdIcon = CMDCameraIcon;
   cmdMiniIconName = "commander/MiniIcons/com_camera_grey";
   targetNameTag = 'Spy';
   targetTypeTag = 'Satellite';
   sensorData = CameraSensorObject;
   sensorRadius = CameraSensorObject.detectRadius;
   firstPersonOnly = true;
   renderWhenDestroyed = false;
   observeParameters = "0.5 4.5 4.5";
   debrisShapeName = "debris_generic_small.dts";
   debris = TurretDebrisSmall;
};

datablock TurretImageData(SpySatelliteBarrel)
{
   shapeFile = "turret_muzzlepoint.dts";
   item      = SpySatelliteBarrel;

   // Turret parameters
   activationMS      = 150;
   deactivateDelayMS = 300;
   thinkTimeMS       = 150;
   degPerSecTheta    = 580;
   degPerSecPhi      = 960;
   attackRadius      = 1;

   // State transitions
   stateName[0]                     = "Activate";
   stateTransitionOnTimeout[0]      = "ActivateReady";
   stateTimeoutValue[0]             = 0.5;
   stateSequence[0]                 = "Activate";

   stateName[1]                     = "ActivateReady";
   stateTransitionOnLoaded[1]       = "Ready";
   stateTransitionOnNoAmmo[1]       = "NoAmmo";

   stateName[2]                     = "Ready";
   stateTransitionOnTriggerDown[2]  = "Fire";

   stateName[3]                     = "Fire";
   stateTransitionOnTimeout[3]      = "Reload";
   stateTimeoutValue[3]             = 0.5;
   stateFire[3]                     = true;
   stateAllowImageChange[3]         = false;
   stateSequence[3]                 = "Fire";
   stateScript[3]                   = "onFire";

   stateName[4]                     = "Reload";
   stateTransitionOnTimeout[4]      = "Ready";
   stateTimeoutValue[4]             = 0.5;
   stateAllowImageChange[4]         = false;
};

function SpySatelliteBarrel::onFire(%data,%obj,%slot)
{
   %range = 1000; //Max range It can move.
   %rot = rotFromTransform(%obj.getTransform());
   %muzzlePos = %obj.getMuzzlePoint(%slot);
   %muzzleVec = %obj.getMuzzleVector(%slot);
   %endPos    = VectorAdd(%muzzlePos, VectorScale(%muzzleVec, %range));
   %damageMasks = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType |
                  $TypeMasks::StationObjectType | $TypeMasks::GeneratorObjectType |
                  $TypeMasks::SensorObjectType | $TypeMasks::TurretObjectType |
                  $TypeMasks::InteriorObjectType;

   %terrain = ContainerRayCast(%muzzlePos, %endPos, $TypeMasks::TerrainObjectType, %obj);
   %message = "";
   if (%terrain)
   {
      %xy = getWords(%terrain, 1, 2);
      %z = getWord(%terrain, 3);
      %pos = %xy SPC %z + 200;
      %mask =    ($TypeMasks::VehicleObjectType     | $TypeMasks::MoveableObjectType   |
                  $TypeMasks::StaticShapeObjectType |
                  $TypeMasks::ForceFieldObjectType  | $TypeMasks::ItemObjectType       |
                  $TypeMasks::PlayerObjectType      | $TypeMasks::TurretObjectType);
      InitContainerRadiusSearch( %pos, 2, %mask );
      %test = containerSearchNext();
      if (%test)
         %message = "Can\'t reposition the satellite. Trajectory Blocked";
      else
      {
         %obj.setTransform(%pos SPC %rot);
      }
   }
   else
      %message = "Trajectory not understood. Reenter.";
   if (%message !$= "")
      messageClient(%obj.client, 'msgBlocked', %message);
}


datablock ShapeBaseImageData(SpySatelliteDeployableImage)
{
   shapeFile = "pack_deploy_sensor_pulse.dts";
   item = SpySatelliteDeployable;
   mountPoint = 1;
   offset = "0 0 0";
   deployed = DeployedSpySatellite;

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

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

   maxDepSlope = 40;
   emap = true;
   heatSignature = 0;

   minDeployDis                       =  0.1;
   maxDeployDis                       =  15.0;  //meters from body
};

datablock ItemData(SpySatelliteDeployable)
{
   className = Pack;
   catagory = "Deployables";
   shapeFile = "pack_deploy_sensor_pulse.dts";
   mass = 2.0;
   elasticity = 0.2;
   friction = 0.6;
   pickupRadius = 1;
   rotate = false;
   image = "SpySatelliteDeployableImage";
   pickUpName = "a spy sattelite pack";

   computeCRC = true;
   emap = true;
};

function SpySatelliteDeployableImage::testObjectTooClose(%item)
{
   %xy = getWords(%item.surfacePt, 0, 1);
   %z = getWord(%item.surfacePt, 2);
   %z += 200;
   %item.surfacePt = %xy SPC %z;
   %item.surfaceNrm = "0 0 -1";
   %mask =    ($TypeMasks::VehicleObjectType     | $TypeMasks::MoveableObjectType   |
               $TypeMasks::StaticShapeObjectType |
               $TypeMasks::ForceFieldObjectType  | $TypeMasks::ItemObjectType       |
               $TypeMasks::PlayerObjectType      | $TypeMasks::TurretObjectType);
   InitContainerRadiusSearch( %item.surfacePt, $MinDeployDistance, %mask );
   %test = containerSearchNext();
   return %test;
}

function SpySatelliteDeployableImage::onDeploy(%item, %plyr, %slot)
{
   %deplObj = Parent::onDeploy(%item, %plyr, %slot);
   %deplObj.setCloaked(true);
   %deplObj.setPassiveJammed(true);
}

function SpySatelliteDeployable::onPickup(%this, %obj, %shape, %amount)
{
   // created to prevent console errors
}

function DeployedSpySatellite::onDestroyed(%this, %obj, %prevState)
{
   Parent::onDestroyed(%this, %obj, %prevState);
   $TeamDeployedCount[%obj.team, SpySatelliteDeployable]--;
   %obj.schedule(500, "delete");
}