mirror of
https://github.com/Ragora/T2-DXAI.git
synced 2026-01-19 18:14:45 +00:00
Added weapon pre-profiler code
This commit is contained in:
parent
167137f755
commit
1ab65e9e70
|
|
@ -15,6 +15,7 @@
|
||||||
//------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------
|
||||||
function AIConnection::initialize(%this)
|
function AIConnection::initialize(%this)
|
||||||
{
|
{
|
||||||
|
%this.dangerObjects = new SimSet();
|
||||||
%this.fieldOfView = $DXAI::Bot::DefaultFieldOfView;
|
%this.fieldOfView = $DXAI::Bot::DefaultFieldOfView;
|
||||||
%this.viewDistance = $DXAI::Bot::DefaultViewDistance;
|
%this.viewDistance = $DXAI::Bot::DefaultViewDistance;
|
||||||
}
|
}
|
||||||
|
|
@ -197,6 +198,10 @@ function AIConnection::updateLegs(%this)
|
||||||
%delta = %now - %this.lastUpdateLegs;
|
%delta = %now - %this.lastUpdateLegs;
|
||||||
%this.lastUpdateLegs = %now;
|
%this.lastUpdateLegs = %now;
|
||||||
|
|
||||||
|
// Set any danger we may need.
|
||||||
|
for (%iteration = 0; %iteration < %this.dangerObjects.getCount(); %iteration++)
|
||||||
|
%this.setDangerLocation(%this.dangerObjects.getObject(%iteration).getPosition(), 3);
|
||||||
|
|
||||||
if (%this.isMovingToTarget)
|
if (%this.isMovingToTarget)
|
||||||
{
|
{
|
||||||
if (%this.aimAtLocation)
|
if (%this.aimAtLocation)
|
||||||
|
|
@ -225,23 +230,52 @@ function AIConnection::updateLegs(%this)
|
||||||
//------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------
|
||||||
function AIConnection::updateWeapons(%this)
|
function AIConnection::updateWeapons(%this)
|
||||||
{
|
{
|
||||||
|
%lockedObject = %this.player;
|
||||||
|
%mount = %this.player.getObjectMount();
|
||||||
|
|
||||||
|
if (isObject(%mount))
|
||||||
|
%lockedObject = %mount;
|
||||||
|
|
||||||
|
// FIXME: Toss %this.player.lockedCount grenades, this will toss all of them basically instantly.
|
||||||
|
if (%lockedObject.isLocked() && %this.player.invFlareGrenade != 0)
|
||||||
|
{
|
||||||
|
%this.pressGrenade();
|
||||||
|
}
|
||||||
|
|
||||||
if (isObject(%this.engageTarget))
|
if (isObject(%this.engageTarget))
|
||||||
{
|
{
|
||||||
%player = %this.player;
|
%player = %this.player;
|
||||||
%targetDistance = vectorDist(%player.getPosition(), %this.engageTarget.getPosition());
|
%targetDistance = vectorDist(%player.getPosition(), %this.engageTarget.getPosition());
|
||||||
|
|
||||||
// Firstly, just aim at them for now
|
// Firstly, just aim at them for now
|
||||||
%this.aimAt(%this.engageTarget.getWorldBoxCenter());
|
%this.aimAt(%this.engageTarget.getPosition());
|
||||||
|
|
||||||
// What is our current best weapon? Right now we just check target distance and weapon spread.
|
// What is our current best weapon? Right now we just check target distance and weapon spread.
|
||||||
%bestWeapon = 0;
|
%bestWeapon = 0;
|
||||||
|
|
||||||
for (%iteration = 0; %iteration < %player.weaponSlotCount; %iteration++)
|
for (%iteration = 0; %iteration < %player.weaponSlotCount; %iteration++)
|
||||||
{
|
{
|
||||||
|
%currentWeapon = %player.weaponSlot[%iteration];
|
||||||
|
%currentWeaponImage = %currentWeapon.image;
|
||||||
|
|
||||||
|
// No ammo?
|
||||||
|
if (isObject(%currentWeaponImage.ammo) && %this.player.inv[%currentWeaponImage.ammo] <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (%currentWeaponImage.projectileSpread >= 3 && %targetDistance <= 20)
|
||||||
|
%bestWeapon = %iteration;
|
||||||
|
else if (%currentWeaponImage.projectileSpread < 3 && %targetDistance >= 20)
|
||||||
|
%bestWeapon = %iteration;
|
||||||
|
else if (%targetDistance >= 100 && %currentWeaponImage.projectileType $= "GrenadeProjectile")
|
||||||
|
%bestWeapon = %iteration;
|
||||||
|
|
||||||
// Weapons with a decent bit of spread should be used <= 20m
|
// Weapons with a decent bit of spread should be used <= 20m
|
||||||
|
// Arced & precision Weapons should be used at >= 100m
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
%player.selectWeaponSlot(%bestWeapon);
|
%player.selectWeaponSlot(%bestWeapon);
|
||||||
|
%this.pressFire(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,7 +300,7 @@ function AIConnection::updateVisualAcuity(%this)
|
||||||
// If we can't even see or if we're downright dead, don't do anything.
|
// If we can't even see or if we're downright dead, don't do anything.
|
||||||
if (%this.visibleDistance = 0 || !isObject(%this.player) || %this.player.getState() !$= "Move")
|
if (%this.visibleDistance = 0 || !isObject(%this.player) || %this.player.getState() !$= "Move")
|
||||||
{
|
{
|
||||||
%this.visualAcuityTick = %this.schedule(getRandom($DXAI::Bot::MinimumVisualAcuityTime, $DXAI::Bot::MaximumVisualAcuityTime,), "updateVisualAcuity");
|
%this.visualAcuityTick = %this.schedule(getRandom($DXAI::Bot::MinimumVisualAcuityTime, $DXAI::Bot::MaximumVisualAcuityTime), "updateVisualAcuity");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -323,6 +357,10 @@ function AIConnection::updateVisualAcuity(%this)
|
||||||
if (%this.awarenessTime[%current] < %noticeTime)
|
if (%this.awarenessTime[%current] < %noticeTime)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Is it a object we want to avoid?
|
||||||
|
if (AIGrenadeSet.isMember(%current))
|
||||||
|
%this.dangerObjects.add(%current);
|
||||||
|
|
||||||
if (%current.getType() & $TypeMasks::ProjectileObjectType)
|
if (%current.getType() & $TypeMasks::ProjectileObjectType)
|
||||||
{
|
{
|
||||||
%className = %current.getClassName();
|
%className = %current.getClassName();
|
||||||
|
|
|
||||||
|
|
@ -230,9 +230,10 @@ function GameConnection::getObjectsInViewcone(%this, %typeMask, %distance, %perf
|
||||||
|
|
||||||
%hitObject = getWord(%raycast, 0);
|
%hitObject = getWord(%raycast, 0);
|
||||||
|
|
||||||
// Since the engine doesn't do raycasts against projectiles correctly, we just check if the bot
|
// Since the engine doesn't do raycasts against projectiles & items correctly, we just check if the bot
|
||||||
// hit -nothing- when doing the raycast rather than checking for a hit against the object
|
// hit -nothing- when doing the raycast rather than checking for a hit against the object
|
||||||
if (%hitObject == %currentObject || (%currentObject.getType() & $TypeMasks::ProjectileObjectType && !isObject(%hitObject)))
|
%workaroundTypes = $TypeMasks::ProjectileObjectType | $TypeMasks::ItemObjectType;
|
||||||
|
if (%hitObject == %currentObject || (%currentObject.getType() & %workaroundTypes && !isObject(%hitObject)))
|
||||||
%result.add(%currentObject);
|
%result.add(%currentObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,9 @@ function DXAI::setup(%numTeams)
|
||||||
// Set our setup flag so that the execution hooks can behave correctly
|
// Set our setup flag so that the execution hooks can behave correctly
|
||||||
$DXAI::System::Setup = true;
|
$DXAI::System::Setup = true;
|
||||||
|
|
||||||
|
// Create the AIGrenadeSet to hold known grenades.
|
||||||
|
new SimSet(AIGrenadeSet);
|
||||||
|
|
||||||
for (%iteration = 1; %iteration < %numTeams + 1; %iteration++)
|
for (%iteration = 1; %iteration < %numTeams + 1; %iteration++)
|
||||||
{
|
{
|
||||||
%commander = new ScriptObject() { class = "AICommander"; team = %iteration; };
|
%commander = new ScriptObject() { class = "AICommander"; team = %iteration; };
|
||||||
|
|
@ -113,6 +116,131 @@ function DXAI::validateEnvironment()
|
||||||
$DXAI::System::InvalidatedEnvironment = false;
|
$DXAI::System::InvalidatedEnvironment = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
// Description: The weapon profiler loops over the active game datablocks, trying to
|
||||||
|
// run solely on weapons and precompute useful usage information for the artificial
|
||||||
|
// intelligence to use during weapon selection & firing.
|
||||||
|
// Param %printResults: A boolean representing whether or not the results should be
|
||||||
|
// printed to the console, useful for debugging.
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
function DXAI::runWeaponProfiler(%printResults)
|
||||||
|
{
|
||||||
|
if (!isObject(DatablockGroup))
|
||||||
|
{
|
||||||
|
error("DXAI: Cannot run weapons profiler, no DatablockGroup exists!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (%iteration = 0; %iteration < DataBlockGroup.getCount(); %iteration++)
|
||||||
|
{
|
||||||
|
%currentItem = DataBlockGroup.getObject(%iteration);
|
||||||
|
|
||||||
|
if (%currentItem.getClassName() $= "ItemData")
|
||||||
|
{
|
||||||
|
%currentImage = %currentItem.image;
|
||||||
|
|
||||||
|
if (isObject(%currentImage))
|
||||||
|
{
|
||||||
|
%currentProjectile = %currentImage.Projectile;
|
||||||
|
|
||||||
|
%ammoDB = %currentImage.ammo;
|
||||||
|
%usesAmmo = isObject(%ammoDB);
|
||||||
|
%usesEnergy = %currentImage.usesEnergy;
|
||||||
|
%firingEnergy = %currentImage.minEnergy;
|
||||||
|
%spread = %currentImage.projectileSpread;
|
||||||
|
|
||||||
|
if (%currentImage.isSeeker)
|
||||||
|
{
|
||||||
|
%dryEffectiveRange = %currentImage.seekRadius;
|
||||||
|
%wetEffectiveRange = %currentImage.seekRadius;
|
||||||
|
%dryAccurateRange = %currentImage.seekRadius;
|
||||||
|
%wetAccurateRange = %currentImage.seekRadius;
|
||||||
|
}
|
||||||
|
else if (isObject(%currentProjectile) && %currentProjectile.getClassName() $= "SniperProjectileData")
|
||||||
|
{
|
||||||
|
%dryEffectiveRange = %currentProjectile.maxRifleRange;
|
||||||
|
%wetEffectiveRange = %currentProjectile.maxRifleRange;
|
||||||
|
%dryAccurateRange = %currentProjectile.maxRifleRange;
|
||||||
|
%wetAccurateRange = %currentProjectile.maxRifleRange;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%dryEffectiveRange = (%currentProjectile.lifetimeMS / 1000) * %currentProjectile.dryVelocity;
|
||||||
|
%wetEffectiveRange = (%currentProjectile.lifetimeMS / 1000) * %currentProjectile.wetVelocity;
|
||||||
|
%dryAccurateRange = %dryEffectiveRange - (%currentImage.projectileSpread * 8);
|
||||||
|
%wetAccurateRange = %wetEffectiveRange - (%currentImage.projectileSpread * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to know if this thing fires underwater: We start at the initial state and look for something
|
||||||
|
// that prohibits underwater usage.
|
||||||
|
%firesWet = true;
|
||||||
|
%firesDry = true;
|
||||||
|
|
||||||
|
// First, we map out state names
|
||||||
|
%stateCount = -1;
|
||||||
|
%targetState = -1;
|
||||||
|
while (%currentImage.stateName[%stateCount++] !$= "")
|
||||||
|
{
|
||||||
|
%stateMapping[%currentImage.stateName[%stateCount]] = %stateCount;
|
||||||
|
|
||||||
|
if (%currentImage.stateFire[%stateCount])
|
||||||
|
%targetStateID = %stateCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start at the Ready state and go
|
||||||
|
%currentState = %stateMapping["Ready"];
|
||||||
|
|
||||||
|
%stateIteration = -1;
|
||||||
|
while (%stateIteration++ <= 10)
|
||||||
|
{
|
||||||
|
if (%currentImage.stateTransitionOnTriggerDown[%currentState] !$= "")
|
||||||
|
%currentState = %stateMapping[%currentImage.stateTransitionOnTriggerDown[%currentState]];
|
||||||
|
else if (%currentImage.stateTransitionOnWet[%currentState] $= "DryFire")
|
||||||
|
{
|
||||||
|
%firesWet = false;
|
||||||
|
|
||||||
|
// Check if it fires dry here as well
|
||||||
|
%firesDry = %currentImage.stateTransitionOnNotWet[%currentState] !$= "DryFire" ? true : false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (%stateIteration == 10)
|
||||||
|
error("DXAI: State analysis timed out on " @ %currentItem.getName() @ "!");
|
||||||
|
|
||||||
|
// Perform the assignments and we're done ... probably
|
||||||
|
%currentItem.firingEnergy = %firingEnergy;
|
||||||
|
%currentItem.dryEffectiveRange = %dryEffectiveRange;
|
||||||
|
%currentItem.wetEffectiveRange = %wetEffectiveRange;
|
||||||
|
%currentItem.dryAccurateRange = %dryAccurateRange;
|
||||||
|
%currentItem.wetAccurateRange = %wetAccurateRange;
|
||||||
|
%currentItem.firesWet = %firesWet;
|
||||||
|
%currentItem.firesDry = %firesDry;
|
||||||
|
%currentItem.usesAmmo = %usesAmmo;
|
||||||
|
%currentItem.usesEnergy = %usesEnergy;
|
||||||
|
%currentItem.firingEnergy = %firingEnergy;
|
||||||
|
%currentItem.ammoDB = %ammoDB;
|
||||||
|
%currentItem.spread = %spread;
|
||||||
|
|
||||||
|
if (%printResults)
|
||||||
|
{
|
||||||
|
error(%currentItem.getName());
|
||||||
|
error("Dry Range: " @ %dryEffectiveRange);
|
||||||
|
error("Wet Range: " @ %wetEffectiveRange);
|
||||||
|
error("Dry Accurate Range: " @ %dryAccurateRange);
|
||||||
|
error("Wet Accurate Range: " @ %wetAccurateRange);
|
||||||
|
error("Fires Wet: " @ %firesWet);
|
||||||
|
error("Fires Dry: " @ %firesDry);
|
||||||
|
|
||||||
|
if (!isObject(%currentProjectile))
|
||||||
|
error("*** COULD NOT FIND PROJECTILE ***");
|
||||||
|
error("--------------------------------------");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------
|
||||||
// Description: This update function is scheduled to be called roughly once every 32
|
// Description: This update function is scheduled to be called roughly once every 32
|
||||||
// milliseconds which updates each active commander in the game as well as performs
|
// milliseconds which updates each active commander in the game as well as performs
|
||||||
|
|
@ -299,6 +427,17 @@ package DXAI_Hooks
|
||||||
DXAI::validateEnvironment();
|
DXAI::validateEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
// Description: The AIGrenadeThrown function is called to notify the AI code that a
|
||||||
|
// grenade has been added to the game sim which is how bots will evade any grenade that
|
||||||
|
// is merely within range of them. However, this is not the behavior we want. We want the
|
||||||
|
// bots to actually see the grenade before responding to it.
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
function AIGrenadeThrown(%projectile)
|
||||||
|
{
|
||||||
|
AIGrenadeSet.add(%projectile);
|
||||||
|
}
|
||||||
|
|
||||||
// Make this do nothing so the bots don't ever get any objectives by default
|
// Make this do nothing so the bots don't ever get any objectives by default
|
||||||
function DefaultGame::AIChooseGameObjective(%game, %client) { return 11595; }
|
function DefaultGame::AIChooseGameObjective(%game, %client) { return 11595; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -217,9 +217,9 @@ function AIEnhancedEngageTarget::monitor(%task, %client)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
%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 !$= "")
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue