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)
|
||||
{
|
||||
%this.dangerObjects = new SimSet();
|
||||
%this.fieldOfView = $DXAI::Bot::DefaultFieldOfView;
|
||||
%this.viewDistance = $DXAI::Bot::DefaultViewDistance;
|
||||
}
|
||||
|
|
@ -197,6 +198,10 @@ function AIConnection::updateLegs(%this)
|
|||
%delta = %now - %this.lastUpdateLegs;
|
||||
%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.aimAtLocation)
|
||||
|
|
@ -225,23 +230,52 @@ function AIConnection::updateLegs(%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))
|
||||
{
|
||||
%player = %this.player;
|
||||
%targetDistance = vectorDist(%player.getPosition(), %this.engageTarget.getPosition());
|
||||
|
||||
// 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.
|
||||
%bestWeapon = 0;
|
||||
|
||||
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
|
||||
// Arced & precision Weapons should be used at >= 100m
|
||||
|
||||
}
|
||||
|
||||
%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 (%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;
|
||||
}
|
||||
|
||||
|
|
@ -322,7 +356,11 @@ function AIConnection::updateVisualAcuity(%this)
|
|||
%noticeTime = getRandom(700, 1200);
|
||||
if (%this.awarenessTime[%current] < %noticeTime)
|
||||
continue;
|
||||
|
||||
|
||||
// Is it a object we want to avoid?
|
||||
if (AIGrenadeSet.isMember(%current))
|
||||
%this.dangerObjects.add(%current);
|
||||
|
||||
if (%current.getType() & $TypeMasks::ProjectileObjectType)
|
||||
{
|
||||
%className = %current.getClassName();
|
||||
|
|
|
|||
|
|
@ -230,9 +230,10 @@ function GameConnection::getObjectsInViewcone(%this, %typeMask, %distance, %perf
|
|||
|
||||
%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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ function DXAI::setup(%numTeams)
|
|||
// Set our setup flag so that the execution hooks can behave correctly
|
||||
$DXAI::System::Setup = true;
|
||||
|
||||
// Create the AIGrenadeSet to hold known grenades.
|
||||
new SimSet(AIGrenadeSet);
|
||||
|
||||
for (%iteration = 1; %iteration < %numTeams + 1; %iteration++)
|
||||
{
|
||||
%commander = new ScriptObject() { class = "AICommander"; team = %iteration; };
|
||||
|
|
@ -113,6 +116,131 @@ function DXAI::validateEnvironment()
|
|||
$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
|
||||
// milliseconds which updates each active commander in the game as well as performs
|
||||
|
|
@ -298,6 +426,17 @@ package DXAI_Hooks
|
|||
// Ensure that the DXAI is active.
|
||||
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
|
||||
function DefaultGame::AIChooseGameObjective(%game, %client) { return 11595; }
|
||||
|
|
|
|||
|
|
@ -217,9 +217,9 @@ function AIEnhancedEngageTarget::monitor(%task, %client)
|
|||
return;
|
||||
}
|
||||
|
||||
%client.engageTargetLastPosition = %client.engageTarget.getWorldBoxCenter();
|
||||
%client.setMoveTarget(getRandomPositionOnTerrain(%client.engageTargetLastPosition, 40));
|
||||
%client.pressFire();
|
||||
// %client.engageTargetLastPosition = %client.engageTarget.getWorldBoxCenter();
|
||||
// %client.setMoveTarget(getRandomPositionOnTerrain(%client.engageTargetLastPosition, 40));
|
||||
//%client.pressFire();
|
||||
}
|
||||
else if (%client.engageTargetLastPosition !$= "")
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue