mirror of
https://github.com/Ragora/T2-DXAI.git
synced 2026-07-15 18:04:34 +00:00
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:
parent
657545aaac
commit
ec3b86cdf6
6 changed files with 260 additions and 103 deletions
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue