Provides an AI controlled turret. Uses the AITurretShapeData datablock, which is based on the
TurretShapeData datablock for common properties.
AITurretShape builds an AI controlled turret. It uses a state machine and properties as defined in
AITurretShapeData to decide how to find targets and what to do with them. As with
TurretShape (which AITurretShape derives from) the
AITurretShape class provides the base on which
ShapeBaseImageData weapons may be mounted.
Overview
The AITurretShape functions through the use of a state machine as defined in its
AITurretShapeData datablock. It is very similar to how
ShapeBaseImageData
works. This allows you to customize exactly how the turret behaves
while it searches for a target, and what it does once it has a target.
But in general, the AI turret goes through a number of stages:
Scanning
The AI turret usually starts off by scanning for a suitable target.
This is done by checking for targets within a pie wedge shaped volume in
front of the turret based on where the scanPoint node is placed. The
turret takes cover into account when searching for a target so that it
doesn't "cheat".
Gained Target
Once a target is acquired the turret attempts to follow it. Usually
at this point the turret activates its weapon. If a target is lost due
to it going behind cover, the turret will attempt to follow and
reacquire the target using its last known position and velocity. The
amount of time allowed for this attempt is defined by AITurretShapeData::trackLostTargetTime.
Lost Target
If the target is lost (either by going behind cover or it is dead)
the turret returns to its scanning mode to find another victim.
Destroyed
If the AI turret is destroyed then it can go into a special state to show the user that it has been destroyed. As with
TurretShape turrets a
AITurretShape may respawn after a set amount of time (see
TurretShape and TurretShape::doRespawn()).
Deployable Turret
In addition to AI turrets being placed within a mission, it is also
possible for a player to deploy a turret such as throwing one from their
inventory. When a turret has been tossed it will be in a Thrown state and usually in an inactive mode. Once the turret comes to rest on the ground it moves into a Deploy
state where it may unfold to get ready. Once ready the turret begins
the scanning process. As the AI turret's state machine may be customized
for your specific circumstances, the way in which turrets are deployed
by a player is up to you. An AI turret could be thrown in a fully
working state, ready to take out targets before the turret even hits the
ground.
Example State Machine
Here is an example AITurretShapeData datablock with a defined state machine and the script to support the state machine. This is just one possible example.
Example:
//-----------------------------------------------------------------------------// AI Turret//-----------------------------------------------------------------------------
datablock AITurretShapeData(AITurret)
{
category = "Turrets";
shapeFile = "art/shapes/weapons/Turret/Turret_Legs.DAE";
maxDamage = 70;
destroyedLevel = 70;
explosion = GrenadeExplosion;
simpleServerCollision = false;
zRotOnly = false;
// Rotation settings
minPitch = 15;
maxPitch = 80;
maxHeading = 90;
headingRate = 50;
pitchRate = 50;
// Scan settings
maxScanPitch = 10;
maxScanHeading = 30;
maxScanDistance = 20;
trackLostTargetTime = 2;
maxWeaponRange = 30;
weaponLeadVelocity = 0;
// Weapon mounting
numWeaponMountPoints = 1;
weapon[0] = AITurretHead;
weaponAmmo[0] = AITurretAmmo;
weaponAmmoAmount[0] = 10000;
maxInv[AITurretHead] = 1;
maxInv[AITurretAmmo] = 10000;
// Initial start up state
stateName[0] = "Preactivate";
stateTransitionOnAtRest[0] = "Scanning";
stateTransitionOnNotAtRest[0] = "Thrown";
// Scan for targets
stateName[1] = "Scanning";
stateScan[1] = true;
stateTransitionOnTarget[1] = "Target";
stateSequence[1] = "scan";
stateScript[1] = "OnScanning";
// Have a target
stateName[2] = "Target";
stateTransitionOnNoTarget[2] = "NoTarget";
stateTransitionOnTimeout[2] = "Firing";
stateTimeoutValue[2] = 2.0;
stateScript[2] = "OnTarget";
// Fire at target
stateName[3] = "Firing";
stateFire[3] = true;
stateTransitionOnNoTarget[3] = "NoTarget";
stateScript[3] = "OnFiring";
// Lost target
stateName[4] = "NoTarget";
stateTransitionOnTimeout[4] = "Scanning";
stateTimeoutValue[4] = 2.0;
stateScript[4] = "OnNoTarget";
// Player thrown turret
stateName[5] = "Thrown";
stateTransitionOnAtRest[5] = "Deploy";
stateSequence[5] = "throw";
stateScript[5] = "OnThrown";
// Player thrown turret is deploying
stateName[6] = "Deploy";
stateTransitionOnTimeout[6] = "Scanning";
stateTimeoutValue[6] = 2.5;
stateSequence[6] = "deploy";
stateScaleAnimation[6] = true;
stateScript[6] = "OnDeploy";
// Special state that is set when the turret is destroyed.// This state is set in the onDestroyed() callback.
stateName[7] = "Destroyed";
stateSequence[7] = "destroyed";
};
//-----------------------------------------------------------------------------// Deployable AI Turret//-----------------------------------------------------------------------------
datablock AITurretShapeData(DeployableTurret : AITurret)
{
// Mission editor category
category = "Weapon";
className = "DeployableTurretWeapon";
startLoaded = false;
// Basic Item properties
mass = 1.5;
elasticity = 0.1;
friction = 0.6;
simpleServerCollision = false;
// Dynamic properties defined by the scripts
PreviewImage = 'turret.png';
pickUpName = "a deployable turret";
description = "Deployable Turret";
image = DeployableTurretImage;
reticle = "blank";
zoomReticle = 'blank';
};
// ----------------------------------------------------------------------------// AITurretShapeData// ----------------------------------------------------------------------------
function AITurretShapeData::onAdd(%this, %obj)
{
Parent::onAdd(%this, %obj);
%obj.mountable = false;
}
// Player has thrown a deployable turret. This copies from ItemData::onThrow()
function AITurretShapeData::onThrow(%this, %user, %amount)
{
// Remove the object from the inventoryif (%amount $= "")
%amount = 1;
if (%this.maxInventory !$= "")
if (%amount > %this.maxInventory)
%amount = %this.maxInventory;
if (!%amount)
return 0;
%user.decInventory(%this,%amount);
// Construct the actual object in the world, and add it to// the mission group so it's cleaned up when the mission is// done. The turret's rotation matches the player's.
%rot = %user.getEulerRotation();
%obj = new AITurretShape()
{
datablock = %this;
rotation = "0 0 1 " @ getWord(%rot, 2);
count = 1;
sourceObject = %user;
client = %user.client;
isAiControlled = true;
};
MissionGroup.add(%obj);
// Let the turret know that we're a firend
%obj.addToIgnoreList(%user);
// We need to add this turret to a list on the client so that if we die,// the turret will still ignore our player.
%client = %user.client;
if (%client)
{
if (!%client.ownedTurrets)
{
%client.ownedTurrets = new SimSet();
}
// Go through the client's owned turret list. Make sure we're// a friend of every turret and every turret is a friend of ours.// Commence hugging!for (%i=0; %i<%client.ownedTurrets.getCount(); %i++)
{
%turret = %client.ownedTurrets.getObject(%i);
%turret.addToIgnoreList(%obj);
%obj.addToIgnoreList(%turret);
}
// Add ourselves to the client's owned list.
%client.ownedTurrets.add(%obj);
}
return %obj;
}
function AITurretShapeData::onDestroyed(%this, %turret, %lastState)
{
// This method is invoked by the ShapeBase code whenever the// object's damage state changes.
%turret.playAudio(0, TurretDestroyed);
%turret.setAllGunsFiring(false);
%turret.resetTarget();
%turret.setTurretState( "Destroyed", true );
// Set the weapons to destoryedfor(%i = 0; %i < %this.numWeaponMountPoints; %i++)
{
%turret.setImageGenericTrigger(%i, 0, true);
}
Parent::onDestroyed(%this, %turret, %lastState);
}
function AITurretShapeData::OnScanning(%this, %turret)
{
//echo("AITurretShapeData::OnScanning: " SPC %this SPC %turret);
%turret.startScanForTargets();
%turret.playAudio(0, TurretScanningSound);
}
function AITurretShapeData::OnTarget(%this, %turret)
{
//echo("AITurretShapeData::OnTarget: " SPC %this SPC %turret);
%turret.startTrackingTarget();
%turret.playAudio(0, TargetAquiredSound);
}
function AITurretShapeData::OnNoTarget(%this, %turret)
{
//echo("AITurretShapeData::OnNoTarget: " SPC %this SPC %turret);
%turret.setAllGunsFiring(false);
%turret.recenterTurret();
%turret.playAudio(0, TargetLostSound);
}
function AITurretShapeData::OnFiring(%this, %turret)
{
//echo("AITurretShapeData::OnFiring: " SPC %this SPC %turret);
%turret.setAllGunsFiring(true);
}
function AITurretShapeData::OnThrown(%this, %turret)
{
//echo("AITurretShapeData::OnThrown: " SPC %this SPC %turret);
%turret.playAudio(0, TurretThrown);
}
function AITurretShapeData::OnDeploy(%this, %turret)
{
//echo("AITurretShapeData::OnDeploy: " SPC %this SPC %turret);// Set the weapons to loadedfor(%i = 0; %i < %this.numWeaponMountPoints; %i++)
{
%turret.setImageLoaded(%i, true);
}
%turret.playAudio(0, TurretActivatedSound);
}
And here is the above example state machine's flow:
Shape File Nodes
In addition to the required TurretBase nodes, AITurretShape
makes use of additional nodes within the shape file to allow the AI to
do its work. The first is the 'scanPoint' node. This is used by the AI
to project a pie wedge shaped scanning volume in which to detect
possible targets. The scanPoint node is at the apex of the scanning
wedge. If the scanPoint node is not present within the shape file then
the turret's world transform is used.
The second is the 'aimPoint' node. Once the AI turret has obtained a
target the aimPoint is used to point the turret at the target.
Specifically, the turret rotates in both pitch and heading such that the
aimPoint points at the target. If you're using a weapon that doesn't
have its muzzle point on the same plane as its mount point (known as an
off-axis weapon) then be sure to place the aimPoint at a z position
equivalent to the weapon's muzzle point. This allows for the correct
pitch calculation. If the aimPoint is not found on the turret's shape,
then the pitch node will be used.
Ignore List
AI turrets keep track of an ignore list. This is used by default to
stop a player deployed turret from targeting its owner, even when that
owner is killed and respawns. But this ignore list could also be used to
have the turret ignore team mates, squad members, invisible players,
etc. Use AITurretShape::addToIgnoreList() and
AITurretShape::removeFromIgnoreList()
to manipulate this list. You should also look in
scripts/server/turret.cs at AITurretShapeData::onThrow() to see how the
ignore list is handled and deployed turrets are kept track of on a per
connected client basis.
See also:
AITurretShapeData
TurretShape
TurretShapeData
ShapeBaseImageData
Member Function Documentation
void AITurretShape::activateTurret
(
)
Activate a turret from a deactive state.
void AITurretShape::addToIgnoreList
(
ShapeBase
obj
)
Adds object to the turret's ignore list.
All objects in this list will be ignored by the turret's targeting.
Parameters:
obj
The
ShapeBase object to ignore.
void AITurretShape::deactivateTurret
(
)
Deactivate a turret from an active state.
SimObject AITurretShape::getTarget
(
)
Get the turret's current target.
Returns:
The object that is the target's current target, or 0 if no target.
float AITurretShape::getWeaponLeadVelocity
(
)
Get the turret's defined projectile velocity that helps with target leading.
Returns:
The defined weapon projectile speed, or 0 if leading is disabled.
bool AITurretShape::hasTarget
(
)
Indicates if the turret has a target.
Returns:
True if the turret has a target.
void AITurretShape::recenterTurret
(
)
Recenter the turret's weapon.
void AITurretShape::removeFromIgnoreList
(
ShapeBase
obj
)
Removes object from the turret's ignore list.
All objects in this list will be ignored by the turret's targeting.
Parameters:
obj
The
ShapeBase object to once again allow for targeting.
void AITurretShape::resetTarget
(
)
Resets the turret's target tracking.
Only resets the internal target tracking. Does not modify the turret's facing.
void AITurretShape::setAllGunsFiring
(
bool
fire
)
Set the firing state of the turret's guns.
Parameters:
fire
Set to true to activate all guns. False to deactivate them.
void AITurretShape::setGunSlotFiring
(
int
slot,
bool
fire
)
Set the firing state of the given gun slot.
Parameters:
slot
The gun to modify. Valid range is 0-3 that corresponds to the weapon mount point.
fire
Set to true to activate the gun. False to deactivate it.
void AITurretShape::setTurretState
(
string
newState,
bool
force = false
)
Set the turret's current state.
Normally the turret's state comes from updating the state machine but
this method allows you to override this and jump to the requested state
immediately.
Parameters:
newState
The name of the new state.
force
Is
true then force the full processing of the new state even if it is the
same as the current state. If false then only the time out value is
reset and the state's script method is called, if any.
void AITurretShape::setWeaponLeadVelocity
(
float
velocity
)
Set the turret's projectile velocity to help lead the target.
This value normally comes from AITurretShapeData::weaponLeadVelocity
but this method allows you to override the datablock value. This can be
useful if the turret changes ammunition, uses a different weapon than
the default, is damaged, etc.
Note:
Setting this to 0 will disable target leading.
void AITurretShape::startScanForTargets
(
)
Begin scanning for a target.
void AITurretShape::startTrackingTarget
(
)
Have the turret track the current target.
void AITurretShape::stopScanForTargets
(
)
Stop scanning for targets.
Note:
Only impacts the scanning for new targets. Does not effect a turret's current target lock.
void AITurretShape::stopTrackingTarget
(
)
Stop the turret from tracking the current target.
AITurretShapeData
The following shows all datablock fields for an AITurretShapeData, which is required to create a new AI Turret.
Member Data Documentation
float AITurretShapeData::maxScanDistance
Maximum distance to scan.
When combined with maxScanHeading and maxScanPitch this forms a 3D scanning wedge used to initially locate a target.
float AITurretShapeData::maxScanHeading
Maximum number of degrees to scan left and right.
Note:
Maximum scan heading is 90 degrees.
float AITurretShapeData::maxScanPitch
Maximum number of degrees to scan up and down.
Note:
Maximum scan pitch is 90 degrees.
float AITurretShapeData::maxWeaponRange
Maximum distance that the weapon will fire upon a target.
int AITurretShapeData::scanTickFrequency
How often should we perform a full scan when looking for a target.
Expressed as the number of ticks between full scans, but no less than 1.
int AITurretShapeData::scanTickFrequencyVariance
Random amount that should be added to the scan tick frequency each scan period.
Expressed as the number of ticks to randomly add, but no less than zero.
bool AITurretShapeData::stateDirection[31]
Direction of the animation to play in this state.
True is forward, false is backward.
bool AITurretShapeData::stateFire[31]
The first state with this set to true is the state entered by the client when it receives the 'fire' event.
caseString AITurretShapeData::stateName[31]
Name of this state.
bool AITurretShapeData::stateScaleAnimation[31]
If true, the timeScale of the stateSequence animation will be
adjusted such that the sequence plays for stateTimeoutValue seconds.
bool AITurretShapeData::stateScan[31]
Indicates the turret should perform a continuous scan looking for targets.
AITurretShapeData::stateScript[31]
Method to execute on entering this state. is state. AITurretShapeData.
string AITurretShapeData::stateSequence[31]
Name of the sequence to play on entry to this state. is state.
AITurretShapeData::stateTimeoutValue[31]
Time in seconds to wait before transitioning to stateTransitionOnTimeout. nTimeout.
AITurretShapeData::stateTransitionOnActivated[31]
Name of the state to transition to when the turret goes from deactivated to activated. ctivated.
AITurretShapeData::stateTransitionOnAtRest[31]
Name of the state to transition to when the turret is at rest (static). (static).