
$File = "RepairDrone";

datablock ShapeBaseImageData(RDroneLight)
{
   shapeFile = "repair_patch.dts";
   mountPoint = 1;
   offset = "0 0.54 0.55";
   mass = 0.1;

   alwaysAmbient = false;
};

datablock ShapeBaseImageData(RDroneRear)
{
   shapeFile = "stackable2s.dts";
   mountPoint = 1;
   offset = "0 -0.2 -0.06";
   mass = 0.1;

   alwaysAmbient = false;
};

datablock ShapeBaseImageData(RepairDronePackImage)
{
   mass = 4;
   emap = true;

   shapeFile = "pack_barrel_missile.dts";

   item = RepairDronePack;

   mountPoint = 1;
   offset = "0 0 0";

   rotation = "0 1 0 90";

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

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

   maxDepSlope = 30;
};

function RepairDronePackImage::onDeploy(%Item, %Player, %Slot)
{
   // Try to place the drone, if you can then do it.
   %Position = %Item.surfacePt;
   %PositionXY = getWords(%Position, 0, 1);
   %PositionZ = getWord(%Position, 2) + 1.6;
   %Position = %PositionXY @ " " @ %PositionZ;

   %Position2 = VectorAdd(%Position, "0 0 100");

   %SearchResult = containerRayCast(%Position, %Position2, $EverythingMask, %Player);

   if (%SearchResult !$= "0")
   {
      messageClient(%Player.client, '', "Repair Drone must be deployed outside in the open.");   
      return;
   }

   %Transform = %Player.getTransform();
   %Rotation = rotFromTransform(%Transform);

   %Drone = CreateRepairDrone(%Position, %Rotation, %Player.client);

   // take the deployable off the player's back and out of inventory
   %Player.unmountImage(%Slot);
   %Player.decInventory(RepairDronePack, 1);  
   
   // play the deploy sound
   serverPlay3D(%Item.deploySound, %Position);

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

   // increment the team count for this deployed object
   $TeamDeployedCount[%Player.team, RepairDronePack]++;

   return(%Drone);  
}

datablock ItemData(RepairDronePack)
{
   className = Pack;
   catagory = "Deployables";

   shapeFile = "pack_barrel_missile.dts";
   mass = 4;

   elasticity = 0.2;
   friction = 0.6;
   pickupRadius = 2;

   rotate = false;

   image = RepairDronePackImage;
   pickUpName = "a repair drone";

   computeCRC = true;
   emap = true;
};

function CreateRepairDrone(%Position, %Rotation, %Owner)
{
   // Place the generator object and link it to the field
   %Drone = new FlyingVehicle()
   {
      dataBlock = RepairDrone;
      position  = %Position;
      rotation  = %Rotation;
      team      = %Owner.team;
      owner     = %Owner;
   };                
   %MissionCleanUp.add(%Drone);

   messageClient(%BasedOn.owner, '', "Repair Drone Deployed.");

   return(%Drone);
}

datablock FlyingVehicleData(RepairDrone) : ShrikeDamageProfile
{
   spawnOffset = "0 0 2";

   catagory = "Vehicles";
   shapeFile = "turret_missile_large.dts";
   multipassenger = false;
   computeCRC = true;

   numWeapons = 3;

   AlternateHUD = MortarBarrelLarge;

   debrisShapeName = "debris_generic_small.dts";
   debris = DeployableDebris;

   item = RepairDronePack;

   drag    = 0.15;
   density = 1.0;

   mountPose[0] = sitting;
   numMountPoints = 1;  
   isProtectedMountPoint[0] = true;
   cameraMaxDist = 15;
   cameraOffset = 2.5;
   cameraLag = 0.9;

   explosion = DeployablesExplosion;
   explosionDamage = 0;
   explosionRadius = 0;
   explosionImpulse = 0;

   maxDamage = 0.40;
   destroyedLevel = 0.40;

   isShielded = true;
   energyPerDamagePoint = 240;
   maxEnergy = 100;             // Afterburner and any energy weapon pool
   minDrag = 30;                // Linear Drag (eventually slows you down when not thrusting...constant drag)
   rotationalDrag = 900;        // Anguler Drag (dampens the drift after you stop moving the mouse...also tumble drag)
   rechargeRate = 0.25;

   maxAutoSpeed = 15;            // Autostabilizer kicks in when less than this speed. (meters/second)
   autoAngularForce = 400;       // Angular stabilizer force (this force levels you out when autostabilizer kicks in)
   autoLinearForce = 300;        // Linear stabilzer force (this slows you down when autostabilizer kicks in)
   autoInputDamping = 0.95;      // Dampen control input so you don't` whack out at very slow speeds
   
   // Maneuvering
   maxSteeringAngle = 5;         // Max radiens you can rotate the wheel. Smaller number is more maneuverable.
   horizontalSurfaceForce = 6;   // Horizontal center "wing" (provides "bite" into the wind for climbing/diving and turning)
   verticalSurfaceForce = 4;     // Vertical center "wing" (controls side slip. lower numbers make MORE slide.)
   maneuveringForce = 1800;      // Horizontal jets (W,S,D,A key thrust)
   steeringForce = 1200;         // Steering jets (force applied when you move the mouse)
   steeringRollForce = 600;      // Steering jets (how much you heel over when you turn)
   rollForce = 4;                // Auto-roll (self-correction to right you after you roll/invert)
   hoverHeight = 1.5;            // Height off the ground at rest
   createHoverHeight = 1;        // Height off the ground when created

   // Turbo Jet
   jetForce = 800;              // Afterburner thrust (this is in addition to normal thrust)
   minJetEnergy = 10;            // Afterburner can't be used if below this threshhold.
   jetEnergyDrain = 1.2;         // Energy use of the afterburners (low number is less drain...can be fractional)                                                                                                                                                                                                                                                                                          // Auto stabilize speed
   vertThrustMultiple = 3.0;
   maxForwardSpeed = 1000;

   ELFDrain  = 1.6;

   // Rigid body
   mass = 120;                   // Mass of the vehicle
   bodyFriction = 0;             // Don't mess with this.
   bodyRestitution = 0.5;        // When you hit the ground, how much you rebound. (between 0 and 1)
   minRollSpeed = 0;             // Don't mess with this.
   softImpactSpeed = 24;         // Sound hooks. This is the soft hit.
   hardImpactSpeed = 32;         // Sound hooks. This is the hard hit.

   // Ground Impact Damage (uses DamageType::Ground)
   minImpactSpeed = 30;          // If hit ground at speed above this then it's an impact. Meters/second
   speedDamageScale = 0.04;

   // Object Impact Damage (uses DamageType::Impact)
   collDamageThresholdVel = 25.0;
   collDamageMultiplier   = 0.02;

   minTrailSpeed = 2;           // The speed your contrail shows up at.
   trailEmitter = ContrailEmitter;
   forwardJetEmitter = FlyerJetEmitter;
   downJetEmitter = FlyerJetEmitter;

   jetSound         = ScoutSqueelSound;
   engineSound      = ScoutEngineSound;
   floatSound       = ScoutThrustSound;
   softImpactSound = SoftImpactSound;
   hardImpactSound = HardImpactSound;
   
   softSplashSoundVelocity = 10.0; 
   mediumSplashSoundVelocity = 15.0;   
   hardSplashSoundVelocity = 20.0;   
   exitSplashSoundVelocity = 10.0;
   
   exitingWater      = VehicleExitWaterMediumSound;
   impactWaterEasy   = VehicleImpactWaterSoftSound;
   impactWaterMedium = VehicleImpactWaterMediumSound;
   impactWaterHard   = VehicleImpactWaterMediumSound;
   waterWakeSound    = VehicleWakeMediumSplashSound; 
    
   dustEmitter = VehicleLiftoffDustEmitter;
   triggerDustHeight = 2.0;
   dustHeight = 0.5;

   damageEmitter[0] = LightDamageSmoke;
   damageEmitter[1] = HeavyDamageSmoke;
   damageEmitter[2] = DamageBubbles;
   damageEmitterOffset[0] = "0.0 -3.0 0.0 ";
   damageLevelTolerance[0] = 0.3;
   damageLevelTolerance[1] = 0.7;
   numDmgEmitterAreas = 1;

   minMountDist = 4;

   splashEmitter[0] = VehicleFoamDropletsEmitter;
   splashEmitter[1] = VehicleFoamEmitter;

   shieldImpact = VehicleShieldImpact;

   cmdCategory = "Tactical";
   cmdIcon = CMDFlyingScoutIcon;
   cmdMiniIconName = "commander/MiniIcons/com_scout_grey";

   targetNameTag = 'Repair Drone';
   targetTypeTag = 'Repair Drone';
   sensorData = VehiclePulseSensor;
   
   checkRadius = 5.5;
   observeParameters = "1 4 2";

   canControl = true;
};

