Moved the weapon profiler to its own source file

This commit is contained in:
Robert MacGregor 2015-10-11 03:02:19 -04:00
parent 1ab65e9e70
commit 2096f19e01
3 changed files with 215 additions and 131 deletions

View file

@ -259,15 +259,15 @@ function AIConnection::updateWeapons(%this)
%currentWeaponImage = %currentWeapon.image;
// No ammo?
if (isObject(%currentWeaponImage.ammo) && %this.player.inv[%currentWeaponImage.ammo] <= 0)
if (%currentWeapon.usesAmmo && %this.player.inv[%currentWeapon.ammoDB] <= 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")
if (%targetDistance <= %currentWeapon.dryEffectiveRange)
%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
// Arced & precision Weapons should be used at >= 100m

View file

@ -15,6 +15,7 @@ exec("scripts/DXAI/aiconnection.cs");
exec("scripts/DXAI/priorityqueue.cs");
exec("scripts/DXAI/cyclicset.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
@ -116,131 +117,6 @@ 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
@ -425,6 +301,9 @@ package DXAI_Hooks
// Ensure that the DXAI is active.
DXAI::validateEnvironment();
// Run our profiler here as well.
WeaponProfiler::run(false);
}
//------------------------------------------------------------------------------------------
@ -502,6 +381,7 @@ package DXAI_Hooks
parent::stationTriggered(%data, %obj, %isTriggered);
// 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)
{
%bot = %obj.triggeredBy.client;

View 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() @ "!");
}