
//----------------------------------------------------------------------------

// When first mounted (assuming there is ammo):
//    SingleShot     activate -> ready
//    Spinning       activate -> idle (spin 0)
//    Sustained      activate -> ready
//    DiscLauncher   activate -> reload -> spinup -> ready
//
// Normal operation:
//    SingleShot     ready -> fire -> reload -> ready
//    Spinning       idle (spin 0) -> spinup -> ready -> fire -> spindown -> idle
//    Sustained      ready -> fire -> reload -> ready
//    DiscLauncher   ready -> fire -> reload -> spinup -> ready

// Image properties
//    emap
//    preload
//    shapeFile
//    mountPoint
//    offset
//    rotation
//    firstPerson
//    mass
//    usesEnergy
//    minEnergy
//    accuFire
//    lightType
//    lightTime
//    lightRadius
//    lightColor

// Image state variables
//    stateName
//    stateTransitionOnLoaded
//    stateTransitionOnNotLoaded
//    stateTransitionOnAmmo
//    stateTransitionOnNoAmmo
//    stateTransitionOnTriggerUp
//    stateTransitionOnTriggerDown
//    stateTransitionOnTimeout
//    stateTimeoutValue
//    stateFire
//    stateEnergyDrain
//    stateAllowImageChange
//    stateScaleAnimation
//    stateDirection
//    stateLoadedFlag
//    stateSpinThread
//    stateRecoil
//    stateSequence
//    stateSound
//    stateScript
//    stateEmitter
//    stateEmitterTime
//    stateEmitterNode

//----------------------------------------------------------------------------

$WeaponSlot = 0;
$AuxiliarySlot = 1;
$BackpackSlot = 2;
$FlagSlot = 3;
$OtherSlot1 = 4;
$OtherSlot2 = 5;
$OtherSlot3 = 6;
$OtherSlot4 = 7;
$OtherSlot5 = 8;

$ArmorSlots = 3;

$EverythingMask = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType |
                  $TypeMasks::StationObjectType | $TypeMasks::GeneratorObjectType |
                  $TypeMasks::SensorObjectType | $TypeMasks::TurretObjectType |
                  $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType |
                  $TypeMasks::ForceFieldObjectType | $TypeMasks::StaticObjectType |
                  $TypeMasks::MoveableObjectType | $TypeMasks::DamagableItemObjectType;

$DamageableMask = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType |
                  $TypeMasks::StationObjectType | $TypeMasks::GeneratorObjectType |
                  $TypeMasks::SensorObjectType | $TypeMasks::TurretObjectType |
                  $TypeMasks::MoveableObjectType | $TypeMasks::DamagableItemObjectType;

//----------------------------------------------------------------------------
datablock EffectProfile(ItemPickupEffect)
{
    effectname = "packs/packs.pickupPack";
    minDistance = 2.5;
};

datablock AudioProfile(ItemPickupSound)
{
   filename = "fx/packs/packs.pickuppack.wav";
   description = AudioClosest3d;
   effect = ItemPickupEffect;
   preload = true;
};

datablock AudioProfile(ItemThrowSound)
{
   filename = "fx/packs/packs.throwpack.wav";
   description = AudioClosest3d;
   preload = true;
};

datablock AudioProfile(RepairPatchSound)
{
   filename    = "fx/misc/health_patch.wav";
   description = AudioClosest3d;
   preload = true;
   effect = ItemPickupEffect;
   preload = true;
};

function ItemData::create(%block)
{
   if(%block $= "flag")
      %obj = new Item() {
         className = FlagObj;
         dataBlock = %block;
         static = false;
         rotate = false;
      };
   else
      %obj = new Item() {
         dataBlock = %block;
         static = true;
         //rotate = true;
         // don't make "placed items" rotate
         rotate = false;
      };
   return(%obj);
}

//--------------------------------------------------------------------------
function Item::schedulePop(%this)
{
   %itemFadeTime = 1000; // items will take 1 second (1000 milliseconds) to fade out
   %this.startFade(%itemFadeTime, $ItemPopTime - %itemFadeTime, true);
   %this.schedule($ItemPopTime, "delete");
}   

function Item::respawn(%this)
{
   %this.startFade(0, 0, true);
   %this.schedule($ItemRespawnTime + 100, "startFade", 1000, 0, false);
   %this.hide(true);
   %this.schedule($ItemRespawnTime, "hide", false);
}

//--------------------------------------------------------------------------
function ItemData::onThrow(%data,%obj,%shape)
{
   serverPlay3D(ItemThrowSound, %obj.getTransform());
   // don't schedule a delete for satchelCharges when they're deployed
   if(!%data.noTimeout)
      %obj.schedulePop();
}

function ItemData::onInventory(%data,%shape,%value)
{
   if (!%value) {
      // If we don't have any more of these items, make sure
      // we don't have an image mounted.
      %slot = %shape.getMountSlot(%data.image);
      if (%slot != -1)
         %shape.unmountImage(%slot);
   }
}

function ItemData::onEnterLiquid(%data, %obj, %coverage, %type)
{
   if(%data.isInvincible)
      return;
      
   switch(%type)
   {
      case 0:
         //Water
      case 1:
         //Ocean Water
      case 2:
         //River Water
      case 3:
         //Stagnant Water
      case 4:
         //Lava
         %obj.delete();
      case 5:
         //Hot Lava
         %obj.delete();
      case 6:    
         //Crusty Lava
         %obj.delete();
      case 7:
         //Quick Sand
   }
}

function ItemData::onLeaveLiquid(%data, %obj, %type)
{
   // dummy
}

function ItemData::onCollision(%data, %Object, %Player)
{
   // Default behavior for items is to get picked 
   // by the colliding object.
   if (%Player.getDataBlock().className $= Armor && %Player.getState() !$= "Dead")
   {
      if (%Player.isMounted())
         return;

      %Success = %Player.pickup(%Object, 1);
      if (%Success == true)
      {
         if (%Player.client !$= "")
         {
            messageClient(%Player.client, 'MsgItemPickup', '\c0You picked up %1.', %data.pickUpName);
            serverPlay3D(ItemPickupSound, %Player.getTransform());
         }
         echo("Category: " @ %Object.getDataBlock().category);

         if (%Object.isStatic() && %Object.getDataBlock().category !$= "Dropped")
            %Object.respawn();
         else
            %Object.delete();
      }
   }
}

//----------------------------------------------------------------------------

datablock ItemData(RepairPatch)
{
   catagory = "Misc";
   shapeFile = "repair_patch.dts";
   mass = 1;
   elasticity = 0.2;
   friction = 0.6;
   pickupRadius = 2.0;
   pickUpName = "a repair patch";
   alwaysAmbient = true;

   computeCRC = true;
   emap = true;

};

function RepairPatch::onCollision(%data,%obj,%col)
{
   if ( %col.getDataBlock().className $= Armor 
     && %col.getDamageLevel() != 0
     && %col.getState() !$= "Dead" ) 
   {
      if (%col.isMounted())
         return;

      %col.playAudio(0, RepairPatchSound);
      %col.applyRepair(0.165);
      %obj.respawn();
      if (%col.client > 0)
         messageClient(%col.client, 'MsgItemPickup', '\c0You picked up %1.', %data.pickUpName);
   }
}

//----------------------------------------------------------------------------
// Flag:
//----------------------------------------------------------------------------
datablock ShapeBaseImageData(FlagImage)
{
   shapeFile = "flag.dts";
   item = Flag;
   mountPoint = 2;
   offset = "0 0 0";

   lightType = "PulsingLight";
   lightColor = "0.5 0.5 0.5 1.0";
   lightTime = "1000";
   lightRadius = "3";
   cloakable = false;
};

datablock ItemData(Flag)
{
   catagory = "Objectives";
   shapefile = "flag.dts";
   mass = 55;
   elasticity = 0.2;
   friction = 5.6;
   pickupRadius = 3;
   pickUpName = "a flag";
   computeCRC = true;
  
   heatsignature = 0;

   lightType = "PulsingLight";
   lightColor = "0.5 0.5 0.5 1.0";
   lightTime = "1000";
   lightRadius = "3";

   isInvincible = true;
   cmdCategory = "Objectives";
   cmdIcon = CMDFlagIcon;
   cmdMiniIconName = "commander/MiniIcons/com_flag_grey";
   targetTypeTag = 'Flag';

   //used in CTF to mark the flag during a stalemate...
   hudImageNameFriendly[1] = "commander/MiniIcons/com_flag_grey";
   hudImageNameEnemy[1] = "commander/MiniIcons/com_flag_grey";
   hudRenderModulated[1] = true;
   hudRenderAlways[1] = true;
   hudRenderCenter[1] = true;
   hudRenderDistance[1] = true;
   hudRenderName[1] = true;
};

//----------------------------------------------------------------------------
function Flag::onThrow(%data,%obj,%src)
{
   Game.playerDroppedFlag(%src);   
}

function Flag::onAdd(%this, %obj)
{
   // make sure flags play "flapping" ambient thread
   Parent::onAdd(%this, %obj);
   %obj.playThread($AmbientThread, "ambient");

   %blocker = new VehicleBlocker()
   {
      position = %obj.position;
      rotation = %obj.rotation;
      dimensions = "2 2 4";
   };
   MissionCleanup.add(%blocker);
}

function Flag::onCollision(%data,%obj,%col)
{
   if (%col.getDataBlock().className $= Armor)
   {
      if (%col.isMounted())
         return;

      // a player hit the flag
      Game.playerTouchFlag(%col, %obj);
   }
}

//----------------------------------------------------------------------------
// HuntersFlag:
//----------------------------------------------------------------------------
datablock ShapeBaseImageData(HuntersFlagImage)
{
   shapeFile = "Huntersflag.dts";
   item = Flag;
   mountPoint = 2;
   offset = "0 0 0";

   lightType = "PulsingLight";
   lightColor = "0.5 0.5 0.5 1.0";
   lightTime = "1000";
   lightRadius = "3";
};

// 1: red
// 2: blue
// 4: yellow
// 8: green
datablock ItemData(HuntersFlag1)
{     
   className = HuntersFlag;

   shapefile = "Huntersflag.dts";
   mass = 75;
   elasticity = 0.2;
   //friction = 0.6;
   friction = 5.6;
   pickupRadius = 3;
   isInvincible = true;
   pickUpName = "a flag";
   computeCRC = true;

   lightType = "PulsingLight";
   lightColor = "0.8 0.2 0.2 1.0";
   lightTime = "1000";
   lightRadius = "3";
};

datablock ItemData(HuntersFlag2) : HuntersFlag1
{     
   lightColor = "0.2 0.2 0.8 1.0";
};

datablock ItemData(HuntersFlag4) : HuntersFlag1
{     
   lightColor = "0.8 0.8 0.2 1.0";
};

datablock ItemData(HuntersFlag8) : HuntersFlag1
{     
   lightColor = "0.2 0.8 0.2 1.0";
};

function HuntersFlag::onRemove(%data, %obj)
{
   // dont want target removed...
}

function HuntersFlag::onThrow(%data,%obj,%src)
{
   Game.playerDroppedFlag(%src);   
}

function HuntersFlag::onCollision(%data,%obj,%col)
{
   if (%col.getDataBlock().className $= Armor)
   {
      if (%col.isMounted())
         return;

      // a player hit the flag
      Game.playerTouchFlag(%col, %obj);
   }
}

//----------------------------------------------------------------------------
// Nexus:
//----------------------------------------------------------------------------
datablock ItemData(Nexus)
{
   catagory = "Objectives";
   shapefile = "nexus_effect.dts";
   mass = 10;
   elasticity = 0.2;
   friction = 0.6;
   pickupRadius = 2;
   icon = "CMDNexusIcon";
   targetTypeTag = 'Nexus';

   computeCRC = true;

};

