mirror of
https://github.com/Ragora/T2-DXAI.git
synced 2026-07-16 06:14:35 +00:00
Moved the weapon profiler to its own source file
This commit is contained in:
parent
1ab65e9e70
commit
2096f19e01
3 changed files with 215 additions and 131 deletions
|
|
@ -259,15 +259,15 @@ function AIConnection::updateWeapons(%this)
|
||||||
%currentWeaponImage = %currentWeapon.image;
|
%currentWeaponImage = %currentWeapon.image;
|
||||||
|
|
||||||
// No ammo?
|
// No ammo?
|
||||||
if (isObject(%currentWeaponImage.ammo) && %this.player.inv[%currentWeaponImage.ammo] <= 0)
|
if (%currentWeapon.usesAmmo && %this.player.inv[%currentWeapon.ammoDB] <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (%currentWeaponImage.projectileSpread >= 3 && %targetDistance <= 20)
|
if (%targetDistance <= %currentWeapon.dryEffectiveRange)
|
||||||
%bestWeapon = %iteration;
|
|
||||||
else if (%currentWeaponImage.projectileSpread < 3 && %targetDistance >= 20)
|
|
||||||
%bestWeapon = %iteration;
|
|
||||||
else if (%targetDistance >= 100 && %currentWeaponImage.projectileType $= "GrenadeProjectile")
|
|
||||||
%bestWeapon = %iteration;
|
%bestWeapon = %iteration;
|
||||||
|
// else if (%currentWeapon.spread < 3 && %targetDistance >= 20)
|
||||||
|
// %bestWeapon = %iteration;
|
||||||
|
// else if (%targetDistance >= 100 && %currentWeapon.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
|
// Arced & precision Weapons should be used at >= 100m
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ exec("scripts/DXAI/aiconnection.cs");
|
||||||
exec("scripts/DXAI/priorityqueue.cs");
|
exec("scripts/DXAI/priorityqueue.cs");
|
||||||
exec("scripts/DXAI/cyclicset.cs");
|
exec("scripts/DXAI/cyclicset.cs");
|
||||||
exec("scripts/DXAI/loadouts.cs");
|
exec("scripts/DXAI/loadouts.cs");
|
||||||
|
exec("scripts/DXAI/weaponProfiler.cs");
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------
|
||||||
// Description: This cleanup function is called when the mission ends to clean up all
|
// Description: This cleanup function is called when the mission ends to clean up all
|
||||||
|
|
@ -116,131 +117,6 @@ 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
|
||||||
|
|
@ -425,6 +301,9 @@ package DXAI_Hooks
|
||||||
|
|
||||||
// Ensure that the DXAI is active.
|
// Ensure that the DXAI is active.
|
||||||
DXAI::validateEnvironment();
|
DXAI::validateEnvironment();
|
||||||
|
|
||||||
|
// Run our profiler here as well.
|
||||||
|
WeaponProfiler::run(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
@ -502,6 +381,7 @@ package DXAI_Hooks
|
||||||
parent::stationTriggered(%data, %obj, %isTriggered);
|
parent::stationTriggered(%data, %obj, %isTriggered);
|
||||||
|
|
||||||
// TODO: If the bot isn't supposed to be on the station, at least restock ammunition?
|
// TODO: If the bot isn't supposed to be on the station, at least restock ammunition?
|
||||||
|
// FIXME: Can bots trigger dead stations?
|
||||||
if (%isTriggered && %obj.triggeredBy.client.isAIControlled() && %obj.triggeredBy.client.shouldRearm)
|
if (%isTriggered && %obj.triggeredBy.client.isAIControlled() && %obj.triggeredBy.client.shouldRearm)
|
||||||
{
|
{
|
||||||
%bot = %obj.triggeredBy.client;
|
%bot = %obj.triggeredBy.client;
|
||||||
|
|
|
||||||
204
scripts/DXAI/weaponProfiler.cs
Normal file
204
scripts/DXAI/weaponProfiler.cs
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
// weaponProfiler.cs
|
||||||
|
// Source file dedicated to the weapon profiling system.
|
||||||
|
// https://github.com/Ragora/T2-DXAI.git
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Robert MacGregor
|
||||||
|
// This software is licensed under the MIT license.
|
||||||
|
// Refer to LICENSE.txt for more information.
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------
|
||||||
|
// 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 WeaponProfiler::run(%printResults)
|
||||||
|
{
|
||||||
|
if (!isObject(DatablockGroup))
|
||||||
|
{
|
||||||
|
error("DXAI: Cannot run weapons profiler, no DatablockGroup exists!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform an initial scan for player, turret and vehicle datablocks first
|
||||||
|
%armorTypes = new SimSet();
|
||||||
|
%vehicleTypes = new SimSet();
|
||||||
|
%turretTypes = new SimSet();
|
||||||
|
for (%iteration = 0; %iteration < DataBlockGroup.getCount(); %iteration++)
|
||||||
|
{
|
||||||
|
%currentDB = DataBlockGroup.getObject(%iteration);
|
||||||
|
|
||||||
|
%classType = %currentDB.getClassName();
|
||||||
|
if (%classType $= "PlayerData")
|
||||||
|
%armorTypes.add(%currentDB);
|
||||||
|
else if (%classType $= "TurretData")
|
||||||
|
%turretTypes.add(%currentDB);
|
||||||
|
else if (%classType $= "HoverVehicleData" || %classType $= "FlyingVehicleData" || %classType $= "WheeledVehicleData")
|
||||||
|
%vehicleTypes.add(%currentDB);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we run the actual calculations
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
WeaponProfiler::_processImageStates(%currentItem);
|
||||||
|
|
||||||
|
// Perform the assignments and we're done ... probably
|
||||||
|
%currentItem.firingEnergy = %firingEnergy;
|
||||||
|
%currentItem.dryEffectiveRange = %dryEffectiveRange;
|
||||||
|
%currentItem.wetEffectiveRange = %wetEffectiveRange;
|
||||||
|
%currentItem.dryAccurateRange = %dryAccurateRange;
|
||||||
|
%currentItem.wetAccurateRange = %wetAccurateRange;
|
||||||
|
%currentItem.usesAmmo = %usesAmmo;
|
||||||
|
%currentItem.usesEnergy = %usesEnergy;
|
||||||
|
%currentItem.firingEnergy = %firingEnergy;
|
||||||
|
%currentItem.ammoDB = %ammoDB;
|
||||||
|
%currentItem.spread = %spread;
|
||||||
|
|
||||||
|
WeaponProfiler::_processArmorEffectiveness(%currentItem, %armorTypes);
|
||||||
|
WeaponProfiler::_processVehicleEffectiveness(%currentItem, %vehicleTypes);
|
||||||
|
WeaponProfiler::_processTurretEffectiveness(%currentItem, %turretTypes);
|
||||||
|
|
||||||
|
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: " @ %currentItem.firesWet);
|
||||||
|
error("Fires Dry: " @ %currentItem.firesDry);
|
||||||
|
|
||||||
|
if (!isObject(%currentProjectile))
|
||||||
|
{
|
||||||
|
error("*** COULD NOT FIND PROJECTILE ***");
|
||||||
|
|
||||||
|
%currentItem.dryEffectiveRange = 300;
|
||||||
|
%currentItem.wetEffectiveRange = 300;
|
||||||
|
%currentItem.dryAccurateRange = 300;
|
||||||
|
%currentItem.wetAccurateRange = 300;
|
||||||
|
}
|
||||||
|
error("--------------------------------------");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%armorTypes.delete();
|
||||||
|
%turretTypes.delete();
|
||||||
|
%vehicleTypes.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
function WeaponProfiler::_processArmorEffectiveness(%itemDB, %armorTypes)
|
||||||
|
{
|
||||||
|
%projectileType = %itemDB.image.Projectile;
|
||||||
|
|
||||||
|
if (!isObject(%projectileType))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (%iteration = 0; %iteration < %armorTypes.getCount(); %iteration++)
|
||||||
|
{
|
||||||
|
%currentArmor = %armorTypes.getObject(%iteration);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function WeaponProfiler::_processTurretEffectiveness(%itemDB, %turretTypes)
|
||||||
|
{
|
||||||
|
%projectileType = %itemDB.image.Projectile;
|
||||||
|
|
||||||
|
if (!isObject(%projectileType))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function WeaponProfiler::_processVehicleEffectiveness(%itemDB, %vehicleTypes)
|
||||||
|
{
|
||||||
|
%projectileType = %itemDB.image.Projectile;
|
||||||
|
|
||||||
|
if (!isObject(%projectileType))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function WeaponProfiler::_processImageStates(%itemDB)
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%itemDB.firesWet = %firesWet;
|
||||||
|
%itemDB.firesDry = %firesDry;
|
||||||
|
|
||||||
|
if (%stateIteration == 10)
|
||||||
|
error("DXAI: State analysis timed out on " @ %currentItem.getName() @ "!");
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue