Skip to content

Commit

Permalink
- Prototype integration with CAC
Browse files Browse the repository at this point in the history
  • Loading branch information
IceRaptor committed Sep 17, 2019
1 parent b367b9c commit 4c4552c
Show file tree
Hide file tree
Showing 9 changed files with 341 additions and 186 deletions.
6 changes: 6 additions & 0 deletions CleverGirl/CleverGirl.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleverGirl", "CleverGirl\Cl
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CC+CAC|Any CPU = CC+CAC|Any CPU
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Vanilla|Any CPU = Vanilla|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{961D1A37-7133-4B94-BDB1-CCA0FD315F03}.CC+CAC|Any CPU.ActiveCfg = CC+CAC|Any CPU
{961D1A37-7133-4B94-BDB1-CCA0FD315F03}.CC+CAC|Any CPU.Build.0 = CC+CAC|Any CPU
{961D1A37-7133-4B94-BDB1-CCA0FD315F03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{961D1A37-7133-4B94-BDB1-CCA0FD315F03}.Debug|Any CPU.Build.0 = Debug|Any CPU
{961D1A37-7133-4B94-BDB1-CCA0FD315F03}.Release|Any CPU.ActiveCfg = Release|Any CPU
{961D1A37-7133-4B94-BDB1-CCA0FD315F03}.Release|Any CPU.Build.0 = Release|Any CPU
{961D1A37-7133-4B94-BDB1-CCA0FD315F03}.Vanilla|Any CPU.ActiveCfg = Vanilla|Any CPU
{961D1A37-7133-4B94-BDB1-CCA0FD315F03}.Vanilla|Any CPU.Build.0 = Vanilla|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
28 changes: 27 additions & 1 deletion CleverGirl/CleverGirl/CleverGirl.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
Expand All @@ -30,6 +30,13 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'CC+CAC|AnyCPU'">
<OutputPath>bin\CC+CAC\</OutputPath>
<DefineConstants>USE_CC, USE_CAC</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Vanilla|AnyCPU'">
<OutputPath>bin\Vanilla\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\Mods\ModTek\0Harmony.dll</HintPath>
Expand All @@ -40,6 +47,12 @@
<Reference Include="BattleTech.Common">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\BattleTech.Common.dll</HintPath>
</Reference>
<Reference Include="CustomAmmoCategories">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\Mods\CustomAmmoCategories\CustomAmmoCategories.dll</HintPath>
</Reference>
<Reference Include="CustomComponents">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\Mods\CustomComponents\CustomComponents.dll</HintPath>
</Reference>
<Reference Include="IRBTModUtils">
<HintPath>..\..\..\IRBTModUtils\IRBTModUtils\IRBTModUtils\bin\Debug\IRBTModUtils.dll</HintPath>
</Reference>
Expand All @@ -63,6 +76,7 @@
<Compile Include="CleverGirl.cs" />
<Compile Include="Helper\AIHelper.cs" />
<Compile Include="Helper\AttackEvaluatorHelper.cs" />
<Compile Include="Helper\CACHelper.cs" />
<Compile Include="Helper\CombatDamageHelper.cs" />
<Compile Include="Patches\AttackEvaluator_EvaluateAttacks_Patches.cs" />
<Compile Include="Patches\AIUtil_ExpectedDamageForAttack_Patches.cs" />
Expand All @@ -72,6 +86,18 @@
<Compile Include="Utils\ModConfig.cs" />
<Compile Include="Utils\State.cs" />
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains('USE_CAC'))">
<Reference Include="CustomAmmoCategories">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\Mods\CustomAmmoCategories\CustomAmmoCategories.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains('USE_CC'))">
<Reference Include="CustomComponents">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\Mods\CustomComponents\CustomComponents.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
Expand Down
64 changes: 43 additions & 21 deletions CleverGirl/CleverGirl/Helper/AIHelper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

