TribesReplay/base/scripts/aiObjectives.cs
Robert MacGregor b1941454ec v22228 (04/06/01):
* Fixed a problem that could have caused texture leaking in the interiors
* Fixed an AI problem in Training 2
* Chinese "simplified" keyboard supported
* Korean keyboard supported
* A bug where infinite ammo could be gained by tossing the ammo was prevented.
* Fixed a problem in Training 2 where a waypoint wouldn't update properly.
* Thundersword and Havoc hold steady now when players try to jump in so they don't invert and detonate.
* CD is now required in the drive for on-line play.
* Scoring has been fixed so that it isn't blanked any longer if the admin changes the time limit during a game.
* Active server queries will be cancelled now when you join a game (loads game faster now).
* If standing in an inventory station when it is destroyed you no longer permanently lose weapons.
* Fixed two issues that *could* cause crashes.
* Fixed a problem where the bombardier could create a permanent targeting laser.
* Cleaned up Chat text to remove programming characters.
* Fixed "highlight text with my nick" option so it saves preference to file correctly.
* Made MPB able to climb hills more easily and reduced damage from impact with the ground.
* Added button to stop server queries in progress on "JOIN" screen.
* Observers can now only chat with other observers (no one else can hear them).
* Made deployable inv stations have smaller trigger so they don't "suck you in" from so far away.
* Bots will now claim switches in CnH more accurately.
* Added a "max distance" ring for sensors on the commander map so players can more accurately assess how well they placed the sensor in relation to how much area it is actually sensing.
* Added a "ding" sound when you have filled up a text buffer so that you know why your text isn't showing up.
* Fixed Chat HUD so that page up/page down works better.
* Fixed a situation where Heavies could end up being permanently cloaked.
* The MPBs on the "Alcatraz" map now deploy correctly (Siege map).
* The "edited post" date stamp now works correctly.
* If you jump into a vehicle while zoomed in, the zoom will reset correctly therafter now.
* The Score Screen (F2) is now available while in a vehicle.
* You can now vote to kick observers, if desired.
* The ELF turret is fixed so it no longer fires at players when destroyed (an intermittent bug)
* Some console spam associated with the Wildcat has been removed.
* There was a situation where a player could die twice if he fell out of bounds. That has been resolved.
* Screen resolution information should update properly now when restarting the application.
* The camera should no longer be able to dip below terrain when in third person mode.
2017-07-17 23:05:21 -04:00

3810 lines
118 KiB
C#

//------------------------------
//AI Objective Q functions...
$ObjectiveClientsSet = 0;
function AIObjectiveFindClients(%objective)
{
//create and clear the set
if (! $ObjectiveClientsSet)
{
$ObjectiveClientsSet = new SimSet();
MissionCleanup.add($ObjectiveClientSet);
}
$ObjectiveClientsSet.clear();
%clientCount = 0;
%count = ClientGroup.getCount();
for(%i = 0; %i < %count; %i++)
{
%cl = ClientGroup.getObject(%i);
if (%cl.objective == %objective)
$ObjectiveClientsSet.add(%cl);
}
return $ObjectiveClientsSet.getCount();
}
function AIObjectiveGetClosestClient(%location, %team)
{
if (%location $= "")
return -1;
if (%team $= "")
%team = 0;
%closestClient = -1;
%closestDistance = 32767;
%count = ClientGroup.getCount();
for(%i = 0; %i < %count; %i++)
{
%cl = ClientGroup.getObject(%i);
if (%cl.isAIControlled() && (%cl.team == %team || %team == 0) && AIClientIsAlive(%cl))
{
%testPos = %cl.player.getWorldBoxCenter();
%distance = VectorDist(%location, %testPos);
if (%distance < %closestDistance)
{
%closestDistance = %distance;
%closestClient = %cl;
}
}
}
return %closestClient;
}
function AICountObjectives(%team)
{
%objCount = 0;
%count = $ObjectiveQ[%team].getCount();
for (%i = 0; %i < %count; %i++)
{
%grp = $ObjectiveQ[%team].getObject(%i);
if (%grp.getClassName() !$= "AIObjective")
%objCount += %grp.getCount();
else
%objCount++;
}
error("DEBUG" SPC %team SPC "has" SPC %objCount SPC "objectives.");
}
function AIAddTableObjective(%objective, %weight, %level, %bump, %position)
{
$objTable[%position, objective] = %objective;
$objTable[%position, weight] = %weight;
$objTable[%position, level] = %level;
$objTable[%position, bump] = %bump;
$objTableCount = %position + 1;
}
function AIChooseObjective(%client, %useThisObjectiveQ)
{
//pick which objectiveQ to use, or use the default
if (%useThisObjectiveQ <= 0 && %client.team < 0)
return;
if (%useThisObjectiveQ <= 0)
%useThisObjectiveQ = $ObjectiveQ[%client.team];
if (!isObject(%useThisObjectiveQ) || %useThisObjectiveQ.getCount() <= 0)
return;
//since most objectives check for inventory, find the closest inventory stations first
%inventoryStr = AIFindClosestInventories(%client);
//find the most appropriate objective
if (!%client.objective)
{
//note, the table is never empty, during the course of this function
AIAddTableObjective(0, 0, 0, 0, 0);
}
else
{
//should re-evaluate the current objective weight - but never decrease the weight!!!
%testWeight = %client.objective.weight(%client, %client.objectiveLevel, 0, %inventoryStr);
if (%testWeight <= 0 || %testWeight > %client.objectiveWeight)
%client.objectiveWeight = %testWeight;
if (%client.objectiveWeight > 0)
AIAddTableObjective(%client.objective, %client.objectiveWeight, %client.objectiveLevel, 0, 0);
else
AIAddTableObjective(0, 0, 0, 0, 0);
}
%objCount = %useThisObjectiveQ.getCount();
for (%i = 0; %i < %objCount; %i++)
{
%objective = %useThisObjectiveQ.getObject(%i);
//don't re-evaluate the client's own
if (%objective == %client.objective)
continue;
//try this objective at each of the 4 weight levels to see if it is weighted higher
for (%level = 1; %level <= 4; %level++)
{
%minWeight = 0;
%bumpWeight = 0;
%bumpClient = "";
//we can bump clients off the objective for the first three levels
if (%level <= 3)
{
//if the objective is part of a group, check the whole group
if (%objective.group > 0)
{
%bumpClient = %objective.group.clientLevel[%level];
%bumpWeight = %bumpClient.objectiveWeight;
}
else
{
%bumpClient = %objective.clientLevel[%level];
%bumpWeight = %bumpClient.objectiveWeight;
}
}
//find the minimum weight the objective must have to be considered
%minWeight = (%bumpWeight > $objTable[0, weight] ? %bumpWeight : $objTable[0, weight]);
//evaluate the weight
%weight = %objective.weight(%client, %level, %minWeight, %inventoryStr);
//make sure we got a valid weight
if (%weight <= 0)
break;
//if it's the highest so far, it now replaces anything else in the table
if (%weight > $objTable[0, weight])
{
//never bump someone unless you out- weight them
if (%weight > %bumpWeight)
{
AIAddTableObjective(%objective, %weight, %level, %bumpClient, 0);
//no need to keep checking the other levels
break;
}
}
//else if it's equal to the highest objective we've seen so far, and higher from our current objective
else if (%weight == $objTable[0, weight] && %weight > %client.objectiveWeight)
{
//never bump someone unless you outweigh them
if (%weight > %bumpWeight)
{
//if this wouldn't require us to bump someone, or the table is empty
if (%bumpWeight <= 0 || $objTable[0, weight] <= 0)
{
//if the table currently contains objectives which would require bumping someone, clear it
if ($objTable[0, bump] > 0)
%position = 0;
else
%position = $objTableCount;
//add it to the table
AIAddTableObjective(%objective, %weight, %level, %bumpClient, %position);
//no need to keep checking the other levels
break;
}
//otherwise, the table is not empty, and this would require us to bump someone
//only add it if everything else in the table would also require us to bump someone
else if ($objTable[0, bump] > 0)
{
AIAddTableObjective(%objective, %weight, %level, %bumpClient, $objTableCount);
//no need to keep checking the other levels
break;
}
}
}
//else it must have been less than our highest objective so far- again, no need to keep checking other levels...
else
break;
}
}
//if we have a table of possible objectives which are higher than our current- choose one at random
if ($objTableCount > 0 && $objTable[0, objective] != %client.objective)
{
//choose the new one
%index = mFloor(getRandom() * ($objTableCount - 0.01));
//clear the old objective
if (%client.objective)
{
if (%client.objectiveLevel <= 3)
{
if (%client.objective.group > 0)
{
if (%client.objective.group.clientLevel[%client.objectiveLevel] == %client)
%client.objective.group.clientLevel[%client.objectiveLevel] = "";
}
else
{
if (%client.objective.clientLevel[%client.objectiveLevel] == %client)
%client.objective.clientLevel[%client.objectiveLevel] = "";
}
}
%client.objective.unassignClient(%client);
}
//assign the new
%chooseObjective = $objTable[%index, objective];
%client.objective = %chooseObjective;
%client.objectiveWeight = $objTable[%index, weight];
%client.objectiveLevel = $objTable[%index, level];
if (%client.objectiveLevel <= 3)
{
if (%chooseObjective.group > 0)
%chooseObjective.group.clientLevel[%client.objectiveLevel] = %client;
else
%chooseObjective.clientLevel[%client.objectiveLevel] = %client;
}
%chooseObjective.assignClient(%client);
//see if this objective needs to be acknowledged
if (%chooseObjective.shouldAcknowledge && %chooseObjective.issuedByHuman && isObject(%chooseObjective.issuedByClientId))
{
//cancel any pending acknowledgements - a bot probably just got bumped off this objective
cancel(%chooseObjective.ackSchedule);
%chooseObjective.ackSchedule = schedule(5500, %chooseObjective, "AIAcknowledgeObjective", %client, %chooseObjective);
}
//if we had to bump someone off this objective,
%bumpClient = $objTable[%index, bump];
if (%bumpClient > 0)
{
//unassign the bumped client and choose a new objective
AIUnassignClient(%bumpClient);
Game.AIChooseGameObjective(%bumpClient);
}
}
//debuging - refresh aidebugq() if required
//if ($AIDebugTeam >= 0)
// aiDebugQ($AIDebugTeam);
}
function AIAcknowledgeObjective(%client, %objective)
{
%objective.shouldAcknowledge = false;
//make sure the client is still assigned to this objective
if (%client.objective == %objective)
serverCmdAcceptTask(%client, %objective.issuedByClientId, -1, %objective.ackDescription);
}
function AIForceObjective(%client, %newObjective, %useWeight)
{
//if we found a new objective, release the old, and assign the new
if (%newObjective && %newObjective != %client.objective)
{
//see if someone was already assigned to this objective
if (%newObjective.group > 0)
%prevClient = newObjective.group.clientLevel[1];
else
%prevClient = newObjective.clientLevel[1];
if (%prevClient > 0)
AIUnassignClient(%prevClient);
//see if we should override the weight
if (%useWeight < %newObjective.weightLevel1)
%useWeight = %newObjective.weightLevel1;
//release the client, and force the assignment
AIUnassignClient(%client);
%client.objective = %newObjective;
%client.objectiveWeight = %useWeight;
%client.objectiveLevel = 1;
if (%newObjective.group > 0)
%newObjective.group.clientLevel[1] = %client;
else
%newObjective.clientLevel[1] = %client;
%newObjective.forceClientId = %client;
%newObjective.assignClient(%client);
//don't acknowledge anything that's been forced...
%newObjective.shouldAcknowledge = false;
//now reassign the prev client
if (%prevClient)
Game.AIChooseGameObjective(%prevClient);
}
//debuging - refresh aidebugq() if required
//if ($AIDebugTeam >= 0)
// aiDebugQ($AIDebugTeam);
}
function AIUnassignClient(%client)
{
//first, dissolve any link with a human
aiReleaseHumanControl(%client.controlByHuman, %client);
if (%client.objective)
{
if (%client.objectiveLevel <= 3)
{
if (%client.objective.group > 0)
{
//make sure the clientLevel was actually this client
if (%client.objective.group.clientLevel[%client.objectiveLevel] == %client)
%client.objective.group.clientLevel[%client.objectiveLevel] = "";
}
else
{
if (%client.objective.clientLevel[%client.objectiveLevel] == %client)
%client.objective.clientLevel[%client.objectiveLevel] = "";
}
}
%client.objective.unassignClient(%client);
%client.objective = "";
%client.objectiveWeight = 0;
}
//debuging - refresh aidebugq() if required
//if ($AIDebugTeam >= 0)
// aiDebugQ($AIDebugTeam);
}
function AIClearObjective(%objective)
{
%count = ClientGroup.getCount();
for(%i = 0; %i < %count; %i++)
{
%cl = ClientGroup.getObject(%i);
if (%cl.objective == %objective)
AIUnassignClient(%cl);
}
//debuging - refresh aidebugq() if required
//if ($AIDebugTeam >= 0)
// aiDebugQ($AIDebugTeam);
}
//------------------------------
//TASKS AND OBJECTIVES
function AIDefendLocation::initFromObjective(%task, %objective, %client)
{
//initialize the task vars from the objective
%task.baseWeight = %client.objectiveWeight;
%task.targetObject = %objective.targetObjectId;
if (%objective.Location !$= "")
%task.location = %objective.location;
else
%task.location = %objective.targetObjectId.getWorldBoxCenter();
%task.equipment = %objective.equipment;
%task.buyEquipmentSet = %objective.buyEquipmentSet;
%task.desiredEquipment = %objective.desiredEquipment;
%task.issuedByClient = %objective.issuedByClientId;
%task.chat = %objective.chat;
//initialize other task vars
%task.sendMsg = true;
%task.sendMsgTime = 0;
%task.engageTarget = -1;
}
function AIDefendLocation::assume(%task, %client)
{
%task.setWeightFreq(15);
%task.setMonitorFreq(15);
%client.inPerimeter = false;
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
//even if we don't *need* equipemnt, see if we should buy some...
if (! %client.needEquipment && %task.buyEquipmentSet !$= "")
{
//see if we could benefit from inventory
%needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client);
%result = AIFindClosestInventory(%client, %needArmor);
%closestInv = getWord(%result, 0);
%closestDist = getWord(%result, 1);
if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0)
{
%result = AIFindClosestEnemy(%client, 200, $AIClientLOSTimeout);
%closestEnemy = getWord(%result, 0);
%closestEnemydist = getWord(%result, 1);
if (%closestEnemy <= 0 || (%closestEnemyDist > %closestDist * 1.5))
%client.needEquipment = true;
}
}
//mark the current time for the buy inventory state machine
%task.buyInvTime = getSimTime();
//set a flag to determine if the objective should be re-aquired when the object is destroyed
%task.reassignOnDestroyed = false;
}
function AIDefendLocation::retire(%task, %client)
{
%task.engageVehicle = -1;
%client.setTargetObject(-1);
}
function AIDefendLocation::weight(%task, %client)
{
//update the task weight
if (%task == %client.objectiveTask)
%task.baseWeight = %client.objectiveWeight;
%player = %client.player;
if (!isObject(%player))
return;
%hasMissile = (%player.getInventory("MissileLauncher") > 0) && (%player.getInventory("MissileLauncherAmmo") > 0);
//if we're defending with a missile launcher, our first priority is to take out vehicles...
//see if we're already attacking a vehicle...
if (%task.engageVehicle > 0 && isObject(%task.engageVehicle) && %hasMissile)
{
//set the weight
%task.setWeight(%task.baseWeight);
return;
}
//search for a new vehicle to attack
%task.engageVehicle = -1;
%losTimeout = $AIClientMinLOSTime + ($AIClientLOSTimeout * %client.getSkillLevel());
%result = AIFindClosestEnemyPilot(%client, 300, %losTimeout);
%pilot = getWord(%result, 0);
%pilotDist = getWord(%result, 1);
//if we've got missiles, and a vehicle to attack...
if (%hasMissile && AIClientIsAlive(%pilot))
{
%task.engageVehicle = %pilot.vehicleMounted;
%client.needEquipment = false;
}
//otherwise look for a regular enemy to fight...
else
{
%result = AIFindClosestEnemyToLoc(%client, %task.location, 100, %losTimeout);
%closestEnemy = getWord(%result, 0);
%closestdist = getWord(%result, 1);
//see if we found someone
if (%closestEnemy > 0)
%task.engageTarget = %closestEnemy;
else
{
%task.engageTarget = -1;
//see if someone is near me...
%result = AIFindClosestEnemy(%client, 100, %losTimeout);
%closestEnemy = getWord(%result, 0);
%closestdist = getWord(%result, 1);
if (%closestEnemy <= 0 || %closestDist > 70)
%client.setEngageTarget(-1);
}
}
//set the weight
%task.setWeight(%task.baseWeight);
}
function AIDefendLocation::monitor(%task, %client)
{
//first, buy the equipment
if (%client.needEquipment)
{
%task.setMonitorFreq(5);
if (%task.equipment !$= "")
%equipmentList = %task.equipment;
else
%equipmentList = %task.desiredEquipment;
%result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime);
if (%result $= "InProgress")
return;
else if (%result $= "Finished")
{
%task.setMonitorFreq(15);
%client.needEquipment = false;
}
else if (%result $= "Failed")
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
}
//if we made it past the inventory buying, reset the inv time
%task.buyInvTime = getSimTime();
//chat
if (%task.sendMsg)
{
if (%task.sendMsgTime == 0)
%task.sendMsgTime = getSimTime();
else if (getSimTime() - %task.sendMsgTime > 7000)
{
%task.sendMsg = false;
if (%client.isAIControlled())
{
if (%task.chat !$= "")
{
%chatMsg = getWord(%task.chat, 0);
%chatTemplate = getWord(%task.chat, 1);
if (%chatTemplate !$= "")
AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1);
else
AIMessageThread(%task.chat, %client, -1);
}
else if (%task.targetObject > 0)
{
%type = %task.targetObject.getDataBlock().getName();
if (%type $= "Flag")
AIMessageThreadTemplate("DefendBase", "ChatSelfDefendFlag", %client, -1);
else if (%type $= "GeneratorLarge")
AIMessageThreadTemplate("DefendBase", "ChatSelfDefendGenerator", %client, -1);
else if (%type $= "StationVehicle")
AIMessageThreadTemplate("DefendBase", "ChatSelfDefendVehicle", %client, -1);
else if (%type $= "SensorLargePulse")
AIMessageThreadTemplate("DefendBase", "ChatSelfDefendSensors", %client, -1);
else if (%type $= "SensorMediumPulse")
AIMessageThreadTemplate("DefendBase", "ChatSelfDefendSensors", %client, -1);
else if (%type $= "TurretBaseLarge")
AIMessageThreadTemplate("DefendBase", "ChatSelfDefendTurrets", %client, -1);
}
}
}
}
//if the defend location task has an object, set the "reset" flag
if (%task == %client.objectiveTask && isObject(%task.targetObject))
{
if (%task.targetObject.getDamageState() !$= "Destroyed")
%task.reassignOnDestroyed = true;
else
{
if (%task.reassignOnDestroyed)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
return;
}
}
}
//first, check for a vehicle to engage
if (%task.engageVehicle > 0 && isObject(%task.engageVehicle))
{
%client.stop();
%client.clearStep();
%client.setEngageTarget(-1);
%client.setTargetObject(%task.engageVehicle, 300, "Missile");
}
else
{
//clear the target vehicle...
%client.setTargetObject(-1);
//see if we're engaging a player
if (%client.getEngageTarget() > 0)
{
//too far, or killed the enemy - return home
if (%client.getStepStatus() !$= "InProgress" || %distance > 75)
{
%client.setEngageTarget(-1);
%client.stepMove(%task.location, 8.0);
}
}
//else see if we have a target to begin attacking
else if (%task.engageTarget > 0)
%client.stepEngage(%task.engageTarget);
//else move to a random location around where we are defending
else if (%client.getStepName() !$= "AIStepIdlePatrol")
{
%dist = VectorDist(%client.player.getWorldBoxCenter(), %task.location);
if (%dist < 10)
{
//dissolve the human control link and re-evaluate the weight
if (%task == %client.objectiveTask)
{
if (aiHumanHasControl(%task.issuedByClient, %client))
{
aiReleaseHumanControl(%client.controlByHuman, %client);
//should re-evaluate the current objective weight
%inventoryStr = AIFindClosestInventories(%client);
%client.objectiveWeight = %client.objective.weight(%client, %client.objectiveLevel, 0, %inventoryStr);
}
}
%client.stepIdle(%task.location);
}
else
%client.stepMove(%task.location, 8.0);
}
}
//see if we're supposed to be engaging anyone...
if (!AIClientIsAlive(%client.getEngageTarget()) && AIClientIsAlive(%client.shouldEngage))
%client.setEngageTarget(%client.shouldEngage);
}
//------------------------------
function AIAttackLocation::initFromObjective(%task, %objective, %client)
{
//initialize the task vars from the objective
%task.baseWeight = %client.objectiveWeight;
%task.location = %objective.location;
%task.equipment = %objective.equipment;
%task.buyEquipmentSet = %objective.buyEquipmentSet;
%task.desiredEquipment = %objective.desiredEquipment;
%task.issuedByClient = %objective.issuedByClientId;
%task.chat = %objective.chat;
//initialize other task vars
%task.sendMsg = true;
%task.sendMsgTime = 0;
%task.engageTarget = -1;
}
function AIAttackLocation::assume(%task, %client)
{
%task.setWeightFreq(30);
%task.setMonitorFreq(30);
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
//even if we don't *need* equipemnt, see if we should buy some...
if (! %client.needEquipment && %task.buyEquipmentSet !$= "")
{
//see if we could benefit from inventory
%needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client);
%result = AIFindClosestInventory(%client, %needArmor);
%closestInv = getWord(%result, 0);
%closestDist = getWord(%result, 1);
if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0)
{
%result = AIFindClosestEnemyToLoc(%client, %task.location, 50, $AIClientLOSTimeout);
%closestEnemy = getWord(%result, 0);
if (%closestEnemy <= 0)
%client.needEquipment = true;
}
}
//mark the current time for the buy inventory state machine
%task.buyInvTime = getSimTime();
%task.snipeLocation = "";
%task.hideLocation = "";
%task.moveToPosition = true;
%task.moveToSnipe = false;
%task.nextSnipeTime = 0;
}
function AIAttackLocation::retire(%task, %client)
{
}
function AIAttackLocation::weight(%task, %client)
{
//update the task weight
if (%task == %client.objectiveTask)
%task.baseWeight = %client.objectiveWeight;
//if we're a sniper, we're going to cheat, and see if there are clients near the attack location
%losTimeout = $AIClientMinLOSTime + ($AIClientLOSTimeout * %client.getSkillLevel());
%distToLoc = VectorDist(%client.player.getWorldBoxCenter(), %task.location);
if (%client.player.getInventory(SniperRifle) > 0 && %client.player.getInventory(EnergyPack) > 0 && %distToLoc > 60)
%result = AIFindClosestEnemyToLoc(%client, %task.location, 50, $AIClientLOSTimeout, true);
//otherwise, do the search normally. (cheat ignores LOS)...
else
%result = AIFindClosestEnemyToLoc(%client, %task.location, 50, %losTimeout, false);
%closestEnemy = getWord(%result, 0);
%closestdist = getWord(%result, 1);
%task.setWeight(%task.baseWeight);
//see if we found someone
if (%closestEnemy > 0)
%task.engageTarget = %closestEnemy;
else
%task.engageTarget = -1;
}
function AIAttackLocation::monitor(%task, %client)
{
//first, buy the equipment
if (%client.needEquipment)
{
%task.setMonitorFreq(5);
if (%task.equipment !$= "")
%equipmentList = %task.equipment;
else
%equipmentList = %task.desiredEquipment;
%result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime);
if (%result $= "InProgress")
return;
else if (%result $= "Finished")
{
%task.setMonitorFreq(30);
%client.needEquipment = false;
}
else if (%result $= "Failed")
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
}
//if we made it past the inventory buying, reset the inv time
%task.buyInvTime = getSimTime();
//chat
if (%task.sendMsg)
{
if (%task.sendMsgTime == 0)
%task.sendMsgTime = getSimTime();
else if (getSimTime() - %task.sendMsgTime > 7000)
{
%task.sendMsg = false;
if (%client.isAIControlled())
{
if (%task.chat !$= "")
{
%chatMsg = getWord(%task.chat, 0);
%chatTemplate = getWord(%task.chat, 1);
if (%chatTemplate !$= "")
AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1);
else
AIMessageThread(%task.chat, %client, -1);
}
else
AIMessageThreadTemplate("AttackBase", "ChatSelfAttack", %client, -1);
}
}
}
//how far are we from the location we're defending
%myPos = %client.player.getWorldBoxCenter();
%distance = %client.getPathDistance(%task.location);
if (%distance < 0)
%distance = 32767;
if (%client.player.getInventory(SniperRifle) > 0 && %client.player.getInventory(EnergyPack) > 0)
{
//first, find an LOS location
if (%task.snipeLocation $= "")
{
%task.snipeLocation = %client.getLOSLocation(%task.location, 150, 250);
%task.hideLocation = %client.getHideLocation(%task.location, VectorDist(%task.location, %task.snipeLocation), %task.snipeLocation, 1);
%client.stepMove(%task.hideLocation, 4.0);
%task.moveToPosition = true;
}
else
{
//see if we can acquire a target
%energy = %client.player.getEnergyPercent();
%distToSnipe = VectorDist(%task.snipelocation, %client.player.getWorldBoxCenter());
%distToHide = VectorDist(%task.hidelocation, %client.player.getWorldBoxCenter());
//until we're in position, we can move using the AIModeExpress, after that, we only want to walk...
if (%task.moveToPosition)
{
if (%distToHide < 4.0)
{
//dissolve the human control link
if (%task == %client.objectiveTask)
{
if (aiHumanHasControl(%task.issuedByClient, %client))
{
aiReleaseHumanControl(%client.controlByHuman, %client);
//should re-evaluate the current objective weight
%inventoryStr = AIFindClosestInventories(%client);
%client.objectiveWeight = %client.objective.weight(%client, %client.objectiveLevel, 0, %inventoryStr);
}
}
%task.moveToPosition = false;
}
}
else if (%task.moveToSnipe)
{
if (%energy > 0.75 && %client.getStepStatus() $= "Finished")
{
%client.stepMove(%task.snipeLocation, 4.0, $AIModeWalk);
%client.setEngageTarget(%task.engageTarget);
}
else if (%energy < 0.4)
{
%client.setEngageTarget(-1);
%client.stepMove(%task.hideLocation, 4.0);
%task.nextSnipeTime = getSimTime() + 4000 + (getRandom() * 4000);
%task.moveToSnipe = false;
}
}
else if (%energy > 0.5 && %task.engageTarget > 0 && getSimTime() > %task.nextSnipeTime)
{
%client.stepRangeObject(%task.engageTarget.player.getWorldBoxCenter(), "BasicSniperShot", 150, 250, %task.snipelocation);
%client.aimAt(%task.engageTarget.player.getWorldBoxCenter(), 8000);
%task.moveToSnipe = true;
}
}
}
else
{
//else see if we have a target to begin attacking
if (%client.getEngageTarget() <= 0 && %task.engageTarget > 0)
%client.stepEngage(%task.engageTarget);
//else move to the location we're defending
else if (%client.getEngageTarget() <= 0)
{
%client.stepMove(%task.location, 8.0);
if (VectorDist(%client.player.position, %task.location) < 10)
{
//dissolve the human control link
if (%task == %client.objectiveTask)
{
if (aiHumanHasControl(%task.issuedByClient, %client))
{
aiReleaseHumanControl(%client.controlByHuman, %client);
//should re-evaluate the current objective weight
%inventoryStr = AIFindClosestInventories(%client);
%client.objectiveWeight = %client.objective.weight(%client, %client.objectiveLevel, 0, %inventoryStr);
}
}
}
}
}
//see if we're supposed to be engaging anyone...
if (!AIClientIsAlive(%client.getEngageTarget()) && AIClientIsAlive(%client.shouldEngage))
%client.setEngageTarget(%client.shouldEngage);
}
//------------------------------
function AIAttackPlayer::initFromObjective(%task, %objective, %client)
{
%task.baseWeight = %client.objectiveWeight;
%task.targetClient = %objective.targetClientId;
%task.equipment = %objective.equipment;
%task.buyEquipmentSet = %objective.buyEquipmentSet;
%task.desiredEquipment = %objective.desiredEquipment;
%task.issuedByClient = %objective.issuedByClientId;
}
function AIAttackPlayer::assume(%task, %client)
{
%task.setWeightFreq(15);
%task.setMonitorFreq(15);
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
if (! %client.needEquipment)
%client.stepEngage(%task.targetClient);
//even if we don't *need* equipemnt, see if we should buy some...
if (! %client.needEquipment && %task.buyEquipmentSet !$= "")
{
//see if we could benefit from inventory
%needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client);
%result = AIFindClosestInventory(%client, %needArmor);
%closestInv = getWord(%result, 0);
%closestDist = getWord(%result, 1);
if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0)
{
%distToTarg = %client.getPathDistance(%task.targetClient.player.getWorldBoxCenter());
if (%distToTarg < 0 || %distToTarg > 100)
%client.needEquipment = true;
}
}
//mark the current time for the buy inventory state machine
%task.buyInvTime = getSimTime();
}
function AIAttackPlayer::retire(%task, %client)
{
//dissolve the human control link
if (%task == %client.objectiveTask)
aiReleaseHumanControl(%client.controlByHuman, %client);
}
function AIAttackPlayer::weight(%task, %client)
{
//update the task weight
if (%task == %client.objectiveTask)
%task.baseWeight = %client.objectiveWeight;
%task.setWeight(%task.baseWeight);
}
function AIAttackPlayer::monitor(%task, %client)
{
//first, buy the equipment
if (%client.needEquipment)
{
%task.setMonitorFreq(5);
if (%task.equipment !$= "")
%equipmentList = %task.equipment;
else
%equipmentList = %task.desiredEquipment;
%result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime);
if (%result $= "InProgress")
return;
else if (%result $= "Finished")
{
%task.setMonitorFreq(15);
%client.needEquipment = false;
%client.stepEngage(%task.targetClient);
}
else if (%result $= "Failed")
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
}
//if we made it past the inventory buying, reset the inv time
%task.buyInvTime = getSimTime();
//cheap hack for now... make the bot always know where you are...
%client.clientDetected(%task.targetClient);
//make sure we're still attacking...
if (%client.getStepName() !$= "AIStepEngage")
%client.stepEngage(%task.targetClient);
//make sure we're still attacking the right target
%client.setEngageTarget(%task.targetClient);
if (%client.getStepStatus() !$= "InProgress" && %task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
}
//------------------------------
function AITouchObject::initFromObjective(%task, %objective, %client)
{
%task.baseWeight = %client.objectiveWeight;
%task.targetObject = %objective.targetObjectId;
%task.mode = %objective.mode;
if (%objective.mode $= "FlagCapture")
%task.location = %objective.location;
else if(%objective.mode $= "TouchFlipFlop")
%task.location = %objective.location;
else
%task.location = "";
%task.equipment = %objective.equipment;
%task.buyEquipmentSet = %objective.buyEquipmentSet;
%task.desiredEquipment = %objective.desiredEquipment;
%task.issuedByClient = %objective.issuedByClientId;
%task.sendMsgTime = 0;
if (%task.mode $= "FlagGrab")
%task.sendMsg = true;
else
%task.sendMsg = false;
}
function AITouchObject::assume(%task, %client)
{
%task.setWeightFreq(15);
%task.setMonitorFreq(15);
%task.engageTarget = 0;
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
//even if we don't *need* equipemnt, see if we should buy some...
if (! %client.needEquipment && (%task.mode $= "FlagGrab" || %task.mode $= "TouchFlipFlop") && %task.buyEquipmentSet !$= "")
{
//see if we could benefit from inventory
%needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client);
%result = AIFindClosestInventory(%client, %needArmor);
%closestInv = getWord(%result, 0);
%closestDist = getWord(%result, 1);
if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0)
{
//find where we are
%clientPos = %client.player.getWorldBoxCenter();
%distToObject = %client.getPathDistance(%task.location);
if (%distToObject < 0 || %closestDist < %distToObject)
%client.needEquipment = true;
}
}
//mark the current time for the buy inventory state machine
%task.buyInvTime = getSimTime();
}
function AITouchObject::retire(%task, %client)
{
}
function AITouchObject::weight(%task, %client)
{
//update the task weight
if (%task == %client.objectiveTask)
%task.baseWeight = %client.objectiveWeight;
//see if we can find someone to shoot at...
if (%client.getEngageTarget() <= 0)
{
%losTimeout = $AIClientMinLOSTime + ($AIClientLOSTimeout * %client.getSkillLevel());
%myLocation = %client.player.getWorldBoxCenter();
%result = AIFindClosestEnemy(%client, 40, %losTimeout);
%task.engageTarget = getWord(%result, 0);
}
%task.setWeight(%task.baseWeight);
}
function AITouchObject::monitor(%task, %client)
{
//first, buy the equipment
if (%client.needEquipment)
{
%task.setMonitorFreq(5);
if (%task.equipment !$= "")
%equipmentList = %task.equipment;
else
%equipmentList = %task.desiredEquipment;
%result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime);
if (%result $= "InProgress")
return;
else if (%result $= "Finished")
{
%task.setMonitorFreq(15);
%client.needEquipment = false;
}
else if (%result $= "Failed")
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
}
//if we made it past the inventory buying, reset the inv time
%task.buyInvTime = getSimTime();
//chat
if (%task.sendMsg)
{
if (%task.sendMsgTime == 0)
%task.sendMsgTime = getSimTime();
else if (getSimTime() - %task.sendMsgTime > 7000)
{
%task.sendMsg = false;
if (%client.isAIControlled())
{
if (%task.mode $= "FlagGrab")
AIMessageThreadTemplate("AttackBase", "ChatSelfAttackFlag", %client, -1);
}
}
}
//keep updating the position, in case the flag is flying through the air...
if (%task.location !$= "")
%touchPos = %task.location;
else
%touchPos = %task.targetObject.getWorldBoxCenter();
//see if we need to engage a new target
%engageTarget = %client.getEngageTarget();
if (!AIClientIsAlive(%engageTarget) && %task.engageTarget > 0)
%client.setEngageTarget(%task.engageTarget);
//else see if we should abandon the engagement
else if (AIClientIsAlive(%engageTarget))
{
%myPos = %client.player.getWorldBoxCenter();
%testPos = %engageTarget.player.getWorldBoxCenter();
%distance = %client.getPathDistance(%testPos);
if (%distance < 0 || %distance > 70)
%client.setEngageTarget(-1);
}
//see if we have completed our objective
if (%task == %client.objectiveTask)
{
%completed = false;
switch$ (%task.mode)
{
case "TouchFlipFlop":
if (%task.targetObject.team == %client.team)
%completed = true;
case "FlagGrab":
if (!%task.targetObject.isHome)
%completed = true;
case "FlagDropped":
if ((%task.targetObject.isHome) || (%task.targetObject.carrier !$= ""))
%completed = true;
case "FlagCapture":
if (%task.targetObject.carrier != %client.player)
%completed = true;
}
if (%completed)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
return;
}
}
if (%task.mode $= "FlagCapture")
{
%homeFlag = $AITeamFlag[%client.team];
//if we're within range of the flag's home position, and the flag isn't home, start idling...
if (VectorDist(%client.player.position, %touchPos) < 40 && !%homeFlag.isHome)
{
if (%client.getStepName() !$= "AIStepIdlePatrol")
%client.stepIdle(%touchPos);
}
else
%client.stepMove(%touchPos, 0.25);
}
else
%client.stepMove(%touchPos, 0.25);
if (VectorDist(%client.player.position, %touchPos) < 10)
{
//dissolve the human control link
if (%task == %client.objectiveTask)
{
if (aiHumanHasControl(%task.issuedByClient, %client))
{
aiReleaseHumanControl(%client.controlByHuman, %client);
//should re-evaluate the current objective weight
%inventoryStr = AIFindClosestInventories(%client);
%client.objectiveWeight = %client.objective.weight(%client, %client.objectiveLevel, 0, %inventoryStr);
}
}
}
//see if we're supposed to be engaging anyone...
if (!AIClientIsAlive(%client.getEngageTarget()) && AIClientIsAlive(%client.shouldEngage))
%client.setEngageTarget(%client.shouldEngage);
}
//------------------------------
function AIEscortPlayer::initFromObjective(%task, %objective, %client)
{
%task.baseWeight = %client.objectiveWeight;
%task.targetClient = %objective.targetClientId;
%task.equipment = %objective.equipment;
%task.buyEquipmentSet = %objective.buyEquipmentSet;
%task.desiredEquipment = %objective.desiredEquipment;
%task.issuedByClient = %objective.issuedByClientId;
%task.forceClient = %objective.forceClientId;
}
function AIEscortPlayer::assume(%task, %client)
{
%task.setWeightFreq(15);
%task.setMonitorFreq(15);
%task.rangedTarget = false;
if (%task == %client.objectiveTask && %client == %task.forceClient && %task.issuedByClient == %task.targetClient)
{
%client.needEquipment = false;
%client.mountVehicle = false;
}
else
{
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
if (! %client.needEquipment)
%client.stepEscort(%task.targetClient);
//even if we don't *need* equipemnt, see if we should buy some...
if (! %client.needEquipment && %task.buyEquipmentSet !$= "")
{
//see if we could benefit from inventory
%needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client);
%result = AIFindClosestInventory(%client, %needArmor);
%closestInv = getWord(%result, 0);
%closestDist = getWord(%result, 1);
if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0)
{
//find where we are
%clientPos = %client.player.getWorldBoxCenter();
%targPos = %task.targetClient.player.getWorldBoxCenter();
%distToTarg = %client.getPathDistance(%targPos);
if (%closestDist < 50 && (%distToTarg < 0 || %distToTarg > 100))
%client.needEquipment = true;
}
}
}
//mark the current time for the buy inventory state machine
%task.buyInvTime = getSimTime();
}
function AIEscortPlayer::retire(%task, %client)
{
%client.clearStep();
if(%client.player.isMounted())
AIDisembarkVehicle(%client);
//clear the target object
%client.setTargetObject(-1);
}
function AIEscortPlayer::weight(%task, %client)
{
//update the task weight
if (%task == %client.objectiveTask)
%task.baseWeight = %client.objectiveWeight;
//make sure we still have someone to escort
if (!AiClientIsAlive(%task.targetClient))
{
%task.setWeight(0);
return;
}
//always shoot at the closest person to the client being escorted
%targetPos = %task.targetClient.player.getWorldBoxCenter();
%losTimeout = $AIClientMinLOSTime + ($AIClientLOSTimeout * %client.getSkillLevel());
%result = AIFindClosestEnemyToLoc(%client, %targetPos, 50, %losTimeout);
%task.engageTarget = getWord(%result, 0);
if (!AIClientIsAlive(%task.engageTarget))
{
if (AIClientIsAlive(%task.targetClient.lastDamageClient, %losTimeout) && getSimTime() - %task.targetClient.lastDamageTime < %losTimeout)
%task.engageTarget = %task.targetClient.lastDamageClient;
}
if (!AIClientIsAlive(%task.engageTarget))
{
%myPos = %client.player.getWorldBoxCenter();
%result = AIFindClosestEnemy(%client, 50, %losTimeout);
%task.engageTarget = getWord(%result, 0);
}
//if both us and the person we're escorting are in a vehicle, set the weight high!
if (%task.targetClient.player.isMounted() && %client.player.isMounted())
{
%vehicle = %client.vehicleMounted;
if (%vehicle > 0 && isObject(%vehicle) && %vehicle.getDamagePercent() < 0.8)
%task.setWeight($AIWeightVehicleMountedEscort);
else
%task.setWeight(%task.baseWeight);
}
else
%task.setWeight(%task.baseWeight);
//find out if our escortee is lazing a target...
%task.missileTarget = -1;
%targetCount = ServerTargetSet.getCount();
for (%i = 0; %i < %targetCount; %i++)
{
%targ = ServerTargetSet.getObject(%i);
if (%targ.sourceObject == %task.targetClient.player)
{
//find out which item is being targetted...
%targPoint = %targ.getTargetPoint();
InitContainerRadiusSearch(%targPoint, 10, $TypeMasks::TurretObjectType | $TypeMasks::StaticShapeObjectType);
%task.missileTarget = containerSearchNext();
break;
}
}
}
function AIEscortPlayer::monitor(%task, %client)
{
//make sure we still have someone to escort
if (!AiClientIsAlive(%task.targetClient))
{
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
//first, buy the equipment
if (%client.needEquipment)
{
%task.setMonitorFreq(5);
if (%task.equipment !$= "")
%equipmentList = %task.equipment;
else
%equipmentList = %task.desiredEquipment;
%result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime);
if (%result $= "InProgress")
return;
else if (%result $= "Finished")
{
%task.setMonitorFreq(15);
%client.needEquipment = false;
%client.stepEscort(%task.targetClient);
%task.buyInvTime = getSimTime();
}
else if (%result $= "Failed")
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
}
//see if our target is mounted in a vehicle...
if (%task.targetClient.player.isMounted())
{
//find the passenger seat the bot will take
%vehicle = %task.targetClient.vehicleMounted;
%node = findAIEmptySeat(%vehicle, %client.player);
//make sure there is an empty seat
if (%node < 0 && %client.vehicleMounted != %task.targetClient.vehicleMounted)
{
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
//find the passenger seat location...
%slotPosition = %vehicle.getSlotTransform(%node);
//make sure we're in the correct armor - assault tanks cannot have a heavy...
if (%task.targetClient.vehicleMounted.getDataBlock().getName() $= "AssaultVehicle")
{
//if the bot is in a heavy, break off the escort...
if (%client.player.getArmorSize() $= "Heavy")
{
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
//throw away any packs that won't fit
if (%client.player.getInventory(InventoryDeployable) > 0)
%client.player.throwPack();
else if (%client.player.getInventory(TurretIndoorDeployable) > 0)
%client.player.throwPack();
else if (%client.player.getInventory(TurretOutdoorDeployable) > 0)
%client.player.throwPack();
}
if (%client.player.isMounted())
{
//make sure it's the same vehicle :)
if (%client.vehicleMounted != %vehicle)
AIDisembarkVehicle(%client);
}
else
{
//mount the vehicle
%client.stepMove(%slotPosition, 0.25, $AIModeMountVehicle);
}
}
else
{
//disembark if we're mounted, but our target isn't (anymore)
if (%client.player.isMounted())
AIDisembarkVehicle(%client);
}
//see if we're supposed to be mortaring/missiling something...
%hasMortar = (%client.player.getInventory("Mortar") > 0) && (%client.player.getInventory("MortarAmmo") > 0);
%hasMissile = (%client.player.getInventory("MissileLauncher") > 0) && (%client.player.getInventory("MissileLauncherAmmo") > 0);
if (!isObject(%task.engageTarget) && isobject(%task.missileTarget) && %task.missileTarget.getDamageState() !$= "Destroyed" && (%hasMortar || %hasMissile))
{
if (%task.rangedTarget)
{
%client.stop();
%client.clearStep();
%client.setEngageTarget(-1);
if (%hasMortar)
%client.setTargetObject(%task.missileTarget, 250, "Mortar");
else
%client.setTargetObject(%task.missileTarget, 500, "MissileNoLock");
}
else if (%client.getStepName() !$= "AIStepRangeObject")
{
if (%hasMortar)
%client.stepRangeObject(%task.missileTarget, "MortarShot", 100, 200);
else
%client.stepRangeObject(%task.missileTarget, "BasicTargeter", 50, 500);
}
else if (%client.getStepStatus() $= "Finished")
%task.rangedTarget = true;
}
else
{
%task.rangedTarget = false;
%client.setTargetObject(-1);
if (%client.getStepName() !$= "AIStepEscort")
%client.stepEscort(%task.targetClient);
}
//make sure we're still shooting...
%client.setEngageTarget(%task.engageTarget);
//see if we're supposed to be engaging anyone...
if (!AIClientIsAlive(%client.getEngageTarget()) && AIClientIsAlive(%client.shouldEngage))
%client.setEngageTarget(%client.shouldEngage);
}
//------------------------------
function AIAttackObject::initFromObjective(%task, %objective, %client)
{
%task.baseWeight = %client.objectiveWeight;
%task.targetObject = %objective.targetObjectId;
%task.equipment = %objective.equipment;
%task.buyEquipmentSet = %objective.buyEquipmentSet;
%task.desiredEquipment = %objective.desiredEquipment;
%task.issuedByClient = %objective.issuedByClientId;
//initialize other task vars
%task.sendMsg = true;
%task.sendMsgTime = 0;
}
function AIAttackObject::assume(%task, %client)
{
%task.setWeightFreq(15);
%task.setMonitorFreq(5);
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
//even if we don't *need* equipemnt, see if we should buy some...
if (! %client.needEquipment && %task.buyEquipmentSet !$= "")
{
//see if we could benefit from inventory
%needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client);
%result = AIFindClosestInventory(%client, %needArmor);
%closestInv = getWord(%result, 0);
%closestDist = getWord(%result, 1);
if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0)
{
//find where we are
%clientPos = %client.player.getWorldBoxCenter();
%objPos = %task.targetObject.getWorldBoxCenter();
%distToObject = %client.getPathDistance(%objPos);
if (%distToObject < 0 || %closestDist < %distToObject)
%client.needEquipment = true;
}
}
//mark the current time for the buy inventory state machine
%task.buyInvTime = getSimTime();
}
function AIAttackObject::retire(%task, %client)
{
%client.setTargetObject(-1);
}
function AIAttackObject::weight(%task, %client)
{
//update the task weight
if (%task == %client.objectiveTask)
%task.baseWeight = %client.objectiveWeight;
//let the monitor decide when to stop attacking
%task.setWeight(%task.baseWeight);
}
function AIAttackObject::monitor(%task, %client)
{
//first, buy the equipment
if (%client.needEquipment)
{
%task.setMonitorFreq(5);
if (%task.equipment !$= "")
%equipmentList = %task.equipment;
else
%equipmentList = %task.desiredEquipment;
%result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime);
if (%result $= "InProgress")
return;
else if (%result $= "Finished")
{
%task.setMonitorFreq(15);
%client.needEquipment = false;
}
else if (%result $= "Failed")
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
}
//if we made it past the inventory buying, reset the inv time
%task.buyInvTime = getSimTime();
//chat
if (%task.sendMsg)
{
if (%task.sendMsgTime == 0)
%task.sendMsgTime = getSimTime();
else if (getSimTime() - %task.sendMsgTime > 7000)
{
%task.sendMsg = false;
if (%client.isAIControlled())
{
if (%task.chat !$= "")
{
%chatMsg = getWord(%task.chat, 0);
%chatTemplate = getWord(%task.chat, 1);
if (%chatTemplate !$= "")
AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1);
else
AIMessageThread(%task.chat, %client, -1);
}
else if (%task.targetObject > 0)
{
%type = %task.targetObject.getDataBlock().getName();
if (%type $= "GeneratorLarge")
AIMessageThreadTemplate("AttackBase", "ChatSelfAttackGenerator", %client, -1);
else if (%type $= "SensorLargePulse")
AIMessageThreadTemplate("AttackBase", "ChatSelfAttackSensors", %client, -1);
else if (%type $= "SensorMediumPulse")
AIMessageThreadTemplate("AttackBase", "ChatSelfAttackSensors", %client, -1);
else if (%type $= "TurretBaseLarge")
AIMessageThreadTemplate("AttackBase", "ChatSelfAttackTurrets", %client, -1);
else if (%type $= "StationVehicle")
AIMessageThreadTemplate("AttackBase", "ChatSelfAttackVehicle", %client, -1);
}
}
}
}
//set the target object
if (isObject(%task.targetObject) && %task.targetObject.getDamageState() !$= "Destroyed")
{
%client.setTargetObject(%task.targetObject, 40, "Destroy");
//move towards the object until we're within range
if (! %client.targetInRange())
%client.stepMove(%task.targetObject.getWorldBoxCenter(), 8.0);
else
{
//dissolve the human control link
if (%task == %client.objectiveTask)
aiReleaseHumanControl(%client.controlByHuman, %client);
%client.stop();
}
}
else
{
%client.setTargetObject(-1);
%client.stop();
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
}
}
//------------------------------
function AIRepairObject::initFromObjective(%task, %objective, %client)
{
%task.baseWeight = %client.objectiveWeight;
%task.targetObject = %objective.targetObjectId;
//need to force this objective to only require a repair pack
//%task.equipment = %objective.equipment;
%task.equipment = "RepairPack";
%task.buyEquipmentSet = %objective.buyEquipmentSet;
%task.desiredEquipment = %objective.desiredEquipment;
%task.issuedByClient = %objective.issuedByClientId;
%task.deployed = %objective.deployed;
if (%task.deployed)
{
%task.location = %objective.position;
%task.deployDirection = MatrixMulVector("0 0 0 " @ getWords(%objective.getTransform(), 3, 6), "0 1 0");
%task.deployDirection = VectorNormalize(%task.deployDirection);
}
}
function AIRepairObject::assume(%task, %client)
{
%task.setWeightFreq(15);
%task.setMonitorFreq(15);
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
//clear the target object, and range it
%client.setTargetObject(-1);
if (! %client.needEquipment)
{
if (%task.deployed)
{
%task.repairLocation = VectorAdd(%task.location,VectorScale(%task.deployDirection, -4.0));
%client.stepMove(%task.repairLocation, 0.25);
}
else
%client.stepRangeObject(%task.targetObject, "DefaultRepairBeam", 3, 8);
}
//mark the current time for the buy inventory state machine
%task.buyInvTime = getSimTime();
%task.needToRangeTime = 0;
%task.pickupRepairPack = -1;
%task.usingInv = false;
//set a tag to help the repairPack.cs script fudge acquiring a target
%client.repairObject = %task.targetObject;
}
function AIRepairObject::retire(%task, %client)
{
%client.setTargetObject(-1);
%client.repairObject = -1;
}
function AIRepairObject::weight(%task, %client)
{
//update the task weight
if (%task == %client.objectiveTask)
%task.baseWeight = %client.objectiveWeight;
//let the monitor decide when to stop repairing
%task.setWeight(%task.baseWeight);
}
function AIRepairObject::monitor(%task, %client)
{
//first, buy the equipment
if (%client.needEquipment)
{
%task.setMonitorFreq(5);
//first, see if we still need a repair pack
if (%client.player.getInventory(RepairPack) > 0)
{
%client.needEquipment = false;
%task.setMonitorFreq(15);
//if this is to repair a deployed object, walk to the deploy point...
if (%task.deployed)
{
%task.repairLocation = VectorAdd(%task.location,VectorScale(%task.deployDirection, -4.0));
%client.stepMove(%task.repairLocation, 0.25);
}
//otherwise, we'll need to range it...
else
%client.stepRangeObject(%task.targetObject, "DefaultRepairBeam", 3, 8);
}
else
{
// check to see if there's a repair pack nearby
%closestRepairPack = -1;
%closestRepairDist = 32767;
//search the AIItemSet for a repair pack (someone might have dropped one...)
%itemCount = $AIItemSet.getCount();
for (%i = 0; %i < %itemCount; %i++)
{
%item = $AIItemSet.getObject(%i);
if (%item.getDataBlock().getName() $= "RepairPack" && !%item.isHidden())
{
%dist = %client.getPathDistance(%item.getWorldBoxCenter());
if (%dist > 0 && %dist < %closestRepairDist)
{
%closestRepairPack = %item;
%closestRepairDist = %dist;
}
}
}
//choose whether we're picking up the closest pack, or buying from an inv station...
if ((isObject(%closestRepairPack) && %closestRepairPack != %task.pickupRepairPack) || (%task.buyInvTime != %client.buyInvTime))
{
%task.pickupRepairPack = %closestRepairPack;
//initialize the inv buying
%task.buyInvTime = getSimTime();
AIBuyInventory(%client, "RepairPack", %task.buyEquipmentSet, %task.buyInvTime);
//now decide which is closer
if (isObject(%closestRepairPack))
{
if (isObject(%client.invToUse))
{
%dist = %client.getPathDistance(%item.position);
if (%dist > %closestRepairDist)
%task.usingInv = true;
else
%task.usingInv = false;
}
else
%task.usingInv = false;
}
else
%task.usingInv = true;
}
//now see if we found a closer repair pack
if (!%task.usingInv)
{
%client.stepMove(%task.pickupRepairPack.position, 0.25);
%distToPack = %client.getPathDistance(%task.pickupRepairPack.position);
if (%distToPack < 10 && %client.player.getMountedImage($BackpackSlot) > 0)
%client.player.throwPack();
//and we're finished until we actually have a repair pack...
return;
}
else
{
%result = AIBuyInventory(%client, "RepairPack", %task.buyEquipmentSet, %task.buyInvTime);
if (%result $= "InProgress")
return;
else if (%result $= "Finished")
{
%client.needEquipment = false;
%task.setMonitorFreq(15);
//if this is to repair a deployed object, walk to the deploy point...
if (%task.deployed)
{
%task.repairLocation = VectorAdd(%task.location,VectorScale(%task.deployDirection, -4.0));
%client.stepMove(%task.repairLocation, 0.25);
}
//otherwise, we'll need to range it...
else
%client.stepRangeObject(%task.targetObject, "DefaultRepairBeam", 3, 8);
}
else if (%result $= "Failed")
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
}
}
}
//if we made it past the inventory buying, reset the inv time
%task.buyInvTime = getSimTime();
//chat
if (%task.sendMsg)
{
if (%task.sendMsgTime == 0)
%task.sendMsgTime = getSimTime();
else if (getSimTime() - %task.sendMsgTime > 7000)
{
%task.sendMsg = false;
if (%client.isAIControlled())
{
if (%task.chat !$= "")
{
%chatMsg = getWord(%task.chat, 0);
%chatTemplate = getWord(%task.chat, 1);
if (%chatTemplate !$= "")
AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1);
else
AIMessageThread(%task.chat, %client, -1);
}
else if (%task.targetObject > 0)
{
%type = %task.targetObject.getDataBlock().getName();
if (%type $= "GeneratorLarge")
AIMessageThreadTemplate("RepairBase", "ChatSelfRepairGenerator", %client, -1);
else if (%type $= "StationVehicle")
AIMessageThreadTemplate("RepairBase", "ChatSelfRepairVehicle", %client, -1);
else if (%type $= "SensorLargePulse")
AIMessageThreadTemplate("RepairBase", "ChatSelfRepairSensors", %client, -1);
else if (%type $= "SensorMediumPulse")
AIMessageThreadTemplate("RepairBase", "ChatSelfRepairSensors", %client, -1);
else if (%type $= "TurretBaseLarge")
AIMessageThreadTemplate("RepairBase", "ChatSelfRepairTurrets", %client, -1);
}
}
}
}
//set the target object
if (%task.targetObject.getDamagePercent() > 0)
{
//make sure we still have equipment
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
if (%client.needEquipment)
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
return;
}
}
if (%task.deployed)
{
//see if we're within range of the deploy location
%clLoc = %client.player.position;
%distance = VectorDist(%clLoc, %task.repairLocation);
%dist2D = VectorDist(%client.player.position, getWords(%task.repairLocation, 0, 1) SPC getWord(%client.player.position, 2));
//set the aim when we get near the target... this will be overwritten when we're actually trying to deploy
if (%distance < 10 && %dist2D < 10)
%client.aimAt(%task.location, 1000);
//see if we're at the deploy location
if ((%client.pathDistRemaining(20) > %distance + 0.25) || %dist2D > 0.3)
{
%client.setTargetObject(-1);
%client.stepMove(%task.repairLocation, 0.25);
}
else
{
%client.stop();
%client.setTargetObject(%task.targetObject, 8.0, "Repair");
}
}
else
{
%currentTime = getSimTime();
if (%currentTime > %task.needToRangeTime)
{
//force a rangeObject every 10 seconds...
%task.needToRangeTime = %currentTime + 6000;
%client.setTargetObject(-1);
%client.stepRangeObject(%task.targetObject, "DefaultRepairBeam", 3, 8);
}
//if we've ranged the object, start repairing, else unset the object
else if (%client.getStepStatus() $= "Finished")
{
//dissolve the human control link
if (%task == %client.objectiveTask)
aiReleaseHumanControl(%client.controlByHuman, %client);
%client.setTargetObject(%task.targetObject, 8.0, "Repair");
}
else
%client.setTargetObject(-1);
}
}
else
{
%client.setTargetObject(-1);
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
}
}
//------------------------------
function AILazeObject::initFromObjective(%task, %objective, %client)
{
%task.baseWeight = %client.objectiveWeight;
%task.targetObject = %objective.targetObjectId;
%task.equipment = %objective.equipment;
%task.buyEquipmentSet = %objective.buyEquipmentSet;
%task.desiredEquipment = %objective.desiredEquipment;
%task.issuedByClient = %objective.issuedByClientId;
%task.msgAck = true;
%task.msgFire = true;
}
function AILazeObject::assume(%task, %client)
{
%task.setWeightFreq(30);
%task.setMonitorFreq(30);
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
//clear the target object, and range it
%client.setTargetObject(-1);
if (! %client.needEquipment)
%client.stepRangeObject(%task.targetObject, "BasicTargeter", 80, 300, %task.issuedByClient.player.getWorldBoxCenter());
//set up some task vars
%task.celebrate = false;
%task.waitTimerMS = 0;
//mark the current time for the buy inventory state machine
%task.buyInvTime = getSimTime();
}
function AILazeObject::retire(%task, %client)
{
%client.setTargetObject(-1);
}
function AILazeObject::weight(%task, %client)
{
//update the task weight
if (%task == %client.objectiveTask)
%task.baseWeight = %client.objectiveWeight;
//let the monitor decide when to stop lazing
%task.setWeight(%task.baseWeight);
}
function AILazeObject::monitor(%task, %client)
{
//first, buy the equipment
if (%client.needEquipment)
{
%task.setMonitorFreq(5);
if (%task.equipment !$= "")
%equipmentList = %task.equipment;
else
%equipmentList = %task.desiredEquipment;
%result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime);
if (%result $= "InProgress")
return;
else if (%result $= "Finished")
{
%task.setMonitorFreq(30);
%client.needEquipment = false;
%client.stepRangeObject(%task.targetObject, "BasicTargeter", 80, 300);
}
else if (%result $= "Failed")
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
}
//if we made it past the inventory buying, reset the inv time
%task.buyInvTime = getSimTime();
//set the target object
if (isObject(%task.targetObject) && %task.targetObject.getDamageState() !$= "Destroyed")
{
//make sure we still have equipment
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
if (%client.needEquipment)
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
return;
}
}
//look to see if anyone else is also targetting...
%foundTarget = false;
%numTargets = ServerTargetSet.getCount();
for (%i = 0; %i < %numTargets; %i++)
{
%targ = ServerTargetSet.getObject(%i);
if (%targ.sourceObject != %client.player)
{
%targDist = VectorDist(%targ.getTargetPoint(), %task.targetObject.getWorldBoxCenter());
if (%targDist < 10)
{
%foundTarget = true;
break;
}
}
}
if (%foundTarget)
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
AIUnassignClient(%client);
}
else if (%client.getStepStatus() $= "Finished")
{
//dissolve the human control link
if (%task == %client.objectiveTask)
aiReleaseHumanControl(%client.controlByHuman, %client);
%client.setTargetObject(%task.targetObject, 300, "Laze");
%task.celebrate = true;
%task.waitTimerMS = 0;
//make sure we only say "fire..." once
if (%task.msgFire)
{
AIMessageThread("FireOnTarget", %client, -1);
%task.msgFire = false;
}
}
else
{
%client.aimAt(%task.targetObject.getWorldBoxCenter(), 1000);
%client.setTargetObject(-1);
}
}
else
{
%client.setTargetObject(-1);
if (%task.celebrate)
{
if (%task.waitTimerMS == 0)
{
//add in a "woohoo"! :)
//choose the animation range
%minCel = 3;
%maxCel = 8;
//pick a random sound
if (getRandom() > 0.25)
%sound = "gbl.awesome";
else if (getRandom() > 0.5)
%sound = "gbl.thanks";
else if (getRandom() > 0.75)
%sound = "gbl.nice";
else
%sound = "gbl.rock";
%randTime = mFloor(getRandom() * 500) + 1;
schedule(%randTime, %client, "AIPlayAnimSound", %client, %task.targetObject.getWorldBoxCenter(), %sound, %minCel, %maxCel, 0);
//set the timer
%task.waitTimerMS = getSimTime();
}
//else see if the celebration period is over
else if (getSimTime() - %task.waitTimerMS > 3000)
%task.celebrate = false;
}
else
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
}
}
}
//------------------------------
function AIMortarObject::initFromObjective(%task, %objective, %client)
{
%task.baseWeight = %client.objectiveWeight;
%task.targetObject = %objective.targetObjectId;
%task.equipment = %objective.equipment;
%task.buyEquipmentSet = %objective.buyEquipmentSet;
%task.desiredEquipment = %objective.desiredEquipment;
%task.issuedByClient = %objective.issuedByClientId;
%task.mode = %task.targetObject.getDataBlock().getName();
%task.sendMsgTime = 0;
%task.sendMsg = true;
}
function AIMortarObject::assume(%task, %client)
{
%task.setWeightFreq(30);
%task.setMonitorFreq(30);
%task.state = moveToRange;
%task.waitForTargetter = true;
%task.celebrate = false;
%task.waitTimerMS = 0;
%task.targetAcquired = false;
%task.sayAcquired = true;
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
//even if we don't *need* equipemnt, see if we should buy some...
if (! %client.needEquipment && %task.buyEquipmentSet !$= "")
{
//see if we could benefit from inventory
%needArmor = AIMustUseRegularInvStation(%task.desiredEquipment, %client);
%result = AIFindClosestInventory(%client, %needArmor);
%closestInv = getWord(%result, 0);
%closestDist = getWord(%result, 1);
if (AINeedEquipment(%task.desiredEquipment, %client) && %closestInv > 0)
{
//find where we are
%clientPos = %client.player.getWorldBoxCenter();
%objPos = %task.targetObject.getWorldBoxCenter();
%distToObject = %client.getPathDistance(%objPos);
if (%distToObject < 0 || %closestDist < %distToObject)
%client.needEquipment = true;
}
}
//mark the current time for the buy inventory state machine
%task.buyInvTime = getSimTime();
}
function AIMortarObject::retire(%task, %client)
{
%client.setTargetObject(-1);
//remove the associated lazeObjective
if (%task.targetterObjective)
{
AIClearObjective(%task.targetterObjective);
%task.targetterObjective.delete();
%task.targetterObjective = "";
}
}
function AIMortarObject::weight(%task, %client)
{
//update the task weight
if (%task == %client.objectiveTask)
%task.baseWeight = %client.objectiveWeight;
//let the monitor decide when to stop mortaring
%task.setWeight(%task.baseWeight);
}
function AIMortarObject::monitor(%task, %client)
{
//first, buy the equipment
if (%client.needEquipment)
{
%task.setMonitorFreq(5);
if (%task.equipment !$= "")
%equipmentList = %task.equipment;
else
%equipmentList = %task.desiredEquipment;
%result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime);
if (%result $= "InProgress")
return;
else if (%result $= "Finished")
{
%task.setMonitorFreq(30);
%client.needEquipment = false;
}
else if (%result $= "Failed")
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
}
//if we made it past the inventory buying, reset the inv time
%task.buyInvTime = getSimTime();
//chat
if (%task.sendMsg)
{
if (%task.sendMsgTime == 0)
%task.sendMsgTime = getSimTime();
else if (getSimTime() - %task.sendMsgTime > 7000)
{
%task.sendMsg = false;
if (%client.isAIControlled())
{
if (%task.chat !$= "")
{
%chatMsg = getWord(%task.chat, 0);
%chatTemplate = getWord(%task.chat, 1);
if (%chatTemplate !$= "")
AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1);
else
AIMessageThread(%task.chat, %client, -1);
}
else if (%task.targetObject > 0)
{
%type = %task.targetObject.getDataBlock().getName();
if (%type $= "GeneratorLarge")
AIMessageThreadTemplate("AttackBase", "ChatSelfAttackGenerator", %client, -1);
else if (%type $= "SensorLargePulse")
AIMessageThreadTemplate("AttackBase", "ChatSelfAttackSensors", %client, -1);
else if (%type $= "SensorMediumPulse")
AIMessageThreadTemplate("AttackBase", "ChatSelfAttackSensors", %client, -1);
else if (%type $= "TurretBaseLarge")
AIMessageThreadTemplate("AttackBase", "ChatSelfAttackTurrets", %client, -1);
else if (%type $= "StationVehicle")
AIMessageThreadTemplate("AttackBase", "ChatSelfAttackVehicle", %client, -1);
}
}
}
}
//make sure we still have something to destroy
if (isObject(%task.targetObject) && %task.targetObject.getDamageState() !$= "Destroyed")
{
%clientPos = %client.player.getWorldBoxCenter();
%targetPos = %task.targetObject.getWorldBoxCenter();
%distance = %client.getPathDistance(%targetPos);
if (%distance < 0)
%distance = 32767;
//make sure we still have equipment
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
if (%client.needEquipment)
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
return;
}
}
//next move to within 220
else if (%distance > 220)
{
%client.setTargetObject(-1);
%client.stepMove(%task.targetObject.getWorldBoxCenter(), 15);
}
//now start ask for someone to laze the target, and start a 20 sec timer
else if (%task.waitForTargetter)
{
//see if we've started the timer
if (%task.waitTimerMS == 0)
{
//range the object
%client.stepRangeObject(%task.targetObject, "MortarShot", 100, 200);
//now ask for a targeter...
%targetType = %task.targetObject.getDataBlock().getName();
if (%targetType $= "TurretBaseLarge")
AIMessageThread("ChatCmdTargetTurret", %client, -1);
else if (%targetType $= "SensorLargePulse")
AIMessageThread("ChatCmdTargetSensors", %client, -1);
else if (%targetType $= "SensorMediumPulse")
AIMessageThread("ChatCmdTargetSensors", %client, -1);
else
AIMessageThread("ChatNeedTarget", %client, -1);
%task.waitTimerMS = getSimTime();
//create the objective
if (! %task.targetterObjective)
{
%task.targetterObjective = new AIObjective(AIOLazeObject)
{
dataBlock = "AIObjectiveMarker";
weightLevel1 = $AIWeightLazeObject[1];
weightLevel2 = $AIWeightLazeObject[2];
description = "Laze the " @ %task.targetObject.getName();
targetObjectId = %task.targetObject;
issuedByClientId = %client;
offense = true;
equipment = "TargetingLaser";
};
MissionCleanup.add(%task.targetterObjective);
$ObjectiveQ[%client.team].add(%task.targetterObjective);
}
%task.targetterObjective.lastLazedTime = 0;
//remove the escort (want a targetter instead)
if (%client.escort)
{
AIClearObjective(%client.escort);
%client.escort.delete();
%client.escort = "";
}
}
else
{
%elapsedTime = getSimTime() - %task.waitTimerMS;
if (%task.targetterObjective.group > 0)
%targetter = %task.targetterObjective.group.clientLevel[1];
else
%targetter = %task.targetterObjective.clientLevel[1];
//see if we can find a target near our objective
%task.targetAcquired = false;
%numTargets = ServerTargetSet.getCount();
for (%i = 0; %i < %numTargets; %i++)
{
%targ = ServerTargetSet.getObject(%i);
%targDist = VectorDist(%targ.getTargetPoint(), %task.targetObject.getWorldBoxCenter());
if (%targDist < 20)
{
%task.targetAcquired = true;
break;
}
}
if (%task.targetAcquired)
{
%task.waitForTargetter = false;
%task.waitTimerMS = 0;
%task.celebrate = true;
%task.sayAcquired = false;
AIMessageThread("ChatTargetAcquired", %client, -1);
}
//else see if we've run out of time
else if ((! %targetter || ! %targetter.isAIControlled()) && %elapsedTime > 20000)
{
%task.waitForTargetter = false;
%task.waitTimerMS = 0;
%task.celebrate = true;
}
}
}
//now we should finally be attacking with or without a targetter
//eventually, the target will be destroyed, or we'll run out of ammo...
else
{
//dissolve the human control link
if (%task == %client.objectiveTask)
aiReleaseHumanControl(%client.controlByHuman, %client);
//see if we didn't acquired a spotter along the way
if (%task.targetterObjective.group > 0)
%targetter = %task.targetterObjective.group.clientLevel[1];
else
%targetter = %task.targetterObjective.clientLevel[1];
if (! %task.targetAcquired && AIClientIsAlive(%targetter) && %targetter.isAIControlled())
{
%client.setTargetObject(-1);
%task.waitForTargetter = true;
}
else
{
//see if we can find a target near our objective
if (! %task.targetAcquired)
{
%numTargets = ServerTargetSet.getCount();
for (%i = 0; %i < %numTargets; %i++)
{
%targ = ServerTargetSet.getObject(%i);
%targDist = VectorDist(%targ.getTargetPoint(), %task.targetObject.getWorldBoxCenter());
if (%targDist < 20)
{
%task.targetAcquired = true;
break;
}
}
//see if we found a target (must be by a human)
if (%task.targetAcquired && %task.sayAcquired)
{
%task.sayAcquired = false;
AIMessageThread("ChatTargetAcquired", %client, -1);
}
}
//set the target object, and keep attacking it
if (%client.getStepStatus() $= "Finished")
%client.setTargetObject(%task.targetObject, 250, "Mortar");
else
%client.setTargetObject(-1);
}
}
}
//the target must have been destroyed :)
else
{
//dissolve the human control link
if (%task == %client.objectiveTask)
aiReleaseHumanControl(%client.controlByHuman, %client);
%client.setTargetObject(-1);
%client.clearStep();
%client.stop();
if (%task.celebrate)
{
if (%task.waitTimerMS == 0)
{
//client animation "woohoo"! :)
//choose the animation range
%minCel = 3;
%maxCel = 8;
//pick a random sound
if (getRandom() > 0.25)
%sound = "gbl.awesome";
else if (getRandom() > 0.5)
%sound = "gbl.thanks";
else if (getRandom() > 0.75)
%sound = "gbl.nice";
else
%sound = "gbl.rock";
%randTime = mFloor(getRandom() * 500) + 1;
schedule(%randTime, %client, "AIPlayAnimSound", %client, %task.targetObject.getWorldBoxCenter(), %sound, %minCel, %maxCel, 0);
//team message
AIMessageThread("ChatEnemyTurretsDestroyed", %client, -1);
//set the timer
%task.waitTimerMS = getSimTime();
}
//else see if the celebration period is over
else if (getSimTime() - %task.waitTimerMS > 3000)
%task.celebrate = false;
}
else
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
}
}
}
//------------------------------
function AIDeployEquipment::initFromObjective(%task, %objective, %client)
{
//initialize the task vars from the objective
%task.baseWeight = %client.objectiveWeight;
%task.location = %objective.location;
%task.equipment = %objective.equipment;
%task.buyEquipmentSet = %objective.buyEquipmentSet;
%task.desiredEquipment = %objective.desiredEquipment;
%task.issuedByClient = %objective.issuedByClientId;
%task.chat = %objective.chat;
//initialize other task vars
%task.sendMsg = true;
%task.sendMsgTime = 0;
//use the Y-axis of the rotation as the desired direction of deployement,
//and calculate a walk to point 3 m behind the deploy point.
%task.deployDirection = MatrixMulVector("0 0 0 " @ getWords(%objective.getTransform(), 3, 6), "0 1 0");
%task.deployDirection = VectorNormalize(%task.deployDirection);
}
function AIDeployEquipment::assume(%task, %client)
{
%task.setWeightFreq(15);
%task.setMonitorFreq(15);
%client.needEquipment = AINeedEquipment(%task.equipment, %client);
//mark the current time for the buy inventory state machine
%task.buyInvTime = getSimTime();
%task.passes = 0;
%task.deployAttempts = 0;
%task.checkObstructed = false;
%task.waitMove = 0;
}
function AIDeployEquipment::retire(%task, %client)
{
}
function AIDeployEquipment::weight(%task, %client)
{
//update the task weight
if (%task == %client.objectiveTask)
%task.baseWeight = %client.objectiveWeight;
%task.setWeight(%task.baseWeight);
}
function findTurretDeployPoint(%client, %location, %attempt)
{
%player = %client.player;
if (!isObject(%player))
return "0 0 0";
%feetPos = posFromTransform(%player.getTransform());
%temp = VectorSub(%location, %feetPos);
%temp2 = getWord(%temp, 0) @ " " @ getWord(%temp, 1) @ " 0";
%facingVector = VectorNormalize(%temp2);
%aimPoint = VectorAdd(%feetPos, %facingVector);
//assume that there will be 10 attempts
%height = getWord(%location, 2) + 1.0 - (0.2 * %attempt);
%aimAt = getWord(%aimPoint, 0) @ " " @ getWord(%aimPoint, 1) @ " " @ %height;
return %aimAt;
}
function AIDeployEquipment::monitor(%task, %client)
{
//first, buy the equipment
if (%client.needEquipment)
{
%task.setMonitorFreq(5);
if (%task.equipment !$= "")
%equipmentList = %task.equipment;
else
%equipmentList = %task.desiredEquipment;
%result = AIBuyInventory(%client, %equipmentList, %task.buyEquipmentSet, %task.buyInvTime);
if (%result $= "InProgress")
return;
else if (%result $= "Finished")
{
%task.setMonitorFreq(30);
%client.needEquipment = false;
//if we made it past the inventory buying, reset the inv time
%task.buyInvTime = getSimTime();
}
else if (%result $= "Failed")
{
//if this task is the objective task, choose a new objective
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
return;
}
}
//chat
if (%task.sendMsg)
{
if (%task.sendMsgTime == 0)
%task.sendMsgTime = getSimTime();
else if (getSimTime() - %task.sendMsgTime > 7000)
{
%task.sendMsg = false;
if (%client.isAIControlled())
{
if (%task.chat !$= "")
{
%chatMsg = getWord(%task.chat, 0);
%chatTemplate = getWord(%task.chat, 1);
if (%chatTemplate !$= "")
AIMessageThreadTemplate(%chatTemplate, %chatMsg, %client, -1);
else
AIMessageThread(%task.chat, %client, -1);
}
}
}
}
//see if we're supposed to be engaging anyone...
if (AIClientIsAlive(%client.shouldEngage))
{
%hasLOS = %client.hasLOSToClient(%client.shouldEngage);
%losTime = %client.getClientLOSTime(%client.shouldEngage);
if (%hasLOS || %losTime < 1000)
%client.setEngageTarget(%client.shouldEngage);
else
%client.setEngageTarget(-1);
}
else
%client.setEngageTarget(-1);
//calculate the deployFromLocation
%factor = -1 * (3 - (%task.passes * 0.5));
%task.deployFromLocation = VectorAdd(%task.location,VectorScale(%task.deployDirection, %factor));
//see if we're within range of the deploy location
%clLoc = %client.player.position;
%distance = VectorDist(%clLoc, %task.deployFromLocation);
%dist2D = VectorDist(%client.player.position, getWords(%task.deployFromLocation, 0, 1) SPC getWord(%client.player.position, 2));
//set the aim when we get near the target... this will be overwritten when we're actually trying to deploy
if (%distance < 10 && %dist2D < 10)
%client.aimAt(%task.location, 1000);
if ((%client.pathDistRemaining(20) > %distance + 0.25) || %dist2D > 0.5)
{
%task.deployAttempts = 0;
%task.checkObstructed = false;
%task.waitMove = 0;
%client.stepMove(%task.deployFromLocation, 0.25);
%task.setMonitorFreq(15);
return;
}
if (%task.deployAttempts < 10 && %task.passes < 5 && !AIClientIsAlive(%client.getEngageTarget()))
{
//dissolve the human control link
if (%task == %client.objectiveTask)
aiReleaseHumanControl(%client.controlByHuman, %client);
%task.setMonitorFreq(3);
%client.stop();
if (%task.deployAttempts == 0)
%deployPoint = %task.location;
else
%deployPoint = findTurretDeployPoint(%client, %task.location, %task.deployAttempts);
if(%deployPoint !$= "")
{
// we have possible point
%task.deployAttempts++;
%client.aimAt(%deployPoint, 2000);
//try to deploy the backpack
%client.deployPack = true;
%client.lastDeployedObject = -1;
%client.player.use(Backpack);
// check if pack deployed
if (isObject(%client.lastDeployedObject))
{
//see if there's a "repairObject" objective for the newly deployed thingy...
if (%task == %client.objectiveTask)
{
%deployedObject = %client.lastDeployedObject;
//search the current objective group and search for a "repair Object" task...
%objective = %client.objective;
//delete any previously associated "AIORepairObject" objective
if (isObject(%objective.repairObjective))
{
AIClearObjective(%objective.repairObjective);
%objective.repairObjective.delete();
%objective.repairObjective = "";
}
//add the repair objective
%objective.repairObjective = new AIObjective(AIORepairObject)
{
dataBlock = "AIObjectiveMarker";
weightLevel1 = %objective.weightLevel1 - 60;
weightLevel2 = 0;
description = "Repair the " @ %deployedObject.getDataBlock().getName();
targetObjectId = %deployedObject;
issuedByClientId = %client;
offense = false;
defense = true;
equipment = "RepairPack";
};
%objective.repairObjective.deployed = true;
%objective.repairObjective.setTransform(%objective.getTransform());
%objective.repairObjective.group = %objective.group;
MissionCleanup.add(%objective.repairObjective);
$ObjectiveQ[%client.team].add(%objective.repairObjective);
//finally, unassign the client so he'll go do something else...
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
//finished
return;
}
}
}
else if (!%task.checkObstructed)
{
%task.checkObstructed = true;
//see if anything is in our way
InitContainerRadiusSearch(%task.location, 4, $TypeMasks::MoveableObjectType | $TypeMasks::VehicleObjectType |
$TypeMasks::PlayerObjectType);
%objSrch = containerSearchNext();
if (%objSrch == %client.player)
%objSrch = containerSearchNext();
if (%objSrch)
AIMessageThread("ChatMove", %client, -1);
}
else if (%task.waitMove < 5 && %task.passes < 5)
{
%task.waitMove++;
//try another pass at deploying
if (%task.waitMove == 5)
{
%task.waitMove = 0;
%task.passes++;
%task.deployAttempts = 0;
//see if we're *right* underneath the deploy point
%deployDist2D = VectorDist(getWords(%client.player.position, 0, 1) @ "0", getWords(%task.location, 0, 1) @ "0");
if (%deployDist2D < 0.25)
{
%client.pressjump();
%client.deployPack = true;
%client.player.use(Backpack);
// check if pack deployed
if(%client.player.getMountedImage($BackpackSlot) == 0)
{
//don't add a "repairObject" objective for ceiling turrets
if (%task == %client.objectiveTask)
{
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
}
}
}
}
else
{
//find a new assignment - and remove this one from the Queue
if (%task == %client.objectiveTask)
{
error(%client SPC "from team" SPC %client.team SPC "is invalidating objective:" SPC %client.objective SPC "UNABLE TO DEPLOY EQUIPMENT");
%client.objective.isInvalid = true;
AIUnassignClient(%client);
Game.AIChooseGameObjective(%client);
}
}
}
//------------------------------
//AI Objective functions
function ClientHasAffinity(%objective, %client)
{
if (%objective.offense && %client.offense)
return true;
else if (%objective.defense && !%client.offense)
return true;
else
return false;
}
function ClientHasRequiredEquipment(%objective, %client)
{
return true;
}
function AIODefault::weight(%objective, %client, %level, %inventoryStr)
{
//make sure the player is still alive!!!!!
if (! AIClientIsAlive(%client))
return 0;
//set the base weight
switch (%level)
{
case 1:
%weight = %objective.weightLevel1;
case 2:
%weight = %objective.weightLevel2;
case 3:
%weight = %objective.weightLevel3;
default:
%weight = %objective.weightLevel4;
}
//check Affinity
if (ClientHasAffinity(%objective, %client))
%weight += 40;
//if the objective doesn't require any equipment, it automatically get's the +100...
if (%objective.equipment $= "" && %objective.desiredEquipment $= "")
%weight += 100;
else
{
//check equipment requirement
%needEquipment = AINeedEquipment(%objective.equipment, %client);
//check Required equipment
if (%objective.equipment !$= "" && !%needEquipment)
%weight += 100;
//figure out the percentage of desired equipment the bot has
else if (%objective.desiredEquipment !$= "")
{
%count = getWordCount(%objective.desiredEquipment);
%itemCount = 0;
for (%i = 0; %i < %count; %i++)
{
%item = getWord(%objective.desiredEquipment, %i);
if (!AINeedEquipment(%item, %client))
%itemCount++;
}
//add to the weight
%weight += mFloor((%itemCount / %count) * 75);
}
}
//find the distance to target
if (%objective.targetClientId !$= "" || %objective.targetObjectId !$= "")
{
if (AIClientIsAlive(%objective.targetClientId))
{
%targetPos = %objective.targetClientId.player.getWorldBoxCenter();
}
else if (VectorDist(%objective.location, "0 0 0") > 1)
%targetPos = %objective.location;
else
{
if(%objective.targetObjectId > 0)
%targetPos = %objective.targetObjectId.getWorldBoxCenter();
}
}
//make sure the destination is accessible
%distance = %client.getPathDistance(%targetPos);
if (%distance < 0)
return 0;
%closestInvIsRemote = (getWordCount(%inventoryStr) == 4);
%closestInv = getWord(%inventoryStr, 0);
%closestDist = getWord(%inventoryStr, 1);
%closestRemoteInv = getWord(%inventoryStr, 2);
%closestRemoteDist = getWord(%inventoryStr, 3);
//if we need equipment, the distance is from the client, to an inv, then to the target
if (%needEquipment)
{
//if we need a regular inventory station, and one doesn't exist, exit
if (!isObject(%closestInv) && %needArmor)
return 0;
//find the closest inv based on whether we require armor (from a regular inv station)
if (!%closestInvIsRemote)
{
%needArmor = false;
%weightDist = %closestDist;
%weightInv = %closestInv;
}
else
{
%needArmor = AIMustUseRegularInvStation(%objective.equipment, %client);
if (%needArmor)
{
%weightDist = %closestDist;
%weightInv = %closestInv;
}
else
{
%weightDist = %closestRemoteDist;
%weightInv = %closestRemoteInv;
}
}
//if we don't need armor, and there's no inventory station, see if the equipment we need
//is something we can pick up off the ground (likely this would be a repair pack...)
if (%weightDist >= 32767)
{
%itemType = getWord(%objective.equipment, 0);
%found = false;
%itemCount = $AIItemSet.getCount();
for (%i = 0; %i < %itemCount; %i++)
{
%item = $AIItemSet.getObject(%i);
if (%item.getDataBlock().getName() $= %itemType && !%item.isHidden())
{
%weightDist = %client.getPathDistance(%item.getWorldBoxCenter());
if (%weightDist > 0)
{
%weightInv = %item; //set the var so the distance function will work...
%found = true;
break;
}
}
}
if (! %found)
return 0;
}
//now find the distance used for weighting the objective
%tempDist = AIGetPathDistance(%targetPos, %weightInv.getWorldBoxCenter());
if (%tempDist < 0)
%tempDist = 32767;
%distance = %weightDist + %tempDist;
}
//see if we're within 200 m
if (%distance < 200)
%weight += 30;
//see if we're within 90 m
if (%distance < 90)
%weight += 30;
//see if we're within 45 m
if (%distance < 45)
%weight += 30;
//see if we're within 20 m
if (%distance < 20)
%weight += 30;
//final return, since we've made it through all the rest
return %weight;
}
function AIODefault::QuickWeight(%objective, %client, %level, %minWeight)
{
//can't do a quick weight when re-evaluating a client's current objective
if (%client.objective == %objective)
return true;
//do a quick check to disqualify this objective if it can't meet the minimum weight
switch (%level)
{
case 1:
%testWeight = %objective.weightLevel1;
case 2:
%testWeight = %objective.weightLevel2;
case 3:
%testWeight = %objective.weightLevel3;
default:
%testWeight = %objective.weightLevel4;
}
if (%testWeight + 260 < %minWeight)
return false;
else
return true;
}
//------------------------------
function AIODefendLocation::weight(%this, %client, %level, %minWeight, %inventoryStr)
{
// if were playing CnH, check who owns this
if (%this.targetObjectId > 0)
{
if (!isObject(%this.targetObjectId) || %this.targetObjectId.isHidden() || %this.targetObjectId.team != %client.team)
return 0;
}
//make sure the player is still alive!!!!!
if (! AIClientIsAlive(%client))
return 0;
//do a quick check to disqualify this objective if it can't meet the minimum weight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
{
if (%this.targetObjectId > 0 && %this.issuedByClientId == %client.controlByHuman)
{
if ($AIWeightHumanIssuedCommand < %minWeight)
return 0;
}
else
return 0;
}
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
//if the object has been destroyed, reduce the weight
if (%this.targetObjectId > 0)
{
//see if we were forced on the objective
if (%this.issuedByClientId == %client.controlByHuman && %weight < $AIWeightHumanIssuedCommand)
%weight = $AIWeightHumanIssuedCommand;
//else see if the object has been destroyed
else if (!isObject(%this.targetObjectId) || %this.targetObjectId.getDamageState() $= "Destroyed")
%weight -= 320;
}
return %weight;
}
function AIODefendLocation::assignClient(%this, %client)
{
%client.objectiveTask = %client.addTask(AIDefendLocation);
%client.objectiveTask.initFromObjective(%this, %client);
}
function AIODefendLocation::unassignClient(%this, %client)
{
%client.removeTask(%client.objectiveTask);
%client.objectiveTask = "";
}
//------------------------------
function AIOAttackLocation::weight(%this, %client, %level, %minWeight, %inventoryStr)
{
//make sure the player is still alive!!!!!
if (! AIClientIsAlive(%client))
return 0;
//now, if this bot is linked to a human who has issued this command, up the weight
if (%this.issuedByClientId == %client.controlByHuman)
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
{
if ($AIWeightHumanIssuedCommand < %minWeight)
return 0;
else
%weight = $AIWeightHumanIssuedCommand;
}
else
{
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
if (%weight < $AIWeightHumanIssuedCommand)
%weight = $AIWeightHumanIssuedCommand;
}
}
else
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
return 0;
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
}
return %weight;
}
function AIOAttackLocation::assignClient(%this, %client)
{
%client.objectiveTask = %client.addTask(AIAttackLocation);
%client.objectiveTask.initFromObjective(%this, %client);
}
function AIOAttackLocation::unassignClient(%this, %client)
{
%client.removeTask(%client.objectiveTask);
%client.objectiveTask = "";
}
//------------------------------
function AIOTouchObject::weight(%this, %client, %level, %minWeight, %inventoryStr)
{
//make sure the player is still alive!!!!!
if (! AIClientIsAlive(%client))
return 0;
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
return 0;
switch$ (%this.mode)
{
case "TouchFlipFlop":
if(%this.targetObjectId.team == %client.team || %this.targetObjectId.isHidden())
return 0;
else
return AIODefault::weight(%this, %client, %level, %inventoryStr);
case "FlagGrab":
if (! %this.targetObjectId.isHome)
return 0;
else
return AIODefault::weight(%this, %client, %level, %inventoryStr);
case "FlagDropped":
if ((%this.targetObjectId.isHome) || (%this.targetObjectId.carrier !$= ""))
return 0;
else
return AIODefault::weight(%this, %client, %level, %inventoryStr);
case "FlagCapture":
if (%this.targetObjectId.carrier != %client.player)
return 0;
else
{
//find our home flag location
%homeTeam = %client.team;
%homeFlag = $AITeamFlag[%homeTeam];
%this.location = %homeFlag.originalPosition;
return AIODefault::weight(%this, %client, %level, %inventoryStr);
}
}
return 0;
}
function AIOTouchObject::assignClient(%this, %client)
{
%client.objectiveTask = %client.addTask(AITouchObject);
%client.objectiveTask.initFromObjective(%this, %client);
//create an AIOEscortPlayer objective to help out, if required
if (%this.mode $= "FlagGrab")
{
%client.escort = new AIObjective(AIOEscortPlayer)
{
dataBlock = "AIObjectiveMarker";
weightLevel1 = $AIWeightEscortOffense[1];
weightLevel2 = $AIWeightEscortOffense[2];
description = "Escort " @ getTaggedString(%client.name);
targetClientId = %client;
offense = true;
desiredEquipment = "EnergyPack";
buyEquipmentSet = "LightEnergyELF";
};
MissionCleanup.add(%client.escort);
$ObjectiveQ[%client.team].add(%client.escort);
}
else if (%this.mode $= "FlagCapture")
{
%client.escort = new AIObjective(AIOEscortPlayer)
{
dataBlock = "AIObjectiveMarker";
weightLevel1 = $AIWeightEscortCapper[1];
weightLevel2 = $AIWeightEscortCapper[2];
description = "Escort " @ getTaggedString(%client.name);
targetClientId = %client;
offense = true;
desiredEquipment = "EnergyPack";
buyEquipmentSet = "LightEnergyDefault";
};
MissionCleanup.add(%client.escort);
$ObjectiveQ[%client.team].add(%client.escort);
}
}
function AIOTouchObject::unassignClient(%this, %client)
{
//kill the escort objective
if (%client.escort)
{
AIClearObjective(%client.escort);
%client.escort.delete();
%client.escort = "";
}
%client.removeTask(%client.objectiveTask);
%client.objectiveTask = "";
}
//------------------------------
function AIOAttackPlayer::weight(%this, %client, %level, %minWeight, %inventoryStr)
{
//make sure the player is still alive!!!!!
if (! AIClientIsAlive(%client))
return 0;
//if we're attacking the flag carrier, make sure a flag carrier exists
if (%this.mode $= "FlagCarrier")
{
if (%this.targetObjectId.carrier $= "")
return 0;
else
%this.targetClientId = %this.targetObjectId.carrier.client;
}
//now, if this bot is linked to a human who has issued this command, up the weight
if (%this.issuedByClientId == %client.controlByHuman)
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
{
if ($AIWeightHumanIssuedCommand < %minWeight)
return 0;
else
%weight = $AIWeightHumanIssuedCommand;
}
else
{
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
if (%weight < $AIWeightHumanIssuedCommand)
%weight = $AIWeightHumanIssuedCommand;
}
}
else
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
return 0;
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
}
return %weight;
}
function AIOAttackPlayer::assignClient(%this, %client)
{
%client.objectiveTask = %client.addTask(AIAttackPlayer);
%client.objectiveTask.initFromObjective(%this, %client);
}
function AIOAttackPlayer::unassignClient(%this, %client)
{
%client.removeTask(%client.objectiveTask);
%client.objectiveTask = "";
}
//------------------------------
function AIOEscortPlayer::weight(%this, %client, %level, %minWeight, %inventoryStr)
{
//make sure the player is still alive!!!!!
if (! AIClientIsAlive(%client) || ! AIClientIsAlive(%this.targetClientId))
return 0;
//can't escort yourself
if (%client == %this.targetClientId)
return 0;
//make sure the class is appropriate
if (%this.forceClientId <= 0 && %this.issuedByClientId != %client.controlByHuman)
{
%targArmor = %this.targetClientId.player.getArmorSize();
%myArmor = %client.player.getArmorSize();
if ((%targArmor $= "Light" && %myArmor !$= "Light") || %myArmor $= "Heavy")
return 0;
}
//can't bump a forced client from level 1
if (%this.forceClientId > 0 && %this.forceClientId != %client && %level == 1)
return 0;
//if this bot is linked to a human who has issued this command, up the weight
if (%this.issuedByClientId == %client.controlByHuman)
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
{
if ($AIWeightHumanIssuedEscort < %minWeight)
return 0;
else
%weight = $AIWeightHumanIssuedEscort;
}
else
{
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
if (%weight < $AIWeightHumanIssuedEscort)
%weight = $AIWeightHumanIssuedEscort;
}
}
else
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
return 0;
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
}
return %weight;
}
function AIOEscortPlayer::assignClient(%this, %client)
{
%client.objectiveTask = %client.addTask(AIEscortPlayer);
%client.objectiveTask.initFromObjective(%this, %client);
}
function AIOEscortPlayer::unassignClient(%this, %client)
{
%client.removeTask(%client.objectiveTask);
%client.objectiveTask = "";
}
//------------------------------
function AIOAttackObject::weight(%this, %client, %level, %minWeight, %inventoryStr)
{
// if were playing CnH, check who owns this
if (!isObject(%this.targetObjectId) || %this.targetObjectId.isHidden() || %this.targetObjectId.team == %client.team)
return 0;
//make sure the player is still alive!!!!!
if (! AIClientIsAlive(%client))
return 0;
//no need to attack if the object is already destroyed
if (!isObject(%this.targetObjectId) || %this.targetObjectId.getDamageState() $= "Destroyed")
return 0;
else
{
//if this bot is linked to a human who has issued this command, up the weight
if (%this.issuedByClientId == %client.controlByHuman)
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
{
if ($AIWeightHumanIssuedCommand < %minWeight)
return 0;
else
%weight = $AIWeightHumanIssuedCommand;
}
else
{
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
if (%weight < $AIWeightHumanIssuedCommand)
%weight = $AIWeightHumanIssuedCommand;
}
}
else
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
return 0;
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
}
return %weight;
}
}
function AIOAttackObject::assignClient(%this, %client)
{
%client.objectiveTask = %client.addTask(AIAttackObject);
%client.objectiveTask.initFromObjective(%this, %client);
}
function AIOAttackObject::unassignClient(%this, %client)
{
%client.removeTask(%client.objectiveTask);
%client.objectiveTask = "";
}
//------------------------------
function AIORepairObject::weight(%this, %client, %level, %minWeight, %inventoryStr)
{
// if were playing CnH, check who owns this
if (!isObject(%this.targetObjectId) || %this.targetObjectId.isHidden() || %this.targetObjectId.team != %client.team)
return 0;
//make sure the player is still alive!!!!!
if (! AIClientIsAlive(%client))
return 0;
//no need to repair if the object isn't in need
if (!isObject(%this.targetObjectId) || %this.targetObjectId.getDamagePercent() <= 0)
return 0;
else
{
//if this bot is linked to a human who has issued this command, up the weight
if (%this.issuedByClientId == %client.controlByHuman)
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
{
if ($AIWeightHumanIssuedCommand < %minWeight)
return 0;
else
%weight = $AIWeightHumanIssuedCommand;
}
else
{
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
if (%weight < $AIWeightHumanIssuedCommand)
%weight = $AIWeightHumanIssuedCommand;
}
}
else
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
return 0;
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
}
return %weight;
}
}
function AIORepairObject::assignClient(%this, %client)
{
%client.objectiveTask = %client.addTask(AIRepairObject);
%client.objectiveTask.initFromObjective(%this, %client);
}
function AIORepairObject::unassignClient(%this, %client)
{
%client.removeTask(%client.objectiveTask);
%client.objectiveTask = "";
}
//------------------------------
function AIOLazeObject::weight(%this, %client, %level, %minWeight, %inventoryStr)
{
//make sure the player is still alive!!!!!
if (! AIClientIsAlive(%client))
return 0;
//see if it's already being lazed
%numTargets = ServerTargetSet.getCount();
for (%i = 0; %i < %numTargets; %i++)
{
%targ = ServerTargetSet.getObject(%i);
if (%targ.sourceObject != %client.player)
{
%targDist = VectorDist(%targ.getTargetPoint(), %this.targetObjectId.getWorldBoxCenter());
if (%targDist < 10)
{
%this.lastLazedTime = getSimTime();
%this.lastLazedClient = %targ.sourceObject.client;
break;
}
}
}
//no need to laze if the object is already destroyed
if (!isObject(%this.targetObjectId) || %this.targetObjectId.getDamageState() $= "Destroyed")
return 0;
else if (%this.targetObjectId.isHidden() || %this.targetObjectId.team != %client.team)
return 0;
else if (getSimTime() - %this.lastLazedTime <= 15000 && %this.lastLazedClient != %client)
return 0;
else
{
//set the base weight
switch (%level)
{
case 1:
%weight = %this.weightLevel1;
case 2:
%weight = %this.weightLevel2;
case 3:
%weight = %this.weightLevel3;
default:
%weight = %this.weightLevel4;
}
//check Affinity
if (ClientHasAffinity(%this, %client))
%weight += 100;
//for now, do not deviate from the current assignment to laze a target, if you don't
//already have a targeting laser.
%needEquipment = AINeedEquipment(%this.equipment, %client);
if (!%needEquipment)
%weight += 100;
else if (!aiHumanHasControl(%client.controlByHuman, %client))
return 0;
//see if this client is close to the issuing client
if (%this.issuedByClientId > 0)
{
if (! AIClientIsAlive(%this.issuedByClientId))
return 0;
%distance = %client.getPathDistance(%this.issuedByClientId.player.getWorldBoxCenter());
if (%distance < 0)
%distance = 32767;
//see if we're within 200 m
if (%distance < 200)
%weight += 30;
//see if we're within 90 m
if (%distance < 90)
%weight += 30;
//see if we're within 45 m
if (%distance < 45)
%weight += 30;
}
//now, if this bot is linked to a human who has issued this command, up the weight
if (%this.issuedByClientId == %client.controlByHuman && %weight < $AIWeightHumanIssuedCommand)
%weight = $AIWeightHumanIssuedCommand;
return %weight;
}
}
function AIOLazeObject::assignClient(%this, %client)
{
%client.objectiveTask = %client.addTask(AILazeObject);
%client.objectiveTask.initFromObjective(%this, %client);
}
function AIOLazeObject::unassignClient(%this, %client)
{
%client.removeTask(%client.objectiveTask);
%client.objectiveTask = "";
}
//------------------------------
function AIOMortarObject::weight(%this, %client, %level, %minWeight, %inventoryStr)
{
// if were playing CnH, check who owns this
if (!isObject(%this.targetObjectId) || %this.targetObjectId.isHidden() || %this.targetObjectId.team == %client.team)
return 0;
//make sure the player is still alive!!!!!
if (! AIClientIsAlive(%client))
return 0;
//no need to attack if the object is already destroyed
if (%this.targetObjectId.getDamageState() $= "Destroyed")
return 0;
else
{
//if this bot is linked to a human who has issued this command, up the weight
if (%this.issuedByClientId == %client.controlByHuman)
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
{
if ($AIWeightHumanIssuedCommand < %minWeight)
return 0;
else
%weight = $AIWeightHumanIssuedCommand;
}
else
{
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
if (%weight < $AIWeightHumanIssuedCommand)
%weight = $AIWeightHumanIssuedCommand;
}
}
else
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
return 0;
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
}
return %weight;
}
}
function AIOMortarObject::assignClient(%this, %client)
{
%client.objectiveTask = %client.addTask(AIMortarObject);
%client.objectiveTask.initFromObjective(%this, %client);
//create the escort objective (require a targeting laser in this case...)
%client.escort = new AIObjective(AIOEscortPlayer)
{
dataBlock = "AIObjectiveMarker";
weightLevel1 = $AIWeightEscortOffense[1];
weightLevel2 = $AIWeightEscortOffense[2];
description = "Escort " @ getTaggedString(%client.name);
targetClientId = %client;
offense = true;
equipment = "TargetingLaser";
buyEquipmentSet = "LightEnergyDefault";
};
MissionCleanup.add(%client.escort);
$ObjectiveQ[%client.team].add(%client.escort);
}
function AIOMortarObject::unassignClient(%this, %client)
{
//kill the escort objective
if (%client.escort)
{
AIClearObjective(%client.escort);
%client.escort.delete();
%client.escort = "";
}
%client.removeTask(%client.objectiveTask);
%client.objectiveTask = "";
}
//------------------------------------------------------------------------
//If the function ShapeBaseImageData::testInvalidDeployConditions() changes at all, those changes need to be reflected here
function AIODeployEquipment::weight(%this, %client, %level, %minWeight, %inventoryStr)
{
//make sure the player is still alive!!!!!
if (! AIClientIsAlive(%client))
return 0;
//make sure the deploy objective is valid
if (%this.isInvalid)
return 0;
//first, make sure we haven't deployed too many...
if (%this.equipment $= "TurretOutdoorDeployable" || %this.equipment $= "TurretIndoorDeployable")
%maxAllowed = countTurretsAllowed(%this.equipment);
else
%maxAllowed = $TeamDeployableMax[%this.equipment];
if ($TeamDeployedCount[%client.team, %this.equipment] >= %maxAllowed)
return 0;
//now make sure there are no other items in the way...
InitContainerRadiusSearch(%this.location, $MinDeployableDistance, $TypeMasks::VehicleObjectType |
$TypeMasks::MoveableObjectType |
$TypeMasks::StaticShapeObjectType |
$TypeMasks::TSStaticShapeObjectType |
$TypeMasks::ForceFieldObjectType |
$TypeMasks::ItemObjectType |
$TypeMasks::PlayerObjectType |
$TypeMasks::TurretObjectType);
%objSearch = containerSearchNext();
//make sure we're not invalidating the deploy location with the client's own player object
if (%objSearch == %client.player)
%objSearch = containerSearchNext();
//did we find an object which would block deploying the equipment?
if (isObject(%objSearch))
return 0;
//now run individual checks based on the equipment type...
if (%this.equipment $= "TurretIndoorDeployable")
{
//check if there's another turret close to the deploy location
InitContainerRadiusSearch(%this.location, $TurretIndoorSpaceRadius, $TypeMasks::StaticShapeObjectType);
%found = containerSearchNext();
if (isObject(%found))
{
%foundName = %found.getDataBlock().getName();
if ((%foundName $= TurretDeployedFloorIndoor) || (%foundName $= "TurretDeployedWallIndoor") || (%foundName $= "TurretDeployedCeilingIndoor") || (%foundName $= "TurretDeployedOutdoor"))
return 0;
}
//now see if there are too many turrets in the area...
%highestDensity = 0;
InitContainerRadiusSearch(%this.location, $TurretIndoorSphereRadius, $TypeMasks::StaticShapeObjectType);
%found = containerSearchNext();
while (isObject(%found))
{
%foundName = %found.getDataBlock().getName();
if ((%foundName $= "TurretDeployedFloorIndoor") || (%foundName $= "TurretDeployedWallIndoor") || (%foundName $= "TurretDeployedCeilingIndoor") || (%foundName $= "TurretDeployedOutdoor"))
{
//found one
%numTurretsNearby++;
%nearbyDensity = testNearbyDensity(%found, $TurretIndoorSphereRadius);
if (%nearbyDensity > %highestDensity)
%highestDensity = %nearbyDensity;
}
%found = containerSearchNext();
}
if (%numTurretsNearby > %highestDensity)
%highestDensity = %numTurretsNearby;
//now see if the area is already saturated
if (%highestDensity > $TurretIndoorMaxPerSphere)
return 0;
}
else if (%this.equipment $= "TurretOutdoorDeployable")
{
//check if there's another turret close to the deploy location
InitContainerRadiusSearch(%this.location, $TurretOutdoorSpaceRadius, $TypeMasks::StaticShapeObjectType);
%found = containerSearchNext();
if (isObject(%found))
{
%foundName = %found.getDataBlock().getName();
if ((%foundName $= "TurretDeployedFloorIndoor") || (%foundName $= "TurretDeployedWallIndoor") || (%foundName $= "TurretDeployedCeilingIndoor") || (%foundName $= "TurretDeployedOutdoor"))
return 0;
}
//now see if there are too many turrets in the area...
%highestDensity = 0;
InitContainerRadiusSearch(%this.location, $TurretOutdoorSphereRadius, $TypeMasks::StaticShapeObjectType);
%found = containerSearchNext();
while (isObject(%found))
{
%foundName = %found.getDataBlock().getName();
if ((%foundName $= "TurretDeployedFloorIndoor") || (%foundName $= "TurretDeployedWallIndoor") || (%foundName $= "TurretDeployedCeilingIndoor") || (%foundName $= "TurretDeployedOutdoor"))
{
//found one
%numTurretsNearby++;
%nearbyDensity = testNearbyDensity(%found, $TurretOutdoorSphereRadius);
if (%nearbyDensity > %highestDensity)
%highestDensity = %nearbyDensity;
}
%found = containerSearchNext();
}
if (%numTurretsNearby > %highestDensity)
%highestDensity = %numTurretsNearby;
//now see if the area is already saturated
if (%highestDensity > $TurretOutdoorMaxPerSphere)
return 0;
}
//check equipment requirement
%needEquipment = AINeedEquipment(%this.equipment, %client);
//if don't need equipment, see if we've past the "point of no return", and should continue regardless
if (! %needEquipment)
{
%needArmor = AIMustUseRegularInvStation(%this.equipment, %client);
%result = AIFindClosestInventory(%client, %needArmor);
%closestInv = getWord(%result, 0);
%closestDist = getWord(%result, 1);
//if we're too far from the inv to go back, or we're too close to the deploy location, force continue
if (%closestDist > 50 && VectorDist(%client.player.getWorldBoxCenter(), %task.location) < 50)
{
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
if (%weight < $AIWeightContinueDeploying)
%weight = $AIWeightContinueDeploying;
return %weight;
}
}
//if this bot is linked to a human who has issued this command, up the weight
if (%this.issuedByClientId == %client.controlByHuman)
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
{
if ($AIWeightHumanIssuedCommand < %minWeight)
return 0;
else
%weight = $AIWeightHumanIssuedCommand;
}
else
{
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
if (%weight < $AIWeightHumanIssuedCommand)
%weight = $AIWeightHumanIssuedCommand;
}
}
else
{
//make sure we have the potential to reach the minWeight
if (!AIODefault::QuickWeight(%this, %client, %level, %minWeight))
return 0;
// calculate the default...
%weight = AIODefault::weight(%this, %client, %level, %inventoryStr);
}
return %weight;
}
function AIODeployEquipment::assignClient(%this, %client)
{
%client.objectiveTask = %client.addTask(AIDeployEquipment);
%task = %client.objectiveTask;
%task.initFromObjective(%this, %client);
}
function AIODeployEquipment::unassignClient(%this, %client)
{
%client.removeTask(%client.objectiveTask);
%client.objectiveTask = "";
}
//------------------------------------------------------------------------