Initial attempts at getting bots unstuck on broken paths; AI visual acuity is now the primary system of picking targets, improving performance

This commit is contained in:
Robert MacGregor 2015-10-07 03:16:32 -04:00
parent 657545aaac
commit ec3b86cdf6
6 changed files with 260 additions and 103 deletions

View file

@ -34,7 +34,6 @@ function AICommander::setup(%this)
for (%iteration = 0; %iteration < ClientGroup.getCount(); %iteration++) for (%iteration = 0; %iteration < ClientGroup.getCount(); %iteration++)
{ {
%currentClient = ClientGroup.getObject(%iteration); %currentClient = ClientGroup.getObject(%iteration);
%currentClient.updateVisualAcuity();
if (%currentClient.isAIControlled() && %currentClient.team == %this.team) if (%currentClient.isAIControlled() && %currentClient.team == %this.team)
{ {
@ -42,6 +41,11 @@ function AICommander::setup(%this)
%this.idleBotList.add(%currentClient); %this.idleBotList.add(%currentClient);
%currentClient.commander = %this; %currentClient.commander = %this;
%currentClient.initialize();
%currentClient.visibleHostiles = new SimSet();
%currentClient.updateVisualAcuity();
%currentClient.stuckCheck();
} }
} }
@ -74,9 +78,7 @@ function AICommander::_skimObjectiveGroup(%this, %group)
case "AIODefendLocation": case "AIODefendLocation":
// FIXME: Console spam from .targetObjectID not being set? // FIXME: Console spam from .targetObjectID not being set?
%datablockName = %current.targetObjectID.getDatablock().getName(); %datablockName = %current.targetObjectID.getDatablock().getName();
echo(%datablockName);
// Defending the flag? // Defending the flag?
if (%datablockName $= "FLAG") if (%datablockName $= "FLAG")
%this.objectiveCycles[$DXAI::Priorities::DefendFlag].add(%current); %this.objectiveCycles[$DXAI::Priorities::DefendFlag].add(%current);
@ -243,14 +245,24 @@ function AICommander::assignTask(%this, %taskID, %bot)
%objective = %this.objectiveCycles[%taskID].next(); %objective = %this.objectiveCycles[%taskID].next();
// Set the bot to defend the location // Set the bot to defend the location
%bot.defendLocation = %objective.location; %bot.defendTargetLocation = %objective.location;
%datablockName = %objective.targetObjectID.getDatablock().getName();
switch$(%datablockName)
{
case "FLAG":
%bot.defenseDescription = "flag";
case "GeneratorLarge":
%bot.defenseDescription = "generator";
}
%bot.addTask("AIEnhancedDefendLocation"); %bot.addTask("AIEnhancedDefendLocation");
case $DXAI::Priorities::ScoutBase: case $DXAI::Priorities::ScoutBase:
%objective = %this.objectiveCycles[%taskID].next(); %objective = %this.objectiveCycles[%taskID].next();
// Set the bot to defend the location // Set the bot to defend the location
%bot.scoutLocation = %objective.location; %bot.scoutTargetLocation = %objective.location;
%bot.scoutDistance = %objective.distance; %bot.scoutDistance = %objective.distance;
%bot.addTask("AIEnhancedScoutLocation"); %bot.addTask("AIEnhancedScoutLocation");
} }
@ -267,6 +279,13 @@ function AICommander::setDefaultPriorities(%this)
function AICommander::cleanUp(%this) function AICommander::cleanUp(%this)
{ {
for (%iteration = 0; %iteration < %this.botList.getCount(); %iteration++)
{
%current = %this.botList.getObject(%iteration);
cancel(%current.visualAcuityTick);
cancel(%current.stuckCheckTick);
}
%this.botList.delete(); %this.botList.delete();
%this.idleBotList.delete(); %this.idleBotList.delete();
} }

View file

@ -9,15 +9,10 @@
// Refer to LICENSE.txt for more information. // Refer to LICENSE.txt for more information.
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
function AIConnection::initialize(%this, %aiClient) function AIConnection::initialize(%this)
{ {
%this.fieldOfView = 3.14 / 2; // 90* View cone %this.fieldOfView = 3.14 / 2; // 90* View cone
%this.viewDistance = 300; %this.viewDistance = 300;
if (!isObject(%aiClient))
error("AIPlayer: Attempted to initialize with bad AI client connection!");
%this.client = %aiClient;
} }
function AIConnection::update(%this) function AIConnection::update(%this)
@ -77,6 +72,9 @@ function AIConnection::setMoveTarget(%this, %position)
%this.isFollowingTarget = false; %this.isFollowingTarget = false;
%this.setPath(%position); %this.setPath(%position);
%this.stepMove(%position); %this.stepMove(%position);
%this.minimumPathDistance = 9999;
%this.maximumPathDistance = -9999;
} }
function AIConnection::setFollowTarget(%this, %target, %minDistance, %maxDistance, %hostile) function AIConnection::setFollowTarget(%this, %target, %minDistance, %maxDistance, %hostile)
@ -97,14 +95,72 @@ function AIConnection::setFollowTarget(%this, %target, %minDistance, %maxDistanc
%this.stepEscort(%target); %this.stepEscort(%target);
} }
function AIConnection::stuckCheck(%this)
{
if (isEventPending(%this.stuckCheckTick))
cancel(%this.stuckCheckTick);
%targetDistance = %this.pathDistRemaining(9000);
if (!%this.isMovingToTarget || !isObject(%this.player) || %this.player.getState() !$= "Move" || %targetDistance <= 5)
{
%this.stuckCheckTick = %this.schedule(5000, "stuckCheck");
return;
}
if (!%this.isPathCorrecting && %targetDistance >= %this.minimumPathDistance && %this.minimumPathDistance != 9999)
%this.isPathCorrecting = true;
if (%targetDistance > %this.maximumPathDistance)
%this.maximumPathDistance = %targetDistance;
if (%targetDistance < %this.minimumPathDistance)
%this.minimumPathDistance = %targetDistance;
%this.stuckCheckTick = %this.schedule(5000, "stuckCheck");
}
function AIConnection::updateLegs(%this) function AIConnection::updateLegs(%this)
{ {
%now = getSimTime();
%delta = %now - %this.lastUpdateLegs;
%this.lastUpdateLegs = %now;
if (%this.isMovingToTarget) if (%this.isMovingToTarget)
{ {
if (%this.aimAtLocation) if (%this.aimAtLocation)
%this.aimAt(%this.moveTarget); %this.aimAt(%this.moveTarget);
else if(%this.manualAim) else if(%this.manualAim)
%this.aimAt(%this.moveTarget); %this.aimAt(%this.moveTarget);
%targetDistance = %this.pathDistRemaining(9000);
if (%targetDistance > %this.maximumPathDistance)
%this.maximumPathDistance = %targetDistance;
if (%targetDistance < %this.minimumPathDistance)
%this.minimumPathDistance = %targetDistance;
// Bots follow a set of lines drawn between nodes to slowly decrement the path distance,
// so bots that are stuck usually get their remaining distance stuck in some range of
// arbitrary values, so we monitor the minimum and maximum values over a period of 5 seconds
// Test...
%pathDistance = %this.getPathDistance(%this.moveTarget);
if(%pathDistance > 10 && %this.moveTravelTime < 10000)
%this.moveTravelTime += %delta;
else if (%pathDistance < 10)
%this.moveTravelTime = 0;
else if (%this.moveTravelTime >= 10000)
{
// We appear to be stuck, so pick a random nearby node and try to run to it
%this.moveTravelTime = 0;
%this.isPathCorrecting = true;
if (isObject(NavGraph))
{
%randomNode = NavGraph.randNode(%this.player.getPosition(), 200, true, true);
if (%randomNode != -1)
%this.setMoveTarget(NavGraph.nodeLoc(%randomNode));
}
}
} }
else if (%this.isFollowingTarget) else if (%this.isFollowingTarget)
{ {
@ -119,7 +175,24 @@ function AIConnection::updateLegs(%this)
function AIConnection::updateWeapons(%this) function AIConnection::updateWeapons(%this)
{ {
if (isObject(%this.engageTarget))
{
%player = %this.player;
%targetDistance = vectorDist(%player.getPosition(), %this.engageTarget.getPosition());
// Firstly, just aim at them for now
%this.aimAt(%this.engageTarget.getWorldBoxCenter());
// What is our current best weapon? Right now we just check target distance and weapon spread.
%bestWeapon = 0;
for (%iteration = 0; %iteration < %player.weaponSlotCount; %iteration++)
{
// Weapons with a decent bit of spread should be used <= 20m
}
%player.selectWeaponSlot(%bestWeapon);
}
} }
function AIConnection::updateVisualAcuity(%this) function AIConnection::updateVisualAcuity(%this)
@ -127,7 +200,7 @@ function AIConnection::updateVisualAcuity(%this)
if (isEventPending(%this.visualAcuityTick)) if (isEventPending(%this.visualAcuityTick))
cancel(%this.visualAcuityTick); cancel(%this.visualAcuityTick);
if (!isObject(%this.player) || %this.player.getState() !$= "Move") if (%this.visibleDistance = 0 || !isObject(%this.player) || %this.player.getState() !$= "Move")
{ {
%this.visualAcuityTick = %this.schedule(getRandom(230, 400), "updateVisualAcuity"); %this.visualAcuityTick = %this.schedule(getRandom(230, 400), "updateVisualAcuity");
return; return;
@ -167,24 +240,26 @@ function AIConnection::updateVisualAcuity(%this)
%this.upperMarker.delete(); %this.upperMarker.delete();
%this.lowerMarker.delete(); %this.lowerMarker.delete();
} }
%now = getSimTime();
%deltaTime = %now - %this.lastVisualAcuityUpdate;
%this.lastVisualAcuityUpdate = %now;
%result = %this.getObjectsInViewcone($TypeMasks::ProjectileObjectType | $TypeMasks::PlayerObjectType, %this.viewDistance, true); %visibleObjects = %this.getObjectsInViewcone($TypeMasks::ProjectileObjectType | $TypeMasks::PlayerObjectType, %this.viewDistance, true);
// What can we see? for (%iteration = 0; %iteration < %visibleObjects.getCount(); %iteration++)
for (%i = 0; %i < %result.getCount(); %i++)
{ {
%current = %result.getObject(%i); %current = %visibleObjects.getObject(%iteration);
%this.awarenessTicks[%current]++;
%this.awarenessTime[%current] += %deltaTime;
// Did we "notice" the object yet?
%noticeTime = getRandom(700, 1200);
if (%this.awarenessTime[%current] < %noticeTime)
continue;
if (%current.getType() & $TypeMasks::ProjectileObjectType) if (%current.getType() & $TypeMasks::ProjectileObjectType)
{ {
// Did we "notice" the object yet?
// We pick a random notice time between 700ms and 1200 ms
// Obviously this timer runs on a 32ms tick, but it should help provide a little unpredictability
%noticeTime = getRandom(700, 1200);
if (%this.awarenessTicks[%current] < (%noticeTime / 32))
continue;
%className = %current.getClassName(); %className = %current.getClassName();
// LinearFlareProjectile and LinearProjectile have linear trajectories, so we can easily determine if a dodge is necessary // LinearFlareProjectile and LinearProjectile have linear trajectories, so we can easily determine if a dodge is necessary
@ -223,26 +298,43 @@ function AIConnection::updateVisualAcuity(%this)
} }
} }
// See a player? // See a player?
else if (%current.getType() & $TypeMasks::PlayerObjectType) else if (%current.getType() & $TypeMasks::PlayerObjectType && %current.client.team != %this.team)
{ {
%this.clientDetected(%current); %this.visibleHostiles.add(%current);
%this.clientDetected(%current.client); //%this.clientDetected(%current);
// %this.clientDetected(%current.client);
// ... if the moron is right there in our LOS then we probably should see them // ... if the moron is right there in our LOS then we probably should see them
%start = %this.player.getPosition(); // %start = %this.player.getPosition();
%end = vectorAdd(%start, vectorScale(%this.player.getEyeVector(), %this.viewDistance)); // %end = vectorAdd(%start, vectorScale(%this.player.getEyeVector(), %this.viewDistance));
%rayCast = containerRayCast(%start, %end, -1, %this.player); // %rayCast = containerRayCast(%start, %end, -1, %this.player);
%hitObject = getWord(%raycast, 0); // %hitObject = getWord(%raycast, 0);
if (%hitObject == %current) // if (%hitObject == %current)
{ // {
%this.clientDetected(%current); // %this.clientDetected(%current);
%this.stepEngage(%current); // %this.stepEngage(%current);
} // }
} }
} }
%result.delete(); // Now we run some logic on some things that we no longer can see.
%this.visualAcuityTick = %this.schedule(getRandom(230, 400), "updateVisualAcuity"); for (%iteration = 0; %iteration < %this.visibleHostiles.getCount(); %iteration++)
{
%current = %this.visibleHostiles.getObject(%iteration);
if (%this.visibleHostiles.isMember(%current) && !%visibleObjects.isMember(%current))
{
%this.awarenessTime[%current] -= %deltaTime;
if (%this.awarenessTime[%current] < 200)
{
%this.visibleHostiles.remove(%current);
continue;
}
}
}
%visibleObjects.delete();
%this.visualAcuityTick = %this.schedule(getRandom($DXAI::Bot::MinimumVisualAcuityTime, $DXAI::Bot::MaximumVisualAcuityTime), "updateVisualAcuity");
} }