datablock ParticleData(NexusParticleDenied)
{
   dragCoeffiecient     = 0.4;
   gravityCoefficient   = 3.0;
   inheritedVelFactor   = 0.0;

   lifetimeMS           = 1200;
   lifetimeVarianceMS   = 400;

   textureName          = "particleTest";

   useInvAlpha =  false;
   spinRandomMin = -200.0;
   spinRandomMax =  200.0;

   colors[0]     = "0.3 0.0 0.0 1.0";
   colors[1]     = "0.5 0.0 0.0 0.5";
   colors[2]     = "0.7 0.0 0.0 0.0";
   sizes[0]      = 0.2;
   sizes[1]      = 0.1;
   sizes[2]      = 0.0;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(NexusParticleDeniedEmitter)
{
   ejectionPeriodMS = 2;
   ejectionOffset = 0.2;
   periodVarianceMS = 0.5;
   ejectionVelocity = 10.0;
   velocityVariance = 4.0;
   thetaMin         = 0.0;
   thetaMax         = 30.0;
   lifetimeMS       = 0;

   particles = "NexusParticleDenied";
};

datablock ParticleData(NexusParticleCap)
{
   dragCoeffiecient     = 0.4;
   gravityCoefficient   = 3.0;
   inheritedVelFactor   = 0.0;

   lifetimeMS           = 1200;
   lifetimeVarianceMS   = 400;

   textureName          = "particleTest";

   useInvAlpha =  false;
   spinRandomMin = -200.0;
   spinRandomMax =  200.0;

   colors[0]     = "0.5 0.8 0.2 1.0";
   colors[1]     = "0.6 0.9 0.3 1.0";
   colors[2]     = "0.7 1.0 0.4 1.0";
   sizes[0]      = 0.2;
   sizes[1]      = 0.1;
   sizes[2]      = 0.0;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(NexusParticleCapEmitter)
{
   ejectionPeriodMS = 2;
   ejectionOffset = 0.5;
   periodVarianceMS = 0.5;
   ejectionVelocity = 10.0;
   velocityVariance = 4.0;
   thetaMin         = 0.0;
   thetaMax         = 30.0;
   lifetimeMS       = 0;

   particles = "NexusParticleCap";
};

//----------------------------------------------------------------------------

function getVector(%string, %num)
{
   %start = %num * 3;
   return getWords(%string,%start, %start + 2); 
}

// ----------------------------------------------------------------------------
// General Hacker Notification Stuff
// ----------------------------------------------------------------------------

// Sound an Alarm, Make a pulsing red light, and notify the whole team of a hacker
function TeamHackNotify(%Object)
{
   //Play sound here
   %Object.playAudio(2, AlarmAlert);
   %Object.schedule(1000, playAudio, 2, AlarmAlert);
   %Object.schedule(3500, playAudio, 2, AlarmAlert);
   %Object.schedule(4500, playAudio, 2, AlarmAlert);

   // Make a team waypoint to where the object is and have it last for about 24 seconds.
   %Position = %Object.getWorldBoxCenter();
   %PositionXY = getWords(%Position, 0, 1);
   %PositionZ = getWord(%Position, 2) + 1.4;
   %Beacon = MakeTeamWaypoint(%PositionXY @ " " @ %PositionZ, %Object.team, 24000, true);

   // Notify the entire team of a hacking attempt gone wrong 
   %ObjectName = %Object.getName();
   if (%ObjectName $= "")
      %ObjectName = %Object.getDataBlock().Name;

   %Message = "An enemy unsuccessfully tried to hack into a " @ %ObjectName @ ".";
   messageTeam(%Object.team, '', %Message);

   return(%Beacon);
}

// ------------------------------------------------------------------------------
// Havoc Repair Kit
// This repair kit can be used on other objects in order to repair them, the only
// limitations are already repaired items or enemy held ones.
// ------------------------------------------------------------------------------

datablock RepairProjectileData(RepairKitBeam)
{
   sound = RepairPackFireSound;

   beamRange      = 10;
   beamWidth      = 0.15;
   numSegments    = 5;
   texRepeat      = 0.20;
   blurFreq       = 10.0;
   blurLifetime   = 1.0;

   textures[0]   = "special/redbump2";
   textures[1]   = "special/redflare";

   maxRifleRange = 5;
   beamColor = "1 0.0 0.0";

   hasLight    = true;
   lightRadius = 1.5;
   lightColor  = "1.0 0.0 0.0";
};

datablock ItemData(RepairKit)
{
   className = HandInventory;
   catagory = "Misc";
   shapeFile = "repair_kit.dts";
   mass = 1;
   elasticity = 0.2;
   friction = 0.6;
   pickupRadius = 1;
   pickUpName = "a repair kit";

   patchRange = 8;
   repairFactor = 0.02;
};

// This function actually uses the repair kit.
function Player::RepairKitUse(%Player)
{
   // Don't use the kit unless we're damaged
   if (%Player.getDamageLevel() <= 0)
      return;

   %Player.decInventory("RepairKit", 1);
   %Player.applyRepair(0.24);

   %Message = "You use a repair kit on yourself.";
   messageClient(%Player.client, 'MsgRepairPackRepairingObj', %Message);

   if (%Player.Special $= "EngAssistant")
      %Player.makeRepairKit();
}

// This function deletes various beams
function StopBeam(%Beam)
{
   %Beam.delete();
}

// Use of the repair kit on either another player, object, or themselves
function RepairKit::onUse(%data, %Player)
{

   %RepairFactor = RepairKit.repairFactor;
   %RepairRange = RepairKit.patchRange;

   // Calculate the direction and distance of the patching
   %Position = %Player.getMuzzlePoint($WeaponSlot);
   %Vector = %Player.getMuzzleVector($WeaponSlot);
   %ScaledVector = VectorScale(%Vector, %RepairRange);
   %End = VectorAdd(%Point, %ScaledVector);

   // Search for objects within the beam's range that fit the above criteria
   %ScannedTarget = ContainerRayCast(%Position, %End, $DamageableMask | $TypeMasks::ForceFieldObjectType, %Player);

   if (%ScannedTarget $= "0")
   {
      %Player.RepairKitUse();
      return;
   }

   // Get the Object from the scan   
   %Target = getWord(%ScannedTarget, 0);
   %TargetTeam = %Target.team;

   // Compare teams, allow them to heal nuetral objects
   if (%TargetTeam != 0 && %TargetTeam != %Player.team)
   {
      %Player.RepairKitUse();
      return;
   }

   // If something is found but is not what we want for some reason
   %Type = %Target.getType();
   if (%Type $= "" || %Type == 0)
   {
      %Player.RepairKitUse();
      return;
   }

   if (%Type & $DamageableMask)
   {
      // No !& works
   } else {
      %Player.RepairKitUse();
      return;
   }

   %RepairAmount = 0.5;
   // If another player, then notify them both
   if(%Target.getClassName() $= Player)
   {
      if (%Target.getDamageLevel() < 0)
      {
         %Player.RepairKitUse();
         return;
      }

      // If a player, also notify them of the patching
      %PlayerName = getTaggedString(%Player.client.name);
      %Message = %PlayerName @ ' uses thier repair kit on you.';
      messageClient(%Target.client, 'MsgRepairPackRepairingObj', %Message);

      %TargetName = getTaggedString(%Target.client.name);
   } else {
      %TargetName = %Target.getName();
      if (%TargetName $= "")
         %TargetName = %Target.getDatablock().name;
   }

   %RepairBeam = new RepairProjectile()
   {
      dataBlock = RepairKitBeam;
      initialDirection = %Vector;
      initialPosition  = %Position;
      sourceObject     = %Player;
      sourceSlot       = $weaponSlot;
      targetObject     = %Target;
   };
   MissionCleanup.add(%RepairBeam);

   %Target.applyRepair(%RepairAmount);
   %Player.decInventory(%Data, 1);

   if (%Player.Special $= "EngAssistant")
      %Player.makeRepairKit();

   %Message = "You use your repair kit on " @ %TargetName @ ".";
   messageClient(%Player.client, 'MsgRepairPackRepairingObj', %Message);

   schedule(850, 0, StopBeam, %RepairBeam);
}

function FollowObject(%Object1, %Object2)
{
   if (isObject(%Object1) == false)
      return;

   if (isObject(%Object2) == false)
      return;

   %Transform = %Object2.getTransform();
   %Object1.setTransform(%Transform);

   %Velocity = %Object.getVelocity();
   %Object1.setVelocity(%Velocity);

   schedule(850, 0, FollowObject, %Object1, %Object2);
}

function rotFromVector(%Vector)
{
   %RotationX = mSin(VectorDot(%Vector, "1 0 0"));
   %RotationY = mSin(VectorDot(%Vector, "0 1 0"));
   %RotationZ = mSin(VectorDot(%Vector, "0 0 1"));

   return(%RotationX @ " " @ %RotationY @ " " @ %RotationZ);
}

datablock ItemData(Beacon)
{
   className = HandInventory;
   catagory = "Misc";

   shapeFile = "beacon.dts";

   mass = 1;

   elasticity = 0.2;
   friction = 0.8;

   pickupRadius = 1;
   pickUpName = "a deployable beacon";

   computeCRC = true;

};

datablock StaticShapeData(DeployedBeacon) : StaticShapeDamageProfile
{
   shapeFile = "beacon.dts";
   explosion = DeployablesExplosion;
   maxDamage = 0.45;
   disabledLevel = 0.45;
   destroyedLevel = 0.45;
   beacon = true;
   targetNameTag = 'beacon';

   dynamicType = $TypeMasks::SensorObjectType;

   debrisShapeName = "debris_generic_small.dts";
   debris = SmallShapeDebris;
};

datablock StaticShapeData(DeployedBeacon) : StaticShapeDamageProfile
{
   shapeFile = "beacon.dts";
   explosion = DeployablesExplosion;
   maxDamage = 0.45;
   disabledLevel = 0.45;
   destroyedLevel = 0.45;

   cantUplink = true;

   deployedObject = true;
   
   dynamicType = $TypeMasks::SensorObjectType;

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

   targetNameTag = 'beacon';
   beacon = true;
};

function DeployedBeacon::onDestroyed(%data, %obj, %prevState)
{
   if(%obj.isBeaconType(friend))
      %bType = "MarkerBeacon";
   else
      %bType = "TargetBeacon";
   $TeamDeployedCount[%obj.team, %bType]--;
   %obj.schedule(500, delete);
}

function TargetingBeacon::onUse(%data, %obj)
{
   // look for 3 meters along player's viewpoint for interior or terrain
   %searchRange = 3.0;
   %mask = $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType;
   // get the eye vector and eye transform of the player
   %eyeVec = %obj.getEyeVector();
   %eyeTrans = %obj.getEyeTransform();
   // extract the position of the player's camera from the eye transform (first 3 words)
   %eyePos = posFromTransform(%eyeTrans);
   // normalize the eye vector
   %nEyeVec = VectorNormalize(%eyeVec);
   // scale (lengthen) the normalized eye vector according to the search range
   %scEyeVec = VectorScale(%nEyeVec, %searchRange);
   // add the scaled & normalized eye vector to the position of the camera
   %eyeEnd = VectorAdd(%eyePos, %scEyeVec);
   // see if anything gets hit
   %searchResult = containerRayCast(%eyePos, %eyeEnd, %mask, 0);
   if(!%searchResult )
   {
      // no terrain/interior collision within search range
      if(%obj.inv[%data.getName()] > 0)
         messageClient(%obj.client, 'MsgBeaconNoSurface', '\c2Cannot place beacon. Too far from surface.');
      return 0;
   }
   else
   {
      %searchObj = GetWord(%searchResult, 0);
      if(%searchObj.getType() & ($TypeMasks::StaticShapeObjectType | $TypeMasks::ForceFieldObjectType) )
      {
         // if there's already a beacon where player is aiming, switch its type
         // otherwise, player can't deploy a beacon there
         if(%searchObj.getDataBlock().getName() $= DeployedBeacon)
            switchBeaconType(%searchObj);
         else
            messageClient(%obj.client, 'MsgBeaconNoSurface', '\c2Cannot place beacon. Not a valid surface.');
         return 0;
      }
      else if(%obj.inv[%data.getName()] <= 0) 
         return 0;   
   }
   // newly deployed beacons default to "target" type
   if($TeamDeployedCount[%obj.team, TargetBeacon] >= $TeamDeployableMax[TargetBeacon])
   {
      messageClient(%obj.client, 'MsgDeployFailed', '\c2Your team\'s control network has reached its capacity for this item.~wfx/misc/misc.error.wav');
      return 0;
   }
   %terrPt = posFromRaycast(%searchResult);
   %terrNrm = normalFromRaycast(%searchResult);

   %intAngle = getTerrainAngle(%terrNrm);  // getTerrainAngle() function found in staticShape.cs
   %rotAxis = vectorNormalize(vectorCross(%terrNrm, "0 0 1"));
   if (getWord(%terrNrm, 2) == 1 || getWord(%terrNrm, 2) == -1)
      %rotAxis = vectorNormalize(vectorCross(%terrNrm, "0 1 0"));
   %rotation = %rotAxis @ " " @ %intAngle;

   %obj.decInventory(%data, 1);
   %depBeac = new BeaconObject() {
      dataBlock = "DeployedBeacon";
      position = VectorAdd(%terrPt, VectorScale(%terrNrm, 0.05));
      rotation = %rotation;
   };
   $TeamDeployedCount[%obj.team, TargetBeacon]++;

   %depBeac.playThread($AmbientThread, "ambient");
   %depBeac.team = %obj.team;
   %depBeac.sourceObject = %obj;

   // give it a team target
   %depBeac.setTarget(%depBeac.team);
   MissionCleanup.add(%depBeac);
}

function switchBeaconType(%beacon)
{
   if(%beacon.getBeaconType() $= "friend")
   {
      // switch from marker beacon to target beacon
      if($TeamDeployedCount[%beacon.team, TargetBeacon] >= $TeamDeployableMax[TargetBeacon])
      {
         messageClient(%beacon.sourceObject.client, 'MsgDeployFailed', '\c2Your team\'s control network has reached its capacity for this item.~wfx/misc/misc.error.wav');
         return 0;
      }
      %beacon.setBeaconType(enemy);
      $TeamDeployedCount[%beacon.team, MarkerBeacon]--;
      $TeamDeployedCount[%beacon.team, TargetBeacon]++;
   }
   else
   {
      // switch from target beacon to marker beacon
      if($TeamDeployedCount[%beacon.team, MarkerBeacon] >= $TeamDeployableMax[MarkerBeacon])
      {
         messageClient(%beacon.sourceObject.client, 'MsgDeployFailed', '\c2Your team\'s control network has reached its capacity for this item.~wfx/misc/misc.error.wav');
         return 0;
      }
      %beacon.setBeaconType(friend);
      $TeamDeployedCount[%beacon.team, TargetBeacon]--;
      $TeamDeployedCount[%beacon.team, MarkerBeacon]++;
   }
}

function MakeTeamWaypoint(%Position, %Team, %Duration, %Light)
{
   //Place a Marker beacon
   %Beacon = new BeaconObject()
   {
      dataBlock = "MarkerBeacon";
      position = %Position;
      team = %Team;
   };
   MissionCleanup.add(%Beacon);

   if (%Light == true)
   {
      %ExtraObject = new Item()
      {
         dataBlock = MarkerBeaconColor;
         position = %Position;
      };
      MissionCleanUp.Add(%ExtraObject);

      %Beacon.Color = %ExtraObject;
   }

   %Beacon.setTarget(%Team);
   %Beacon.setBeaconType(friend);

   if (%Duration > 0)
      %Beacon.schedule(%Duration, delete);

   return(%Beacon);
}

datablock StaticShapeData(MarkerBeacon) : StaticShapeDamageProfile
{
   shapeFile = "turret_muzzlepoint.dts";
   maxDamage = 500;
   disabledLevel = 495;
   destroyedLevel = 500;

   cantUplink = true;

   deployedObject = true;
   
   dynamicType = $TypeMasks::SensorObjectType;

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

   targetNameTag = 'beacon';
   beacon = true;
};

function MarkerBeacon::onRemove(%data, %Beacon)
{
   if (%Beacon.Color !$= "")
      %Beacon.Color.delete();
}

datablock ItemData(MarkerBeaconColor)
{
   shapeFile = "turret_muzzlepoint.dts";

   sticky = true;
   mass = 0;
   friction = 1.0;

   haslightradius = true;
   lightType = "PulsingLight";
   lightColor  = "0.6 0.0 0.0 0.5";
   lightTime = "2500";
   lightRadius = "4.5";

   computeCRC = true;
   emap = true;
};