using BattleTech;
using CustAmmoCategories;
using Harmony;
using System.Collections.Concurrent;
using System.Collections.Generic;
Expand Down Expand Up @@ -165,39 +166,60 @@ private static float CalculateWeaponDamageEV(CondensedWeapon cWeapon, BehaviorTr
// If this is an aggregate weapon and the toHitFromPos isn't multiplied by count, does it make a diff?
// i.e. this would be (2 * 0.7 * X) => 1.4x per, w/ 8 weapons -> 8 * 1.4 => 11.2
// with (8 * 2 * 0.7 * X) => 11.2
float weaponDamageEV = (float)shotsWhenFired * toHitFromPos * (damagePerShotFromPos + heatDamPerShotWeight + stabilityDamPerShotWeight + meleeStatusWeights);

float aggregateDamageEV = weaponDamageEV * cWeapon.weaponsCondensed;
float weaponDamageEV = (float)shotsWhenFired * toHitFromPos * (damagePerShotFromPos + heatDamPerShotWeight + stabilityDamPerShotWeight + meleeStatusWeights);

return aggregateDamageEV;
}
#if USE_CAC

public class AggregateWeapon {
public Weapon weapon;
public int count;
List<WeaponMode> usableModes = CACHelper.UsableModes(cWeapon.First);
foreach (WeaponMode wMode in usableModes) {
Mod.Log.Info($"Found mode: {wMode.Id}");
if (wMode.AOECapable == TripleBoolean.True) {
float AoEDamage = CustomAmmoCategories.getWeaponAOEDamage(cWeapon.First);
float AoEHeat = CustomAmmoCategories.getWeaponAOEHeatDamage(cWeapon.First);
float AoEStability = cWeapon.First.AOEInstability();
Mod.Log.Info($" mode has AOE damage:{AoEDamage} heat:{AoEHeat}");
}

public AggregateWeapon(Weapon weapon, int count) {
this.weapon = weapon;
this.count = count;
}
}

public static List<AggregateWeapon> AggregateWeaponList(List<Weapon> allWeapons) {
Dictionary<string, AggregateWeapon> aggregates = new Dictionary<string, AggregateWeapon>();
//AIHelper.TargetsWithinAoE(attacker, target.CurrentPosition, 20.0f,
// out int allyCount, out int neutralCount, out int enemyCount);

//float collateralDamageEV = weaponDamageEV * (allyCount + neutralCount);
//float enemyAOEDamageEV = weaponDamageEV * (enemyCount - 1);
//Mod.Log.Debug($"AOE attack - will inflict {collateralDamageEV} on {allyCount} allies and {neutralCount} neutral actors. Inflicts damage {enemyAOEDamageEV} on {enemyCount} enemies.");

foreach(Weapon weapon in allWeapons) {
if (!aggregates.ContainsKey(weapon.defId)) {
AggregateWeapon aw = new AggregateWeapon(weapon, 1);
aggregates.Add(weapon.defId, aw);
} else {
aggregates[weapon.defId].count++;
//weaponDamageEV = weaponDamageEV + enemyAOEDamageEV - collateralDamageEV;
#endif

float aggregateDamageEV = weaponDamageEV * cWeapon.weaponsCondensed;

return aggregateDamageEV;
}

public static void TargetsWithinAoE(AbstractActor attacker, Vector3 position, float radius,
out int alliesWithin, out int neutralWithin, out int enemyWithin) {

alliesWithin = 0;
neutralWithin = 0;
enemyWithin = 0;
foreach (ICombatant target in attacker.Combat.GetAllLivingCombatants()) {
float distance = (target.CurrentPosition - position).magnitude;
if (distance <= radius) {
Hostility targetHostility = attacker.Combat.HostilityMatrix.GetHostility(attacker.TeamId, target.team?.GUID);
if (targetHostility == Hostility.ENEMY) {
enemyWithin++;
} else if (targetHostility == Hostility.NEUTRAL) {
neutralWithin++;
} else if (targetHostility == Hostility.FRIENDLY) {
alliesWithin++;
}
}
}

return aggregates.Select(kvp => kvp.Value).ToList();
}


// --- BEHAVIOR VARIABLE BELOW
public static void ResetBehaviorCache() { State.BehaviorVarValuesCache.Clear(); }

Expand Down
41 changes: 33 additions & 8 deletions CleverGirl/CleverGirl/Helper/AttackEvaluatorHelper.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
using BattleTech;

#if USE_CAC
using CustAmmoCategories;
#endif

using System.Collections.Concurrent;
using System.Collections.Generic;
using UnityEngine;

using static AttackEvaluator;

namespace CleverGirl {
Expand All @@ -11,9 +17,14 @@ public class CondensedWeapon {
public int weaponsCondensed = 0;
public List<Weapon> condensedWeapons = new List<Weapon>();

#if USE_CAC
public WeaponMode CACWeaponMode = null;
#endif

public CondensedWeapon() {}
public CondensedWeapon(Weapon weapon) {
AddWeapon(weapon);

}

// Invoke this after construction and every time you want to aggregate a weapon
Expand All @@ -25,6 +36,7 @@ public void AddWeapon(Weapon weapon) {
public Weapon First {
get { return this.condensedWeapons[0]; }
}

}

public class CandidateWeapons {
Expand All @@ -35,40 +47,54 @@ public class CandidateWeapons {
readonly private Dictionary<string, CondensedWeapon> condensed = new Dictionary<string, CondensedWeapon>();

public CandidateWeapons(AbstractActor attacker, ICombatant target) {
Mod.Log.Debug($"Calculating candidate weapons");

for (int i = 0; i < attacker.Weapons.Count; i++) {
Weapon weapon = attacker.Weapons[i];

CondensedWeapon cWeapon = new CondensedWeapon(weapon);

if (cWeapon.First.CanFire) {
Mod.Log.Debug($" weapon: ({cWeapon.First.defId}) is a candidate, adding");
Mod.Log.Debug($" ({cWeapon.First.defId}) can fire, adding as candidate");
string cWepKey = cWeapon.First.weaponDef.Description.Id;
if (condensed.ContainsKey(cWepKey)) {
condensed[cWepKey].AddWeapon(weapon);
} else {
condensed[cWepKey] = cWeapon;
}
} else {
Mod.Log.Debug($" weapon: ({cWeapon.First.defId}) is disabled or out of ammo, skipping.");
Mod.Log.Debug($" ({cWeapon.First.defId}) is disabled or out of ammo, skipping.");
}
}

// TODO: Can fire only evaluates ammo once... check for enough ammo for all shots?

float positionDelta = (target.CurrentPosition - attacker.CurrentPosition).magnitude;
#if USE_CAC
// Evaluate CAC ammo boxes if defined.
foreach (KeyValuePair<string, CondensedWeapon> kvp in condensed) {
CondensedWeapon cWeapon = kvp.Value;

}
#endif

float distance = (target.CurrentPosition - attacker.CurrentPosition).magnitude;
Mod.Log.Debug($" Checking range {distance} and LOF from attacker: ({attacker.CurrentPosition}) to " +
$"target: ({target.CurrentPosition})");
foreach (KeyValuePair<string, CondensedWeapon> kvp in condensed) {
CondensedWeapon cWeapon = kvp.Value;
// Evaluate being able to hit the target
bool willFireAtTarget = cWeapon.First.WillFireAtTargetFromPosition(target, attacker.CurrentPosition, attacker.CurrentRotation);
bool withinRange = positionDelta <= cWeapon.First.MaxRange;
bool withinRange = distance <= cWeapon.First.MaxRange;
if (willFireAtTarget && withinRange) {
Mod.Log.Debug($" adding weapon: ({cWeapon.First.defId}) to ranged set");
Mod.Log.Debug($" ({cWeapon.First.defId}) has LOF and is within range, adding ");
RangedWeapons.Add(cWeapon);
} else {
Mod.Log.Debug($" weapon: ({cWeapon.First.defId}) out of range or has no LOF, skipping.");
Mod.Log.Debug($" ({cWeapon.First.defId}) is out of range (MaxRange: {cWeapon.First.MaxRange} vs {distance}) " +
$"or has no LOF, skipping.");
}

if (cWeapon.First.Category == WeaponCategory.AntiPersonnel) {
Mod.Log.Debug($" adding support weapon: ({cWeapon.First.defId}) to melee and DFA attacks.");
Mod.Log.Debug($" ({cWeapon.First.defId}) is anti-personnel, adding to melee and DFA sets.");
MeleeWeapons.Add(cWeapon);
DFAWeapons.Add(cWeapon);
}
Expand All @@ -82,7 +108,6 @@ public static List<AttackEvaluation> EvaluateAttacks(AbstractActor unit, ICombat
List<List<CondensedWeapon>>[] weaponSetListByAttack, Vector3 attackPosition, Vector3 targetPosition,
bool targetIsEvasive) {

Mod.Log.Debug($"Evaluating {weaponSetListByAttack?.Length} types of attack.");
ConcurrentBag<AttackEvaluation> allResults = new ConcurrentBag<AttackEvaluation>();

// List 0 is ranged weapons, 1 is melee+support, 2 is DFA+support
Expand Down
67 changes: 67 additions & 0 deletions CleverGirl/CleverGirl/Helper/CACHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using BattleTech;
using CustAmmoCategories;
using System;
using System.Collections.Generic;

namespace CleverGirl {
public static class CACHelper {

// largely a copy of AIWeaponChoose::getWeaponDamagePredict
public static Dictionary<WeaponMode, int> UsableModes(Weapon weapon) {
Dictionary<WeaponMode, int> filteredModes = new Dictionary<WeaponMode, int>();

ExtWeaponDef extWeaponDef = CustomAmmoCategories.getExtWeaponDef(weapon.defId);
if (extWeaponDef.Modes.Count < 1) {
Mod.Log.Error($" Weapon: ({weapon.defId}) has no base or custom modes!");
return filteredModes;
}

List<WeaponMode> availableModes = weapon.AvaibleModes();
if (availableModes.Count < 1) {
Mod.Log.Debug($" Weapon: ({weapon.defId}) has no modes that it can use.");
return filteredModes;
}
Mod.Log.Debug($" weapon: {weapon.defId} has: {availableModes.Count} modes");

foreach (WeaponMode weaponMode in availableModes) {
CustomAmmoCategory ammoCategory = CustomAmmoCategories.find(weapon.AmmoCategory.ToString());
// The weapon defaults to the base ammo type
if (extWeaponDef.AmmoCategory.BaseCategory == weapon.AmmoCategory) { ammoCategory = extWeaponDef.AmmoCategory; }
// The weapon mode doesn't match the default ammo type, change
if (weaponMode.AmmoCategory.Index != ammoCategory.Index) { ammoCategory = weaponMode.AmmoCategory; }
// Hardcode the comparison here b/c CustomAmmoCategories.NotSetCustomAmmoCategoty.Index is private
if (ammoCategory.Index == 0) {
Mod.Log.Info("Ammo type is unset, skipping.");
}
foreach (AmmunitionBox ammoBox in weapon.ammoBoxes) {
if (ammoBox.IsFunctional == false) { continue; }
if (ammoBox.CurrentAmmo <= 0 ) { continue; }
CustomAmmoCategory boxAmmoCategory = CustomAmmoCategories.getAmmoAmmoCategory(ammoBox.ammoDef);
if (boxAmmoCategory.Index == ammoCategory.Index) {
Mod.Log.Info($" found ammoBox:{ammoBox.Name} with count: {ammoBox.CurrentAmmo} for weapon: {weapon.defId} that has shots: {weaponMode.ShotsWhenFired}");
if (filteredModes.ContainsKey(weaponMode)) {
filteredModes[weaponMode] += (int)Math.Floor((double)ammoBox.CurrentAmmo / weaponMode.ShotsWhenFired);
} else {
filteredModes[weaponMode] = (int)Math.Floor((double)ammoBox.CurrentAmmo / weaponMode.ShotsWhenFired);
}
}
}
}

// Unnecessary here, but useful elsewhere to set the active mode
//string currentMode = extWeaponDef.baseModeId;
//if (CustomAmmoCategories.checkExistance(weapon.StatCollection, CustomAmmoCategories.WeaponModeStatisticName) == true) {
// currentMode = weapon.StatCollection.GetStatistic(CustomAmmoCategories.WeaponModeStatisticName).Value<string>();
//}

//string currentAmmo = "";
//if (CustomAmmoCategories.checkExistance(weapon.StatCollection, CustomAmmoCategories.AmmoIdStatName) == true) {
// currentAmmo = weapon.StatCollection.GetStatistic(CustomAmmoCategories.AmmoIdStatName).Value<string>();
//}

Mod.Log.Debug($"Returning {filteredModes.Count} for weapon: {weapon.defId}");
return filteredModes;
}

}
}
Loading

0 comments on commit 4c4552c

Please sign in to comment.