datablock EnergyProjectileData(RepairBolt)
{
   emitterDelay        = -1;
   directDamage        = -0.035;
   velInheritFactor    = 0.5;

   explosion           = "BlasterExplosion";
   splash              = BlasterSplash;

   muzzleVelocity    = 30.0;
   drag = 0.05;

   dryVelocity       = 30.0;
   wetVelocity       = 30.0;

   elasticity = 0.99;	

   hasLight    = true;
   lightRadius = 2.0;
   lightColor  = "0.5 0.175 0.175";

   scale = "0.125 1.5 0.5";
   crossViewAng = 0.99;
   crossSize = 0.55;

   lifetimeMS     = 500;

   blurLifetime   = 0.2;
   blurWidth      = 0.25;
   blurColor = "0.4 0.0 0.0 1.0";

   texture[0] = "special/blasterBolt";
   texture[1] = "special/blasterBoltCross";
};

function RepairBolt::onCollision(%data, %Object, %Player)
{
   echo("Target Object: " @ %Player);

   %Player.applyRepair(0.05);
}

datablock ShapeBaseImageData(RepairDroneImage)
{
   className = WeaponImage;
   shapeFile = "turret_muzzlepoint.dts";

   offset = "0 2 0.5";

   projectile = RepairBolt;
   projectileType = EnergyProjectile;

   usesEnergy = true;
   fireEnergy = 4;
   minEnergy = 8;

   stateName[0] = "Activate";
   stateTransitionOnTimeout[0] = "ActivateReady";
   stateTimeoutValue[0] = 0.5;
   stateSequence[0] = "Activate";
   stateSound[0] = BlasterSwitchSound;

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

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

   stateName[3] = "Fire";
   stateTransitionOnTimeout[3] = "Ready";
   stateTimeoutValue[3] = 0.3;
   stateFire[3] = true;
   stateRecoil[3] = NoRecoil;
   stateAllowImageChange[3] = false;
   stateSequence[3] = "Fire";
   stateSound[3] = BlasterFireSound;
   stateScript[3] = "onFire";

   stateName[5] = "NoAmmo";
   stateTransitionOnAmmo[5] = "Ready";
   stateSequence[5] = "NoAmmo";
   stateTransitionOnTriggerDown[5] = "DryFire";
   
   stateName[6] = "DryFire";
   stateTimeoutValue[6] = 0.3;
   stateSound[6] = BlasterDryFireSound;
   stateTransitionOnTimeout[6] = "Ready";
};

// The Repair Drone needs its toys
function RepairDrone::onAdd(%this, %Vehicle)
{
   Parent::onAdd(%this, %Vehicle);

   %Vehicle.mountImage(RepairDroneImage, 2);

   %Vehicle.mountImage(RDroneLight, 1);
   %Vehicle.mountImage(RDroneRear, 3);

   %Vehicle.mountable = false;
 
   schedule(600, 0, SetControl, %Vehicle.owner, %Vehicle);

   %Position = posFromTransform(%Vehicle.owner.player.getTransform());

   schedule(3500, 0, CheckRDroneStatus, %Vehicle, %Position);
}

