DTS/Scripting/Vehicles/Guide

From TDN

This page is a Work In Progress.

Contents

Introduction

This documentation aims at providing a complete vehicular support for the player and Torque's vehicles. As with any scripting there are many ways of doing one thing and this provides only one method of completing this task.

Requirements

It is advised that you have read the DTS guides to vehicles, including having a vehicle ready for use with all assets. A template vehicle is being put together for this example.

Due to the complexity of these functions, it is advised that you become very familiar with TorqueScript, especially as this section covers the player, camera, moveMaps, vehicle data and more.

Script

Each section is detailed to explain what is going on, a final compiled script can be found at the end of this document.

This script is run from ~/server/scripts/vehicles/vehicles.cs.

We are aiming to get a fully functioning vehicle system, to allow the player to mount the vehicle, dismount it, get damage during the vehicle. This currently doesn't add weapon support, although this can be expanded on by using the moveMaps to control the weapons on the vehicles. While these scripts only provide a basic template, they aim to give you a good understanding of what is happening with each function to get this gameplay section working.

General Purpose Functions

This section contains global functions used for all the vehicles. Typically this will entail adding and removing the vehicle from the WorldSpace.

VehicleData::onAdd

//**************************************************************
//* GENERAL PURPOSE FUNCTIONS
//**************************************************************

function VehicleData::onAdd(%this, %obj)
{
   Parent::onAdd(%this, %obj);
   
   %obj.setRechargeRate(%this.rechargeRate);
   // set full energy
   %obj.setEnergyLevel(%this.MaxEnergy);

   if(%obj.disableMove)
      %obj.immobilized = true;
   if(%obj.deployed)
   {
      if($countDownStarted)
         %data.schedule(($Host::WarmupTime * 1000) / 2, "vehicleDeploy", %obj, 0, 1);
      else
      {
         $VehiclesDeploy[$NumVehiclesDeploy] = %obj;
         $NumVehiclesDeploy++;
      }
   }
   if(%obj.mountable || %obj.mountable $= "")
      %this.isMountable(%obj, true);
   else
      %this.isMountable(%obj, false);

   %obj.setSelfPowered();
//   %this.canObserve = true;
}

VehicleData::onRemove

function VehicleData::onRemove(%this, %obj)
{
   // if there are passengers/driver, kick them out
   %this.deleteAllMounted(%obj);
   for(%i = 0; %i < %obj.getDatablock().numMountPoints; %i++)
      if (%obj.getMountNodeObject(%i)) {
         %passenger = %obj.getMountNodeObject(%i);
         %passenger.unmount();
      }
   vehicleListRemove(%obj.getDataBlock(), %obj);
   if(%obj.lastPilot.lastVehicle == %obj)
      %obj.lastPilot.lastVehicle = "";      

   Parent::onRemove(%this, %obj);
}

Creating Vehicles

HoverVehicleData::create

//**************************************************************
//* VEHICLE CREATE
//**************************************************************
function HoverVehicleData::create(%this, %team, %oldObj)
{
   if(%oldObj $= "")
   {
      %obj = new HoverVehicle() 
      {
         datablock  = %this;
         respawn    = "0";
      };
   }
   else
   {
      %obj = new HoverVehicle() 
      {
         datablock  = %this;
         respawn    = "0";
         mountable = %oldObj.mountable;
         disableMove = %oldObj.disableMove;
         resetPos = %oldObj.resetPos;
         respawnTime = %oldObj.respawnTime;
         marker = %oldObj;
      }; 
   }
   return(%obj);
}

WheeledVehicleData::create

$Vehicle::Wheeled::EnergyLevel = 60;

function WheeledVehicleData::create(%this, %obj, %oldObj)
{
   if(%oldObj $= "")
   {
      %obj = new WheeledVehicle() 
      {
         datablock  = %this;
         respawn    = "0";
      };
   }
   else
   {
      %obj = new WheeledVehicle() 
      {
         datablock  = %this;
         respawn    = "0";
         mountable = %oldObj.mountable;
         disableMove = %oldObj.disableMove;
         resetPos = %oldObj.resetPos;
         deployed = %oldObj.deployed;
         respawnTime = %oldObj.respawnTime;
         marker = %oldObj;
      };   

   %obj.mountable = true;
   %obj.setEnergyLevel($Vehicle::Wheeled::EnergyLevel);
   }
   return(%obj);
}

FlyingVehicleData::create

$Vehicle::Flying::EnergyLevel = 120

function FlyingVehicleData::create(%this, %obj, %oldObj)
{
   if(%oldObj $= "")
   {
      %obj = new FlyingVehicle() 
      {
         datablock  = %this;
         respawn    = "0";
         teamBought = %team;
         team = %team;
      };
   }      
   else
   {
      %obj = new FlyingVehicle() 
      {
         datablock  = %this;
         teamBought = %team;
         team = %team;
         mountable = %oldObj.mountable;
         disableMove = %oldObj.disableMove;
         resetPos = %oldObj.resetPos;
         respawnTime = %oldObj.respawnTime;
         marker = %oldObj;
      };  
 %obj.mountable = true;
   %obj.setEnergyLevel($Vehicle::Hover::EnergyLevel);    
   }
   
   return(%obj);
}

Player Functions

This section explains code that is specific to the player's functions in mounting/dismounting through various ways. You can set the mounting and dismounting functions to act upon collision or key binds.

PlayerData::onCollision

1. Ignore collisions if this player is "Dead". i.e. a Corpse

Note - This will probably need to be removed for RPG style games where you pick up a corpse's inventory. 2. Call into the parent callback allowing it to do any work it should do first.
3. Handle collisions with vehicles. This is accomplished by checking whether a player has collided with a vehicle, then whether the vehicle is mountable. Then, the player is checked to see if it can mount vehicles, and finally whether it is mounted already.

function PlayerData::onCollision()
{
}

PlayerData::doVehicleMount

function PlayerData::doVehicleMount()
{
}

PlayerData::doDismount

function doPlayerDismount(%player, %obj, %forced)
{
%vel = %obj.getVelocity();
   %speed = vectorLen(%vel);

   // Check our speed. If we're still moving, we can't dismount.
   if (%speed >= 1 || !%obj.isMounted())
   {
      // The vehicle is moving or the player is not mounted.
      return;
   }

   // Find the position above dismount point.
   %pos    = getWords(%obj.getTransform(), 0, 2);
   %oldPos = %pos;
   %vec[0] = " 2  0  0";
   %vec[1] = " 0  -2  0";
   %vec[2] = " 0  2  0";
   %vec[3] = "-2  0  0";
   %vec[4] = " 4  0  0";
   %impulseVec  = "0 0 0";
   %vec[0] = MatrixMulVector( %obj.getTransform(), %vec[0]);

   // Make sure the point is valid
   %pos = "0 0 0";
   %numAttempts = 5;
   %success     = -1;
   for (%i = 0; %i < %numAttempts; %i++) {
      %pos = VectorAdd(%oldPos, VectorScale(%vec[%i], 3));
      if (%obj.checkDismountPoint(%oldPos, %pos)) {
         %success = %i;
         %impulseVec = %vec[%i];
         break;
      }
   }

   if (%forced && %success == -1)
      %pos = %oldPos;

   %obj.unmount();
   %obj.setControlObject(%obj);
   %obj.mountVehicle = false;

   // Schedule the function to set the mount flag, so that the player
   // can mount another vehicle in the future.
   %obj.schedule(4000, "MountVehicles", true);

   // Position above dismount point
   %obj.setTransform(%pos);
   %obj.applyImpulse(%pos, VectorScale(%impulseVec, %obj.getDataBlock().mass));

   %obj.setActionThread("run",true,true);
   %obj.setArmThread("look");

   // Command the client to display the correct movement map and
   // activate the command menu.
   CommandToClient(%obj.client, 'PopActionMap', $Vehicle::moveMaps[%obj.mSeat]);
   CommandToClient(%obj.client, 'PushActionMap', moveMap);
   CommandToClient(%obj.client,'activateCommandMenu');
}

PlayerData::onUnmount

Assume that the player is dismounting a shape that was until now the control object.

function PlayerData::onUnmount( %this, %Obj, %mount, %node )
{
   %Obj.setControlObject( %Obj );

    //Adds his weapon back
   %obj.mountImage(%obj.lastWeapon, $WeaponSlot);
}

VehicleData::onPlayerMount


Player::onVehicleMount

function onPlayerMount(%player,%obj,%vehicle,%node)
{
 CommandToClient(%obj.client, 'PopActionMap', moveMap);
   CommandToClient(%obj.client, 'PushActionMap', $Vehicle::moveMaps[%node]);
   CommandToClient(%obj.client,'HideCommandMenuServer');

   %obj.setTransform(%vehicle.getDataBlock().mountPointTransform[%node]);
   %obj.lastWeapon = %obj.getMountedImage($WeaponSlot);
   %obj.unmountImage($WeaponSlot);
   %obj.setActionThread(%vehicle.getDatablock().mountPose[%node],true,true);

   // Are we driving this vehicle?
   if (%node == 0)  {
      %obj.setControlObject(%vehicle);
   }

Damage Functions

VehicleData::damage

//**************************************************************
//* DAMAGE FUNCTIONS
//**************************************************************
function VehicleData::damage(%this,%obj,%type,%vel,%damage,%damageType)
{
   echo("Vehicle IS HIT");
  %obj.applyDamage(%damage);
  if(%obj.getDamageState() $= "Destroyed" )
   {
      %obj.blowUp();
   }
   //Parent::damage(%this, %obj);
}

VehicleData::onDamage

function VehicleData::onDamage(%this,%obj,%amount)
{
   //called when damage level is changed
   echo("AT DAMAGE TIME");
   %damage = %obj.getDamageLevel();
   //
   echo("damage given by projectile " @ %amount);
   echo("THIS dataBlock is " @ %this.getDataBlock().dataBlock);
   echo("OBJ dataBlock is " @ %obj.dataBlock);//The vehicle
   echo("getEnergyLevel is " @ %this.getEnergyLevel());
   echo("getEnergyValue is " @ %this.getEnergyValue());
   echo("getDamageState is " @  %obj.getDamageState());//enablebed
   echo("getDamageLevel is " @  %obj.getDamageLevel());//the amount of damage taken
   echo("MaxDamage is " @  %this.maxDamage);//amount of damage it can take

   %healthLeft = %this.maxDamage - %damage;
   echo("The Vehicles's health is " @ %healthLeft);
  //if (%damage >= %this.destroyedLevel)
  //GUI should show maxDamage - damageLevel
    if(%damage >= %this.maxDamage)
   {
      if(%obj.getDamageState() !$= "Destroyed")
      {
         if(%obj.respawnTime !$= "")
            %obj.marker.schedule = %obj.marker.data.schedule(%obj.respawnTime, "respawn", %obj.marker); 
         %obj.setDamageState(Destroyed);
      }
   }
   else
   {
      if(%obj.getDamageState() !$= "Enabled")
         %obj.setDamageState(Enabled);
   }
}

VehicleData::onImpact

function VehicleData::onImpact(%data, %vehicleObject, %collidedObject, %vec, %vecLen)
{
   if(%vecLen > %data.minImpactSpeed)
      %data.damageObject(%vehicleObject, 0, VectorAdd(%vec, %vehicleObject.getPosition()), 
                         %vecLen * %data.speedDamageScale, $DamageType::Ground);

   // associated "crash" sounds
   if(%vecLen > %vDataBlock.hardImpactSpeed)
      %vehicleObject.playAudio(0, %vDataBlock.hardImpactSound);
   else if(%vecLen > %vDataBlock.softImpactSpeed)
      %vehicleObject.playAudio(0, %vDataBlock.softImpactSound);
}         

VehicleData::damageObject

function VehicleData::damageObject(%data, %targetObject, %sourceObject, 
%position, %amount, %damageType, %momVec, %theClient, %proj)
{
//{  echo("you are damaging an object");
//   if(%proj !$= "")
//   {
//      if(%amount > 0 && %targetObject.lastDamageProj !$= %proj)
//      {
//         %targetObject.lastDamageProj = %proj;
//         %targetObject.lastDamageAmount = %amount;
//      }
//      else if(%targetObject.lastDamageAmount < %amount)
//         %amount = %amount - %targetObject.lastDamageAmount;
//      else
//         return;
//   }

   // check for team damage
//   %sourceClient = %sourceObject ? %sourceObject.getOwnerClient() : 0;
 //  %targetTeam = getTargetSensorGroup(%targetObject.getTarget());

//   if(%sourceClient)
//      %sourceTeam = %sourceClient.getSensorGroup();
//   else if(isObject(%sourceObject) && %sourceObject.getClassName() $= "Turret")
//      %sourceTeam = getTargetSensorGroup(%sourceObject.getTarget());
//   else
//      %sourceTeam = %sourceObject ? getTargetSensorGroup(%sourceObject.getTarget()) : -1;

    // vehicles no longer obey team damage -JR
//    if(!$teamDamage && (%targetTeam == %sourceTeam) && %targetObject.getDamagePercent() > 0.5)
//       return;
    //but we do want to track the destroyer
//    if(%sourceObject)
//    {
//        %targetObject.lastDamagedBy = %sourceObject;
 //       %targetObject.lastDamageType = %damageType;
//    }
//    else
//        %targetObject.lastDamagedBy = 0;


   // Scale damage type & include shield calculations...
//   if (%data.isShielded)
//      %amount = %data.checkShields(%targetObject, %position, %amount, %damageType);


//   %damageScale = %data.damageScale[%damageType];
//   if(%damageScale !$= "")
//      %amount *= %damageScale;

//   if(%amount != 0)
//      %targetObject.applyDamage(%amount);

//   if(%targetObject.getDamageState() $= "Destroyed" )
//   {
//      if( %momVec !$= "")
//         %targetObject.setMomentumVector(%momVec);
//   }
}

VehicleData::onEnterLiquid

function VehicleData::onEnterLiquid(%data, %obj, %coverage, %type)
{
   switch(%type)
   {
      case 0:
         //Water
         %obj.setHeat(0.0);
      case 1:
         //Ocean Water
         %obj.setHeat(0.0);
      case 2:
         //River Water
         %obj.setHeat(0.0);
      case 3:
         //Stagnant Water
         %obj.setHeat(0.0);
      case 4:
         //Lava
         %obj.liquidDamage(%data, $VehicleDamageLava, $DamageType::Lava);
      case 5:
         //Hot Lava
         %obj.liquidDamage(%data, $VehicleDamageHotLava, $DamageType::Lava);
      case 6:    
         //Crusty Lava
         %obj.liquidDamage(%data, $VehicleDamageCrustyLava, $DamageType::Lava);
      case 7:
         //Quick Sand
   }
}

VehicleData::onLeaveLiquid

function VehicleData::onLeaveLiquid(%data, %obj, %type)
{
   switch(%type)
   {
      case 0:
         //Water
         %obj.setHeat(1.0);
      case 1:
         //Ocean Water
         %obj.setHeat(1.0);
      case 2:
         //River Water
         %obj.setHeat(1.0);
      case 3:
         //Stagnant Water
         %obj.setHeat(1.0);
      case 4:
         //Lava
      case 5:
         //Hot Lava
      case 6:
         //Crusty Lava
      case 7:
         //Quick Sand
   }

   if(%obj.lDamageSchedule !$= "")
   {
      cancel(%obj.lDamageSchedule);
      %obj.lDamageSchedule = "";
   }
}

FlyingVehicle::liquidDamage

function FlyingVehicle::liquidDamage(%obj, %data, %damageAmount, %damageType)
{
   if(%obj.getDamageState() !$= "Destroyed")
   {
      %data.damageObject(%obj, 0, "0 0 0", %damageAmount, %damageType); 
      %obj.lDamageSchedule = %obj.schedule(50, "liquidDamage", %data, %damageAmount, %damageType);
      passengerLiquidDamage(%obj, %damageAmount, %damageType);
   }
   else
      %obj.lDamageSchedule = "";
}

WheeledVehicle::liquidDamage

function WheeledVehicle::liquidDamage(%obj, %data, %damageAmount, %damageType)
{
   if(%obj.getDamageState() !$= "Destroyed")
   {
      %data.damageObject(%obj, 0, "0 0 0", %damageAmount, %damageType); 
      %obj.lDamageSchedule = %obj.schedule(50, "liquidDamage", %data, %damageAmount, %damageType);
      passengerLiquidDamage(%obj, %damageAmount, %damageType);
   }
   else
      %obj.lDamageSchedule = "";
}

HoverVehicle::liquidDamage

function HoverVehicle::liquidDamage(%obj, %data, %damageAmount, %damageType)
{
   if(%obj.getDamageState() !$= "Destroyed")
   {
      %data.damageObject(%obj, 0, "0 0 0", %damageAmount, %damageType); 
      %obj.lDamageSchedule = %obj.schedule(50, "liquidDamage", %data, %damageAmount, %damageType);
      passengerLiquidDamage(%obj, %damageAmount, %damageType);
   }
   else
      %obj.lDamageSchedule = "";
}

PassengerLiquidDamage

function PassengerLiquidDamage(%obj, %damageAmount, %damageType)
{
   for(%i = %num; %i < %obj.getDataBlock().numMountPoints; %i++)
      if (%p = %obj.getMountNodeObject(%i))
         %p.liquidDamage(%p.getDatablock(), $DamageLava, $DamageType::Lava);
}

VehicleData::onDestroyed

function VehicleData::onDestroyed(%data, %obj, %prevState)
{
    if(%obj.lastDamagedBy)
    {
        %destroyer = %obj.lastDamagedBy;
        game.vehicleDestroyed(%obj, %destroyer);
        //error("vehicleDestroyed( "@ %obj @", "@ %destroyer @")");
    }
    
	radiusVehicleExplosion(%data, %obj);
   if(%obj.turretObject)
      if(%obj.turretObject.getControllingClient())
         %obj.turretObject.getDataBlock().playerDismount(%obj.turretObject);
   for(%i = 0; %i < %obj.getDatablock().numMountPoints; %i++)
   {
      if (%obj.getMountNodeObject(%i)) {
         %flingee = %obj.getMountNodeObject(%i);
         %flingee.getDataBlock().doDismount(%flingee, true);
         %xVel = 250.0 - (getRandom() * 500.0);
         %yVel = 250.0 - (getRandom() * 500.0);
         %zVel = (getRandom() * 100.0) + 50.0;
         %flingVel = %xVel @ " " @ %yVel @ " " @ %zVel;
         %flingee.applyImpulse(%flingee.getTransform(), %flingVel);
         echo("got player..." @ %flingee.getClassName());
         %flingee.damage(0, %obj.getPosition(), 0.4, $DamageType::Crash); 
      }
   }

   %data.deleteAllMounted(%obj);
   %obj.schedule(2000, "delete");
}

RadiusVehicleExplosion

function RadiusVehicleExplosion(%data, %vehicle)
{
	// this is a modified version of RadiusExplosion() from projectiles.cs
	%position = %vehicle.getPosition();
   InitContainerRadiusSearch(%position, %data.explosionRadius, $TypeMasks::PlayerObjectType      |
                                                 $TypeMasks::VehicleObjectType     |
                                                 $TypeMasks::MoveableObjectType    |
                                                 $TypeMasks::StaticShapeObjectType |
                                                 $TypeMasks::ForceFieldObjectType  |
                                                 $TypeMasks::TurretObjectType      |
                                                 $TypeMasks::ItemObjectType);

   %numTargets = 0;
   while ((%targetObject = containerSearchNext()) != 0)
   {
		if(%targetObject == %vehicle)
			continue;

      %dist = containerSearchCurrRadDamageDist();

      if (%dist > %data.explosionRadius)
         continue;

      if (%targetObject.isMounted())
      {
         %mount = %targetObject.getObjectMount();
			if(%mount == %vehicle)
				continue;

         %found = -1;
         for (%i = 0; %i < %mount.getDataBlock().numMountPoints; %i++)
         {
            if (%mount.getMountNodeObject(%i) == %targetObject)
            {
               %found = %i;
               break;
            }
         }
      
         if (%found != -1)
         {
            if (%mount.getDataBlock().isProtectedMountPoint[%found] && (%mount != %vehicle))
               continue;
         }
      }

      %targets[%numTargets]     = %targetObject;
      %targetDists[%numTargets] = %dist;
      %numTargets++;
   }

   for (%i = 0; %i < %numTargets; %i++)
   {
      %targetObject = %targets[%i];
      %dist = %targetDists[%i];

      %coverage = calcExplosionCoverage(%position, %targetObject,
                                        ($TypeMasks::InteriorObjectType |
                                         $TypeMasks::TerrainObjectType |
                                         $TypeMasks::ForceFieldObjectType));
      if (%coverage == 0)
         continue;

      %amount = (1.0 - (%dist / %data.explosionRadius)) * %coverage * %data.explosionDamage;
      %targetData = %targetObject.getDataBlock();

      %momVec = "0 0 1";
      
      if(%amount > 0)
         %targetData.damageObject(%targetObject, %sourceObject, %position, %amount, $DamageType::Explosion, %momVec);
   }
}

Controls

Movemaps can be defined for every mounted position as follows, however this is limited for vehicle-specific controls which might use weapons.

Place the copies of the following moveMaps in your ~/client/scripts/ folder.
General Vehicle Movemaps

// Define the move maps for each position. This may need
// to be defined on a per vehicle basis in the future
// once mounted weapons are implemented.

$Vehicle::moveMaps[0] = "vehicleDriverMap";
$Vehicle::moveMaps[1] = "vehiclePassengerMap";
$Vehicle::moveMaps[2] = "vehiclePassengerMap";
$Vehicle::moveMaps[3] = "vehiclePassengerMap";
$Vehicle::moveMaps[4] = "vehiclePassengerMap";
$Vehicle::moveMaps[5] = "vehiclePassengerMap";
$Vehicle::moveMaps[6] = "vehiclePassengerMap";
$Vehicle::moveMaps[7] = "vehiclePassengerMap";
$Vehicle::moveMaps[8] = "vehiclePassengerMap";



Resources

http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=3925

Final Script

// FROM TRIBES 2
// WATCH FOR PRODUCTION

// Notes:
// - respawning vehicles with turrets (bomber/tank) will not setup the turret properly

//Damage Rate for entering Liquid
$VehicleDamageLava       = 0.0325;
$VehicleDamageHotLava    = 0.0325;
$VehicleDamageCrustyLava = 0.0325;

$NumVehiclesDeploy = 0;

//**************************************************************
//* GENERAL PURPOSE FUNCTIONS
//**************************************************************

function VehicleData::onAdd(%data, %obj)
{
   Parent::onAdd(%data, %obj);
   if((%data.sensorData !$= "") && (%obj.getTarget() != -1))
      setTargetSensorData(%obj.getTarget(), %data.sensorData);
   %obj.setRechargeRate(%data.rechargeRate);
   // set full energy
   %obj.setEnergyLevel(%data.MaxEnergy);

   if(%obj.disableMove)
      %obj.immobilized = true;
   if(%obj.deployed)
   {
      if($countDownStarted)
         %data.schedule(($Host::WarmupTime * 1000) / 2, "vehicleDeploy", %obj, 0, 1);
      else
      {
         $VehiclesDeploy[$NumVehiclesDeploy] = %obj;
         $NumVehiclesDeploy++;
      }
   }
   if(%obj.mountable || %obj.mountable $= "")
      %data.isMountable(%obj, true);
   else
      %data.isMountable(%obj, false);

   %obj.setSelfPowered();
//   %data.canObserve = true;
}

function VehicleData::onRemove(%this, %obj)
{
   // if there are passengers/driver, kick them out
   %this.deleteAllMounted(%obj);
   for(%i = 0; %i < %obj.getDatablock().numMountPoints; %i++)
      if (%obj.getMountNodeObject(%i)) {
         %passenger = %obj.getMountNodeObject(%i);
         %passenger.unmount();
      }
   vehicleListRemove(%obj.getDataBlock(), %obj);
   if(%obj.lastPilot.lastVehicle == %obj)
      %obj.lastPilot.lastVehicle = "";      

   Parent::onRemove(%this, %obj);
}
}

//**************************************************************
//* DAMAGE FUNCTIONS
//**************************************************************

function VehicleData::damageObject(%data, %targetObject, %sourceObject, %position, %amount, %damageType, %momVec, %theClient, %proj)
{  echo("you are damaging an object");

    // check for team damage
    //%sourceClient = %sourceObject ? %sourceObject.getOwnerClient() : 0;
    //%targetTeam = getTargetSensorGroup(%targetObject.getTarget());

    // if(%sourceClient)
    //   %sourceTeam = %sourceClient.getSensorGroup();
    // else if(isObject(%sourceObject) && %sourceObject.getClassName() $= "Turret")
    //   %sourceTeam = getTargetSensorGroup(%sourceObject.getTarget());
    //else
    //   %sourceTeam = %sourceObject ? getTargetSensorGroup(%sourceObject.getTarget()) : -1;

    // vehicles no longer obey team damage -JR
    //    if(!$teamDamage && (%targetTeam == %sourceTeam) && %targetObject.getDamagePercent() > 0.5)
    //       return;
    //but we do want to track the destroyer
    //if(%sourceObject)
    //{
    //    %targetObject.lastDamagedBy = %sourceObject;
    //    %targetObject.lastDamageType = %damageType;
    //}
    //else
    //    %targetObject.lastDamagedBy = 0;

   // Scale damage type & include shield calculations...
   if (%data.isShielded)
      %amount = %data.checkShields(%targetObject, %position, %amount, %damageType);

   %damageScale = %data.damageScale[%damageType];
   if(%damageScale !$= "")
      %amount *= %damageScale;

   if(%amount != 0)
      %targetObject.applyDamage(%amount);

   if(%targetObject.getDamageState() $= "Destroyed" )
   {
      if( %momVec !$= "")
         %targetObject.setMomentumVector(%momVec);
   }
}

function VehicleData::damage(%this,%obj,%type,%vel,%damage,%damageType)
{
   echo("Vehicle IS HIT");
  %obj.applyDamage(%damage);
  if(%obj.getDamageState() $= "Destroyed" )
   {
      %obj.blowUp();
   }
   //Parent::damage(%this, %obj);
}

function VehicleData::onDamage(%this,%obj,%amount)
{
   //called when damage level is changed
   echo("AT DAMAGE TIME");
   %damage = %obj.getDamageLevel();
   //
   echo("damage given by projectile " @ %amount);
   echo("THIS dataBlock is " @ %this.getDataBlock().dataBlock);
   echo("OBJ dataBlock is " @ %obj.dataBlock);//The vehicle
   echo("getEnergyLevel is " @ %this.getEnergyLevel());
   echo("getEnergyValue is " @ %this.getEnergyValue());
   echo("getDamageState is " @  %obj.getDamageState());//enablebed
   echo("getDamageLevel is " @  %obj.getDamageLevel());//the amount of damage taken
   echo("MaxDamage is " @  %this.maxDamage);//amount of damage it can take

   %healthLeft = %this.maxDamage - %damage;
   echo("The Vehicles's health is " @ %healthLeft);
  //if (%damage >= %this.destroyedLevel)
  //GUI should show maxDamage - damageLevel
    if(%damage >= %this.maxDamage)
   {
      if(%obj.getDamageState() !$= "Destroyed")
      {
         if(%obj.respawnTime !$= "")
            %obj.marker.schedule = %obj.marker.data.schedule(%obj.respawnTime, "respawn", %obj.marker); 
         %obj.setDamageState(Destroyed);
      }
   }
   else
   {
      if(%obj.getDamageState() !$= "Enabled")
         %obj.setDamageState(Enabled);
   }
}

function VehicleData::onImpact(%data, %vehicleObject, %collidedObject, %vec, %vecLen)
{
   if(%vecLen > %data.minImpactSpeed)
      %data.damageObject(%vehicleObject, 0, VectorAdd(%vec, %vehicleObject.getPosition()), 
                         %vecLen * %data.speedDamageScale, $DamageType::Ground);

   // associated "crash" sounds
   if(%vecLen > %vDataBlock.hardImpactSpeed)
      %vehicleObject.playAudio(0, %vDataBlock.hardImpactSound);
   else if(%vecLen > %vDataBlock.softImpactSpeed)
      %vehicleObject.playAudio(0, %vDataBlock.softImpactSound);
}         

function VehicleData::damageObject(%data, %targetObject, %sourceObject, %position, %amount, %damageType, %momVec, %theClient, %proj)
{
//{  echo("you are damaging an object");
//   if(%proj !$= "")
//   {
//      if(%amount > 0 && %targetObject.lastDamageProj !$= %proj)
//      {
//         %targetObject.lastDamageProj = %proj;
//         %targetObject.lastDamageAmount = %amount;
//      }
//      else if(%targetObject.lastDamageAmount < %amount)
//         %amount = %amount - %targetObject.lastDamageAmount;
//      else
//         return;
//   }

   // check for team damage
//   %sourceClient = %sourceObject ? %sourceObject.getOwnerClient() : 0;
 //  %targetTeam = getTargetSensorGroup(%targetObject.getTarget());

//   if(%sourceClient)
//      %sourceTeam = %sourceClient.getSensorGroup();
//   else if(isObject(%sourceObject) && %sourceObject.getClassName() $= "Turret")
//      %sourceTeam = getTargetSensorGroup(%sourceObject.getTarget());
//   else
//      %sourceTeam = %sourceObject ? getTargetSensorGroup(%sourceObject.getTarget()) : -1;

    // vehicles no longer obey team damage -JR
//    if(!$teamDamage && (%targetTeam == %sourceTeam) && %targetObject.getDamagePercent() > 0.5)
//       return;
    //but we do want to track the destroyer
//    if(%sourceObject)
//    {
//        %targetObject.lastDamagedBy = %sourceObject;
 //       %targetObject.lastDamageType = %damageType;
//    }
//    else
//        %targetObject.lastDamagedBy = 0;


   // Scale damage type & include shield calculations...
//   if (%data.isShielded)
//      %amount = %data.checkShields(%targetObject, %position, %amount, %damageType);


//   %damageScale = %data.damageScale[%damageType];
//   if(%damageScale !$= "")
//      %amount *= %damageScale;

//   if(%amount != 0)
//      %targetObject.applyDamage(%amount);

//   if(%targetObject.getDamageState() $= "Destroyed" )
//   {
//      if( %momVec !$= "")
//         %targetObject.setMomentumVector(%momVec);
//   }
}

//**************************************************************
//* PLAYER FUNCTIONS
//**************************************************************

//PLAYER: Dismount
function VehicleData::playerDismounted(%data, %obj, %player)
{
   if( %player.client.observeCount > 0 )
      resetObserveFollow( %player.client, true );

   setTargetSensorGroup(%obj.getTarget(), %obj.team);
   
   // if there is a turret, set its team as well.
   if( %obj.turretObject > 0 )
      setTargetSensorGroup(%obj.turretObject.getTarget(), %obj.team);
}

function VehicleData::onEnterLiquid(%data, %obj, %coverage, %type)
{
   switch(%type)
   {
      case 0:
         //Water
         %obj.setHeat(0.0);
      case 1:
         //Ocean Water
         %obj.setHeat(0.0);
      case 2:
         //River Water
         %obj.setHeat(0.0);
      case 3:
         //Stagnant Water
         %obj.setHeat(0.0);
      case 4:
         //Lava
         %obj.liquidDamage(%data, $VehicleDamageLava, $DamageType::Lava);
      case 5:
         //Hot Lava
         %obj.liquidDamage(%data, $VehicleDamageHotLava, $DamageType::Lava);
      case 6:    
         //Crusty Lava
         %obj.liquidDamage(%data, $VehicleDamageCrustyLava, $DamageType::Lava);
      case 7:
         //Quick Sand
   }
}

function VehicleData::onLeaveLiquid(%data, %obj, %type)
{
   switch(%type)
   {
      case 0:
         //Water
         %obj.setHeat(1.0);
      case 1:
         //Ocean Water
         %obj.setHeat(1.0);
      case 2:
         //River Water
         %obj.setHeat(1.0);
      case 3:
         //Stagnant Water
         %obj.setHeat(1.0);
      case 4:
         //Lava
      case 5:
         //Hot Lava
      case 6:
         //Crusty Lava
      case 7:
         //Quick Sand
   }

   if(%obj.lDamageSchedule !$= "")
   {
      cancel(%obj.lDamageSchedule);
      %obj.lDamageSchedule = "";
   }
}

function FlyingVehicle::liquidDamage(%obj, %data, %damageAmount, %damageType)
{
   if(%obj.getDamageState() !$= "Destroyed")
   {
      %data.damageObject(%obj, 0, "0 0 0", %damageAmount, %damageType); 
      %obj.lDamageSchedule = %obj.schedule(50, "liquidDamage", %data, %damageAmount, %damageType);
      passengerLiquidDamage(%obj, %damageAmount, %damageType);
   }
   else
      %obj.lDamageSchedule = "";
}

function WheeledVehicle::liquidDamage(%obj, %data, %damageAmount, %damageType)
{
   if(%obj.getDamageState() !$= "Destroyed")
   {
      %data.damageObject(%obj, 0, "0 0 0", %damageAmount, %damageType); 
      %obj.lDamageSchedule = %obj.schedule(50, "liquidDamage", %data, %damageAmount, %damageType);
      passengerLiquidDamage(%obj, %damageAmount, %damageType);
   }
   else
      %obj.lDamageSchedule = "";
}

function HoverVehicle::liquidDamage(%obj, %data, %damageAmount, %damageType)
{
   if(%obj.getDamageState() !$= "Destroyed")
   {
      %data.damageObject(%obj, 0, "0 0 0", %damageAmount, %damageType); 
      %obj.lDamageSchedule = %obj.schedule(50, "liquidDamage", %data, %damageAmount, %damageType);
      passengerLiquidDamage(%obj, %damageAmount, %damageType);
   }
   else
      %obj.lDamageSchedule = "";
}

function assengerLiquidDamage(%obj, %damageAmount, %damageType)
{
   for(%i = %num; %i < %obj.getDataBlock().numMountPoints; %i++)
      if (%p = %obj.getMountNodeObject(%i))
         %p.liquidDamage(%p.getDatablock(), $DamageLava, $DamageType::Lava);
}

function VehicleData::onDestroyed(%data, %obj, %prevState)
{
    if(%obj.lastDamagedBy)
    {
        %destroyer = %obj.lastDamagedBy;
        game.vehicleDestroyed(%obj, %destroyer);
        //error("vehicleDestroyed( "@ %obj @", "@ %destroyer @")");
    }
    
	radiusVehicleExplosion(%data, %obj);
   if(%obj.turretObject)
      if(%obj.turretObject.getControllingClient())
         %obj.turretObject.getDataBlock().playerDismount(%obj.turretObject);
   for(%i = 0; %i < %obj.getDatablock().numMountPoints; %i++)
   {
      if (%obj.getMountNodeObject(%i)) {
         %flingee = %obj.getMountNodeObject(%i);
         %flingee.getDataBlock().doDismount(%flingee, true);
         %xVel = 250.0 - (getRandom() * 500.0);
         %yVel = 250.0 - (getRandom() * 500.0);
         %zVel = (getRandom() * 100.0) + 50.0;
         %flingVel = %xVel @ " " @ %yVel @ " " @ %zVel;
         %flingee.applyImpulse(%flingee.getTransform(), %flingVel);
         echo("got player..." @ %flingee.getClassName());
         %flingee.damage(0, %obj.getPosition(), 0.4, $DamageType::Crash); 
      }
   }

   %data.deleteAllMounted(%obj);
   %obj.schedule(2000, "delete");
}

function radiusVehicleExplosion(%data, %vehicle)
{
	// this is a modified version of RadiusExplosion() from projectiles.cs
	%position = %vehicle.getPosition();
   InitContainerRadiusSearch(%position, %data.explosionRadius, $TypeMasks::PlayerObjectType      |
                                                 $TypeMasks::VehicleObjectType     |
                                                 $TypeMasks::MoveableObjectType    |
                                                 $TypeMasks::StaticShapeObjectType |
                                                 $TypeMasks::ForceFieldObjectType  |
                                                 $TypeMasks::TurretObjectType      |
                                                 $TypeMasks::ItemObjectType);

   %numTargets = 0;
   while ((%targetObject = containerSearchNext()) != 0)
   {
		if(%targetObject == %vehicle)
			continue;

      %dist = containerSearchCurrRadDamageDist();

      if (%dist > %data.explosionRadius)
         continue;

      if (%targetObject.isMounted())
      {
         %mount = %targetObject.getObjectMount();
			if(%mount == %vehicle)
				continue;

         %found = -1;
         for (%i = 0; %i < %mount.getDataBlock().numMountPoints; %i++)
         {
            if (%mount.getMountNodeObject(%i) == %targetObject)
            {
               %found = %i;
               break;
            }
         }
      
         if (%found != -1)
         {
            if (%mount.getDataBlock().isProtectedMountPoint[%found] && (%mount != %vehicle))
               continue;
         }
      }

      %targets[%numTargets]     = %targetObject;
      %targetDists[%numTargets] = %dist;
      %numTargets++;
   }

   for (%i = 0; %i < %numTargets; %i++)
   {
      %targetObject = %targets[%i];
      %dist = %targetDists[%i];

      %coverage = calcExplosionCoverage(%position, %targetObject,
                                        ($TypeMasks::InteriorObjectType |
                                         $TypeMasks::TerrainObjectType |
                                         $TypeMasks::ForceFieldObjectType));
      if (%coverage == 0)
         continue;

      %amount = (1.0 - (%dist / %data.explosionRadius)) * %coverage * %data.explosionDamage;
      %targetData = %targetObject.getDataBlock();

      %momVec = "0 0 1";
      
      if(%amount > 0)
         %targetData.damageObject(%targetObject, %sourceObject, %position, %amount, $DamageType::Explosion, %momVec);
   }
}

function VehicleData::deleteAllMounted()
{
// urm...
};

//**************************************************************
//* VEHICLE CREATION
//**************************************************************

function HoverVehicle::useCreateHeight()
{
	//this function is declared to prevent console error msg spam...
}

function WheeledVehicle::useCreateHeight()
{
	//this function is declared to prevent console error msg spam...
}

//**************************************************************
//* MULTI-CREW VEHICLE DELETION
//**************************************************************


//----------------------------
// THUNDERSWORD BOMBER
//----------------------------

function BomberFlyer::deleteAllMounted(%data, %obj)
{
   if(isObject(%obj.beacon))
      %obj.beacon.delete();

   %turret = %obj.getMountNodeObject(10);
   if(!%turret)
      return;

   %turret.altTrigger = 0;
   %turret.fireTrigger = 0;
   
   if(%client = %turret.getControllingClient())
   {
      commandToClient(%client, 'endBomberSight');
      %client.player.setControlObject(%client.player);
      %client.player.mountImage(%client.player.lastWeapon, $WeaponSlot);
      %client.player.mountVehicle = false;

      %client.player.bomber = false;
      %client.player.isBomber = false;
   }
   %turret.delete();
}

//**************************************************************
//* WEAPON MOUNTING ON VEHICLES
//**************************************************************

//----------------------------
// SKY HAWK FLIER
//----------------------------

function buildPassengerString(%vehicle)
{
   %passStr = "";
   for(%i = 0; %i < %vehicle.getDatablock().numMountPoints; %i++)
   {
      if(%vehicle.getMountNodeObject(%i) > 0)
         %passStr = %passStr @ "1 ";
      else
         %passStr = %passStr @ "0 ";
   }
   return %passStr;
}

function WheeledVehicle::deployVehicle(%obj, %data, %player)
{
   if (!%data.vehicleDeploy(%obj, %player))
      %obj.schedule(500, "deployVehicle", %data, %player);
}

//**************************************************************
//* VEHICLE INVENTORY MANAGEMENT
//**************************************************************

//--------------------------------------------------------------
// NUMBER OF PURCHASEABLE VEHICLES PER TEAM
//--------------------------------------------------------------

$VehicleRespawnTime        = 15000;
$Vehiclemax[ScoutVehicle]     = 4;
$VehicleMax[AssaultVehicle]   = 3;
$VehicleMax[MobileBaseVehicle]  = 1;
$VehicleMax[ScoutFlyer]       = 4;
$VehicleMax[BomberFlyer]      = 2;
$VehicleMax[HAPCFlyer]        = 2;

function vehicleListRemove(%data, %obj)
{
   %blockName = %data.getName();
   for($i = 0; %i < $VehicleMax[%blockName]; %i++)
      if($VehicleInField[%obj.team, %blockName, %i] == %obj)
      {
         $VehicleInField[%obj.team, %blockName, %i] = 0;
         $VehicleTotalCount[%obj.team, %blockName]--;   
         break;
      }
   }
}

function vehicleListAdd(%blockName, %obj)
{
   for($i = 0; %i < $VehicleMax[%blockName]; %i++)
   {
      if($VehicleInField[%obj.team, %blockName, %i] $= "" || $VehicleInField[%obj.team, %blockName, %i] == 0)
      {
         $VehicleInField[%obj.team, %blockName, %i] = %obj;
         $VehicleTotalCount[%obj.team, %blockName]++;   
         break;
      }      
   }
}

function clearVehicleCount(%team)
{
   $VehicleTotalCount[%team, ScoutVehicle]      = 0;
   $VehicleTotalCount[%team, AssaultVehicle]    = 0;
   $VehicleTotalCount[%team, MobileBaseVehicle] = 0;
   $VehicleTotalCount[%team, ScoutFlyer]        = 0;
   $VehicleTotalCount[%team, BomberFlyer]       = 0;
   $VehicleTotalCount[%team, HAPCFlyer]         = 0;
}

//**************************************************************
//* VEHICLE HUD - SEAT - INDICATOR LIGHTS
//**************************************************************

function findEmptySeat(%vehicle, %vehicleblock)
{
 for (%i = 0; %i <  %vehicleblock.numMountPoints; %i++)
 {
        %node = %vehicle.getMountNodeObject(%i);
        if (%node == 0)
          {
         return %i;
          }
  }
 return -1;
}

function findAIEmptySeat(%vehicle)
{
 %num = 0;
	%node = -1;
	for(%i = %num; %i < %vehicle.numMountPoints; %i++)
	{
	   if (!%vehicle.getMountNodeObject(%i))
	   {
	      //cheap hack - for now, will mount the next available node regardless of where they collided
	      %node = %i;
	      break;
	   }
	}
	//return the empty seat
	return %node;
}

function findFirstHeavyNode(%data)
{
   for(%i = 0; %i < %data.numMountPoints; %i++)
      if(%data.mountPose[%i] $= "")
         return %i;
   return %data.numMountPoints;
}

//**************************************************************
//* VEHICLE TIMEOUTS
//**************************************************************

function vehicleAbandonTimeOut(%vehicle)
{
   if(%vehicle.getDatablock().cantAbandon $= "" && %vehicle.lastPilot $= "")
   {
      for(%i = 0; %i < %vehicle.getDatablock().numMountPoints; %i++)
         if (%vehicle.getMountNodeObject(%i))
         {
            %passenger = %vehicle.getMountNodeObject(%i);
            if(%passenger.lastVehicle !$= "")
               schedule(15000, %passenger.lastVehicle,"vehicleAbandonTimeOut", %passenger.lastVehicle);
            %passenger.lastVehicle = %vehicle;   
            %vehicle.lastPilot = %passenger;   
            return;
         }
      
      if(%vehicle.respawnTime !$= "")
         %vehicle.marker.schedule = %vehicle.marker.data.schedule(%vehicle.respawnTime, "respawn", %vehicle.marker); 
      %vehicle.mountable = 0;
      %vehicle.startFade(1000, 0, true);
      %vehicle.schedule(1001, "delete");
      }
   }
}

//**************************************************************
//* VEHICLE CREATE
//**************************************************************
function HoverVehicleData::create(%block, %team, %oldObj)
{
   if(%oldObj $= "")
   {
      %obj = new HoverVehicle() 
      {
         dataBlock  = %block;
         respawn    = "0";
         teamBought = %team;
         team = %team;
      };
   }
   else
   {
      %obj = new HoverVehicle() 
      {
         dataBlock  = %data;
         respawn    = "0";
         teamBought = %team;
         team = %team;
         mountable = %oldObj.mountable;
         disableMove = %oldObj.disableMove;
         resetPos = %oldObj.resetPos;
         respawnTime = %oldObj.respawnTime;
         marker = %oldObj;
      }; 
   }
   return(%obj);
}

function WheeledVehicleData::create(%data, %team, %oldObj)
{
   if(%oldObj $= "")
   {
      %obj = new WheeledVehicle() 
      {
         dataBlock  = %data;
         respawn    = "0";
         teamBought = %team;
         team = %team;
      };
   }
   else
   {
      %obj = new WheeledVehicle() 
      {
         dataBlock  = %data;
         respawn    = "0";
         teamBought = %team;
         team = %team;
         mountable = %oldObj.mountable;
         disableMove = %oldObj.disableMove;
         resetPos = %oldObj.resetPos;
         deployed = %oldObj.deployed;
         respawnTime = %oldObj.respawnTime;
         marker = %oldObj;
      };   
   }
   
   return(%obj);
}

function FlyingVehicleData::create(%data, %team, %oldObj)
{
   if(%oldObj $= "")
   {
      %obj = new FlyingVehicle() 
      {
         dataBlock  = %data;
         respawn    = "0";
         teamBought = %team;
         team = %team;
      };
   }      
   else
   {
      %obj = new FlyingVehicle() 
      {
         dataBlock  = %data;
         teamBought = %team;
         team = %team;
         mountable = %oldObj.mountable;
         disableMove = %oldObj.disableMove;
         resetPos = %oldObj.resetPos;
         respawnTime = %oldObj.respawnTime;
         marker = %oldObj;
      };      
   }
   
   return(%obj);
}
                                    
function FlyingVehicleData::switchSidesSetPos(%data, %oldObj)
{
   %team = %oldObj.curTeam == 1 ? 2 : 1;
   %oldObj.curTeam = %team;
   %obj = new FlyingVehicle() 
   {
      dataBlock  = %data;
      teamBought = %team;
      team = %team;
      mountable = %oldObj.mountable;
      disableMove = %oldObj.disableMove;
      resetPos = %oldObj.resetPos;
      respawnTime = %oldObj.respawnTime;
      marker = %oldObj;
   };   
   %obj.setTransform(%oldObj.getTransform());

   return(%obj);
}

function WheeledVehicleData::switchSidesSetPos(%data, %oldObj)
{
   %team = %oldObj.curTeam == 1 ? 2 : 1;
   %oldObj.curTeam = %team;
   %obj = new WheeledVehicle() 
   {
      dataBlock  = %data;
      respawn    = "0";
      teamBought = %team;
      team = %team;
      mountable = %oldObj.mountable;
      disableMove = %oldObj.disableMove;
      resetPos = %oldObj.resetPos;
      deployed = %oldObj.deployed;
      respawnTime = %oldObj.respawnTime;
      marker = %oldObj;
   };   
   %obj.setTransform(%oldObj.getTransform());
   return(%obj);
}

function HoverVehicleData::switchSidesSetPos(%data, %oldObj)
{
   %team = %oldObj.curTeam == 1 ? 2 : 1;
   %oldObj.curTeam = %team;
   %obj = new HoverVehicle() 
   {
      dataBlock  = %data;
      respawn    = "0";
      teamBought = %team;
      team = %team;
      mountable = %oldObj.mountable;
      disableMove = %oldObj.disableMove;
      resetPos = %oldObj.resetPos;
      respawnTime = %oldObj.respawnTime;
      marker = %oldObj;
   }; 
   %obj.setTransform(%oldObj.getTransform());
   return(%obj);
}

function resetNonStaticObjPositions()
{
   MissionGroup.setupPositionMarkers(false);
   MissionCleanup.positionReset();
}

function next(%team)
{
   ResetObjsPositions(%team);
}

function SimGroup::positionReset(%group)
{
   for(%i = %group.getCount() - 1; %i >=0 ; %i--)
   {               
      %obj = %group.getObject(%i);
      if(%obj.resetPos && %obj.getName() !$= PosMarker)
         %obj.delete();
      else
         %obj.positionReset();
   }

   for(%i = 0; %i < %group.getCount(); %i++)
   {
      %obj = %group.getObject(%i);
      if(%obj.getName() $= PosMarker)
      {
         cancel(%obj.schedule);
         %newObj =  %obj.data.switchSidesSetPos(%obj);
         MissionCleanup.add(%newObj);
         setTargetSensorGroup(%newObj.target, %newObj.team);
      }
      else 
         %obj.positionReset();
   }
}

function VehicleData::respawn(%data, %marker)
{
   %mask = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::TurretObjectType;
   InitContainerRadiusSearch(%marker.getWorldBoxCenter(), %data.checkRadius, %mask);
   if(containerSearchNext() == 0)    
   {
      %newObj = %data.create(%marker.curTeam, %marker);
      %newObj.startFade(1000, 0, false);
      %newObj.setTransform(%marker.getTransform());

      setTargetSensorGroup(%newObj.target, %newObj.team);
      MissionCleanup.add(%newObj);
   }
   else
   {
      %marker.schedule = %data.schedule(3000, "respawn", %marker);
   }
}

function SimObject::positionReset(%group, %team)
{
   //Used to avoid warnings
}

function Terraformer::positionReset(%group, %team)
{
   //Used to avoid warnings
}

function SimGroup::setupPositionMarkers(%group, %create)
{
   for(%i = %group.getCount() - 1; %i >= 0; %i--)
   {               
      %obj = %group.getObject(%i);
      if(%obj.resetPos || %obj.respawnTime !$= "")
      {
         if(%create)
         {
            %marker = %obj.getDataBlock().createPositionMarker(%obj);
            MissionCleanup.add(%marker);
            %obj.marker = %marker;
         }
         else
         {
            %obj.delete();
         }
      }
      else
         %obj.setupPositionMarkers(%create);
   }               
}

function SimObject::setupPositionMarkers(%group, %create)
{
   //Used to avoid warnings
}

function VehicleData::createPositionMarker(%data, %obj)
{
   %marker = new Trigger(PosMarker)
   {
      dataBlock = markerTrigger;
      mountable = %obj.mountable;
      disableMove = %obj.disableMove;
      resetPos = %obj.resetPos;
      data = %obj.getDataBlock().getName();
      deployed = %obj.deployed;
      curTeam = %obj.team;
      respawnTime = %obj.respawnTime;
   };   
   %marker.setTransform(%obj.getTransform());
   return %marker;
}

function VehicleData::hasDismountOverrides(%data, %obj)
{
   return false;
}