mirror of
https://github.com/Ragora/T2-DXAI.git
synced 2026-01-19 18:14:45 +00:00
Moved the weapon profiler to its own source file
This commit is contained in:
parent
1ab65e9e70
commit
2096f19e01
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
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…
Reference in a new issue