function CheckRDroneStatus(%Drone, %Position)
{
   if (isObject(%Drone) == false)
      return;

   %Transform = %Drone.getTransform();
   %DronePosition = posFromTransform(%Transform);

   %VectorBetween = VectorSub(%DronePosition, %Position);
   %Distance = VectorLen(%VectorBetween);

   if (%Distance > 350)
   {
      %Drone.setImageTrigger(1, false);

      messageClient(%Drone.owner, '', "Lost contact with Repair Drone.");   

      %Drone.setCloaked(true);
      %Drone.schedule(1000, delete);

      %Drone.owner.setControlObject(%Drone.owner.player);

      %Weapon = %Drone.owner.player.getMountedImage($WeaponSlot);
      %Item = %Weapon.UseCrossHair;
      if (%Item $= "")
         %Item = %Weapon.item;
      %Drone.owner.setWeaponsHudActive(%Item);

      $TeamDeployedCount[%Drone.team, RepairDronePack]--;

      return;
   }

   %ControlObject = %Drone.owner.getControlObject();
   if (%ControlObject != %Drone)
   {
      messageClient(%Drone.owner, '', "Repair Drone deactivated, ordering repack.");

      %Drone.setCloaked(true);

      %Random = getRandom();
      %Damage = %Drone.getDamageLevel();
      if (%Random > %Damage)
      {
         %Drone.getDataBlock().schedule(650, ItemSwap, %Drone);
         messageClient(%Drone.owner, '', 'Drone repacked successfully.');   
      } else {
         schedule(750, 0, detonateGrenade, %Drone);
         messageClient(%Drone.owner, '', 'Drone destroyed by compound damage while attempting to repack.');   
      }

      $TeamDeployedCount[%Drone.team, RepairDronePack]--;

      return;
   }

   if (%Distance > 225)
   {
      if (%Drone.NearEdge != true)
         messageClient(%Drone.owner, '', 'Nearing edge of control range.~wfx/misc/misc.error.wav');   

      %Drone.NearEdge = true;
   } else {
      %Drone.NearEdge = "";
   }

   schedule(2000, 0, CheckRDroneStatus, %Drone, %Position);   
}

function RepairDrone::onDestroyed(%this, %Drone, %prevState)
{
   %Weapon = %Drone.owner.player.getMountedImage($WeaponSlot);
   %Item = %Weapon.UseCrossHair;
   if (%Item $= "")
      %Item = %Weapon.item;
   %Drone.owner.setWeaponsHudActive(%Item);

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

   %Drone.owner.setControlObject(%Drone.owner.player);
   messageClient(%Drone.owner, '', "Repair Drone Destroyed.");   

   Parent::onDestroyed(%this, %Drone, %prevState);

   %Random = getRandom();
   if (%Random > 0.75)
   {
      %Item = new Item()
      {
         datablock = RepairPatch;
         position = %Position;
      };
      MissionCleanUp.Add(%Item);

      %Item.applyImpulse(%Position, "-1 1 10");

      %Item.schedule(14500, "setCloaked", true);
      %Item.schedule(15000, delete);
   }
}

function RepairDrone::onTrigger(%data, %Vehicle, %trigger, %state)
{
   switch (%Trigger)
   {
      // Fire weapon
      case 0:
         if (%State == false)
         {
            // No Longer Firing
            %Vehicle.fireWeapon = false;
            %Vehicle.setImageTrigger(2, false);

         } else {
            // Firing now
            %Vehicle.fireWeapon = true;
            %Vehicle.setImageTrigger(2, true);
         }

      case 2:
         if (%State == true)
            %Vehicle.getDataBlock().playerDismount(%Vehicle);   
   }
}

function RepairDrone::ItemSwap(%data, %Drone)
{
   %Transform = %Drone.getTransform();
   %Position = posFromTransform(%Transform);

   %ItemData = %Drone.getDataBlock().item;

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

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

   %Drone.delete();

   %NewItem.schedulePop();
}

function SetControl(%Client, %Object)
{
   if (isObject(%Object) == false)
      return;

   %Client.setControlObject(%Object);
   commandToClient(%Client, 'setRepairReticle');
}