View file

@ -13,3 +13,6 @@ $DXAI::Commander::minimumGeneratorDefense = 1;
$DXAI::Bot::DefaultFieldOfView = 3.14159 / 2; // 90* $DXAI::Bot::DefaultFieldOfView = 3.14159 / 2; // 90*
$DXAI::Bot::DefaultViewDistance = 300; $DXAI::Bot::DefaultViewDistance = 300;
$DXAI::Bot::MinimumVisualAcuityTime = 200;
$DXAI::Bot::MaximumVisualAcuityTime = 400;

View file

@ -188,7 +188,7 @@ function GameConnection::getObjectsInViewcone(%this, %typeMask, %distance, %perf
%result.add(%currentObject); %result.add(%currentObject);
else else
{ {
%rayCast = containerRayCast(%coneOrigin, %currentObject.getWorldBoxCenter(), -1, 0); %rayCast = containerRayCast(%coneOrigin, %currentObject.getWorldBoxCenter(), $TypeMasks::AllObjectType, %this.player);
%hitObject = getWord(%raycast, 0); %hitObject = getWord(%raycast, 0);
@ -224,6 +224,16 @@ function vectorMultiply(%vec1, %vec2)
(getWord(%vec1, 2) * getWord(%vec2, 2)); (getWord(%vec1, 2) * getWord(%vec2, 2));
} }
function listStuckBots()
{
for (%iteration = 0; %iteration < ClientGroup.getCount(); %iteration++)
{
%client = ClientGroup.getObject(%iteration);
if (%client.isAIControlled() && %client.isPathCorrecting)
error(%client);
}
}
// If the map editor was instantiated, this will prevent a little bit // If the map editor was instantiated, this will prevent a little bit
// of console warnings // of console warnings
function Terraformer::getType(%this) { return 0; } function Terraformer::getType(%this) { return 0; }

View file

@ -245,6 +245,9 @@ package DXAI_Hooks
%client.shouldRearm = true; %client.shouldRearm = true;
%client.targetLoadout = 1; %client.targetLoadout = 1;
%client.engageTargetLastPosition = "";
%client.engageTarget = -1;
return 11595; return 11595;
} }
@ -270,10 +273,26 @@ package DXAI_Hooks
//switch$ (%eventTag) //switch$ (%eventTag)
//{ //{
schedule(250, %targetClient, "AIPlayAnimSound", %targetClient, %clientPos, "cmd.decline", $AIAnimSalute, $AIAnimSalute, 0); schedule(250, %targetClient, "AIPlayAnimSound", %targetClient, %clientPos, "cmd.decline", $AIAnimSalute, $AIAnimSalute, 0);
schedule(2000, %targetClient, "AIPlayAnimSound", %targetClient, %clientPos, ObjectiveNameToVoice(%targetClient.getTaskName()), $AIAnimSalute, $AIAnimSalute, 0); schedule(2000, %targetClient, "AIPlayAnimSound", %targetClient, %clientPos, ObjectiveNameToVoice(%targetClient), $AIAnimSalute, $AIAnimSalute, 0);
schedule(3700, %targetClient, "AIPlayAnimSound", %targetClient, %clientPos, "vqk.sorry", $AIAnimSalute, $AIAnimSalute, 0); schedule(3700, %targetClient, "AIPlayAnimSound", %targetClient, %clientPos, "vqk.sorry", $AIAnimSalute, $AIAnimSalute, 0);
} }
function AISystemEnabled(%enabled)
{
parent::AISystemEnabled(%enabled);
echo(%enabled);
$DXAI::AISystemEnabled = %enabled;
}
function AIConnection::onAIDrop(%client)
{
parent::onAIDrop(%client);
if (isObject(%client.visibleHostiles))
%client.visibleHostiles.delete();
}
function Station::stationTriggered(%data, %obj, %isTriggered) function Station::stationTriggered(%data, %obj, %isTriggered)
{ {
parent::stationTriggered(%data, %obj, %isTriggered); parent::stationTriggered(%data, %obj, %isTriggered);

View file

@ -20,7 +20,8 @@ $DXAI::Task::NoPriority = 0;
$DXAI::Task::LowPriority = 100; $DXAI::Task::LowPriority = 100;
$DXAI::Task::MediumPriority = 200; $DXAI::Task::MediumPriority = 200;
$DXAI::Task::HighPriority = 500; $DXAI::Task::HighPriority = 500;
$DXAI::Task::VeryHighPriority = 1000; $DXAI::Task::VeryHighPriority = 1000;
$DXAI::Task::ReservedPriority = 5000;
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
// +Param %bot.escortTarget: The ID of the object to escort. This can be literally // +Param %bot.escortTarget: The ID of the object to escort. This can be literally
@ -119,7 +120,10 @@ function AIEnhancedScoutLocation::retire(%task, %client) { }
function AIEnhancedScoutLocation::weight(%task, %client) { %task.setWeight($DXAI::Task::MediumPriority); } function AIEnhancedScoutLocation::weight(%task, %client) { %task.setWeight($DXAI::Task::MediumPriority); }
function AIEnhancedScoutLocation::monitor(%task, %client) function AIEnhancedScoutLocation::monitor(%task, %client)
{ {
if (%client.engageTarget)
return AIEnhancedScoutLocation::monitorEngage(%task, %client);
// We can't really work without a NavGraph // We can't really work without a NavGraph
if (!isObject(NavGraph)) if (!isObject(NavGraph))
return; return;
@ -127,7 +131,7 @@ function AIEnhancedScoutLocation::monitor(%task, %client)
// We just received the task, so find a node within distance of our scout location // We just received the task, so find a node within distance of our scout location
if (%client.currentNode == -1) if (%client.currentNode == -1)
{ {
%client.currentNode = NavGraph.randNode(%client.scoutLocation, %client.scoutDistance, true, true); %client.currentNode = NavGraph.randNode(%client.scoutTargetLocation, %client.scoutDistance, true, true);
if (%client.currentNode != -1) if (%client.currentNode != -1)
%client.setMoveTarget(NavGraph.nodeLoc(%client.currentNode)); %client.setMoveTarget(NavGraph.nodeLoc(%client.currentNode));
@ -138,7 +142,7 @@ function AIEnhancedScoutLocation::monitor(%task, %client)
%pathDistance = %client.getPathDistance(%client.moveTarget); %pathDistance = %client.getPathDistance(%client.moveTarget);
// Don't move if we're close enough to our next node // Don't move if we're close enough to our next node
if (%pathDistance <= 40 && %client.isMoving) if (%pathDistance <= 40 && %client.isMovingToTarget)
{ {
%client.setMoveTarget(-1); %client.setMoveTarget(-1);
%client.nextScoutRotation = getRandom(5000, 10000); %client.nextScoutRotation = getRandom(5000, 10000);
@ -159,7 +163,7 @@ function AIEnhancedScoutLocation::monitor(%task, %client)
%client.nextScoutRotation = getRandom(5000, 10000); %client.nextScoutRotation = getRandom(5000, 10000);
// Pick a new node // Pick a new node
%client.currentNode = NavGraph.randNode(%client.scoutLocation, %client.scoutDistance, true, true); %client.currentNode = NavGraph.randNode(%client.scoutTargetLocation, %client.scoutDistance, true, true);
// Ensure that we found a node. // Ensure that we found a node.
if (%client.currentNode != -1) if (%client.currentNode != -1)
@ -167,6 +171,11 @@ function AIEnhancedScoutLocation::monitor(%task, %client)
} }
} }
} }
function AIEnhancedScoutLocation::monitorEngage(%task, %client)
{
}
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
@ -182,40 +191,24 @@ function AIEnhancedEngageTarget::retire(%task, %client) { }
function AIEnhancedEngageTarget::weight(%task, %client) function AIEnhancedEngageTarget::weight(%task, %client)
{ {
if (!isObject(%client.engageTarget)) // Blow through seen targets
%chosenTarget = -1;
%chosenTargetDistance = 9999;
%botPosition = %client.player.getPosition();
for (%iteration = 0; %iteration < %client.visibleHostiles.getCount(); %iteration++)
{ {
%visibleObjects = %client.getObjectsInViewcone($TypeMasks::PlayerObjectType, %client.viewDistance, true); %current = %client.visibleHostiles.getObject(%iteration);
// Choose the closest target %targetDistance = vectorDist(%current.getPosition(), %botPosition);
// TODO: Choose on more advanced metrics like HP if (%targetDistance < %chosenTargetDistance)
%chosenTarget = -1;
%chosenTargetDistance = 9999;
for (%iteration = 0; %iteration < %visibleObjects.getCount(); %iteration++)
{ {
%potentialTarget = %visibleObjects.getObject(%iteration); %chosenTargetDistance = %targetDistance;
%chosenTarget = %current;
%potentialTargetDistance = vectorDist(%potentialTarget.getPosition(), %client.player.getPosition());
if (%potentialTarget.client.team != %client.team && %potentialTargetDistance < %chosenTargetDistance)
{
%chosenTargetDistance = %potentialTargetDistance;
%chosenTarget = %potentialTarget;
}
} }
%visibleObjects.delete();
%client.engageTarget = %chosenTarget;
} }
else
{ %client.engageTarget = %chosenTarget;
// Can we still see them?
%rayCast = containerRayCast(%client.player.getWorldBoxCenter(), %client.engageTarget.getWorldBoxCenter(), -1, %client.player);
%hitObject = getWord(%raycast, 0);
// TODO: Go to the last known position.
if (%hitObject != %client.engageTarget)
%client.engageTarget = -1;
}
if (!isObject(%client.engageTarget) && %client.engageTargetLastPosition $= "") if (!isObject(%client.engageTarget) && %client.engageTargetLastPosition $= "")
%task.setWeight($DXAI::Task::NoPriority); %task.setWeight($DXAI::Task::NoPriority);
else else
@ -225,26 +218,16 @@ function AIEnhancedEngageTarget::weight(%task, %client)
function AIEnhancedEngageTarget::monitor(%task, %client) function AIEnhancedEngageTarget::monitor(%task, %client)
{ {
if (isObject(%client.engageTarget)) if (isObject(%client.engageTarget))
{ {
%player = %client.player; if (%client.engageTarget.getState() !$= "Move")
%targetDistance = vectorDist(%player.getPosition(), %client.engageTarget.getPosition());
// Firstly, just aim at them for now
%client.aimAt(%client.engageTarget.getWorldBoxCenter());
// What is our current best weapon? Right now we just check target distance and weapon spread.
%bestWeapon = 0;
for (%iteration = 0; %iteration < %player.weaponSlotCount; %iteration++)
{ {
// Weapons with a decent bit of spread should be used <= 20m %client.engageTarget = -1;
%client.engageTargetLastPosition = "";
return;
} }
%player.selectWeaponSlot(%bestWeapon); %client.engageTargetLastPosition = %client.engageTarget.getWorldBoxCenter();
%client.engageTargetLastPosition = %client.engageTarget.getWorldBoxCenter(); %client.setMoveTarget(getRandomPositionOnTerrain(%client.engageTargetLastPosition, 40));
%client.setMoveTarget(getRandomPositionOnTerrain(%client.engageTargetLastPosition, 40));
%client.pressFire(); %client.pressFire();
} }
else if (%client.engageTargetLastPosition !$= "") else if (%client.engageTargetLastPosition !$= "")
@ -258,6 +241,7 @@ function AIEnhancedEngageTarget::monitor(%task, %client)
} }
} }
} }
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
@ -275,6 +259,8 @@ function AIEnhancedRearmTask::weight(%task, %client)
%task.setWeight($DXAI::Task::HighPriority); %task.setWeight($DXAI::Task::HighPriority);
else else
%task.setWeight($DXAI::Task::NoPriority); %task.setWeight($DXAI::Task::NoPriority);
%task.setMonitorFreq(getRandom(10, 32));
} }
function AIEnhancedRearmTask::monitor(%task, %client) function AIEnhancedRearmTask::monitor(%task, %client)
@ -322,26 +308,44 @@ function AIEnhancedReturnFlagTask::monitor(%task, %client)
{ {
if (!isObject(%client.returnFlagTarget)) if (!isObject(%client.returnFlagTarget))
return; return;
%client.setMoveTarget(%client.returnFlagTarget.getPosition()); if (isObject(%client.engageTarget) && %client.engageTarget.getState() $= "Move")
AIEnhancedReturnFlagTask::monitorEngage(%task, %client);
else
%client.setMoveTarget(%client.returnFlagTarget.getPosition());
} }
function AIEnhancedReturnFlagTask::monitorEngage(%task, %client)
{
}
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
// Description: A task that performs path correction. // Description: A task that performs path correction.
//------------------------------------------------------------------------------------------` //------------------------------------------------------------------------------------------`
function AIEnhancedPathCorrectionTask::initFromObjective(%task, %objective, %client) { } function AIEnhancedPathCorrectionTask::initFromObjective(%task, %objective, %client) { }
function AIEnhancedPathCorrectionTask::assume(%task, %client) { %task.setMonitorFreq(32); } function AIEnhancedPathCorrectionTask::assume(%task, %client) { %task.setMonitorFreq(2); }
function AIEnhancedPathCorrectionTask::retire(%task, %client) { } function AIEnhancedPathCorrectionTask::retire(%task, %client) { }
function AIEnhancedPathCorrectionTask::weight(%task, %client) function AIEnhancedPathCorrectionTask::weight(%task, %client)
{ {
%task.setWeight(0); if (%client.isPathCorrecting)
%task.setWeight($DXAI::Task::VeryHighPriority);
else
%task.setWeight($DXAI::Task::NoPriority);
} }
function AIEnhancedPathCorrectionTask::monitor(%task, %client) function AIEnhancedPathCorrectionTask::monitor(%task, %client)
{ {
if (%client.isPathCorrecting)
{
if (%client.player.getEnergyPercent() >= 1)
%client.isPathCorrecting = false;
else
%client.setMoveTarget(-1);
}
} }
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
@ -383,8 +387,10 @@ function AIEnhancedFlagCaptureTask::monitor(%task, %client)
} }
//------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------
function ObjectiveNameToVoice(%objective) function ObjectiveNameToVoice(%bot)
{ {
%objective = %bot.getTaskName();
%result = "avo.grunt"; %result = "avo.grunt";
switch$(%objective) switch$(%objective)
{ {
@ -397,7 +403,15 @@ function ObjectiveNameToVoice(%objective)
case "AIEnhancedScoutLocation": case "AIEnhancedScoutLocation":
%result = "slf.def.defend"; %result = "slf.def.defend";
case "AIEnhancedDefendLocation": case "AIEnhancedDefendLocation":
%result = "slf.def.defend"; switch$(%bot.defenseDescription)
{
case "flag":
%result = "slf.def.flag";
case "generator":
%result = "slf.def.generator";
default:
%result = "slf.def.defend";
}
case "AIEnhancedEscort": case "AIEnhancedEscort":
%result = "slf.tsk.cover"; %result = "slf.tsk.cover";
} }