private static List <WeaponAttackEval> FilterForBreachingShot(List <WeaponAttackEval> attacks, AttackDetails details) { if (!details.Attacker.HasBreachingShotAbility) { return(attacks); } List <WeaponAttackEval> filteredList = new List <WeaponAttackEval>(); // TODO: Sort by chance to hit / weight weapons with a higher chance to hit? attacks.Sort((wae1, wae2) => (wae1.EVDirectDmg + wae1.EVStructDam).CompareTo(wae2.EVDirectDmg + wae2.EVStructDam)); WeaponAttackEval bShotWAE = attacks.First(); float bShotDmg = (bShotWAE.EVDirectDmg + bShotWAE.EVStructDam) * Mod.Config.Weights.BreachingShot.Multi; float sumDmg = attacks.Sum(x => x.EVDirectDmg + x.EVStructDam); Mod.Log.Debug?.Write($" breachingShotDmg: {bShotDmg} vs. sumEVDmg: {sumDmg}"); // TODO: Normalize toHit chance of sumDmg vs. toHit of bShotDmg before comparing damage if (bShotDmg > sumDmg) { Mod.Log.Debug?.Write($"Breaching shot has more damage, returning a list of one item."); filteredList.Add(bShotWAE); } else { Mod.Log.Debug?.Write($"Full attack has more damage, returning the entire list."); filteredList.AddRange(attacks); } return(filteredList); }
// Iterate the ammoModePairs on the weapon to find the highest direct damage, heat damage, and stab damage private static (WeaponAttackEval damage, WeaponAttackEval heat, WeaponAttackEval stab) OptimizeAmmoPairForAttack(Weapon weapon, AttackDetails details) { WeaponAttackEval damage = new WeaponAttackEval() { Weapon = weapon }; WeaponAttackEval heat = new WeaponAttackEval() { Weapon = weapon }; WeaponAttackEval stab = new WeaponAttackEval() { Weapon = weapon }; BehaviorTree bTree = details.Attacker.BehaviorTree; try { float attackTypeWeight = AIHelper.GetCachedBehaviorVariableValue(bTree, BehaviorVariableName.Float_ShootingDamageMultiplier).FloatVal;; // Damage prediction assumes an attack quality of Solid. It doesn't apply targetMultis either Dictionary <AmmoModePair, WeaponFirePredictedEffect> damagePredictions = CleverGirlHelper.gatherDamagePrediction(weapon, details.AttackPosition, details.Target); foreach (KeyValuePair <AmmoModePair, WeaponFirePredictedEffect> kvp in damagePredictions) { AmmoModePair ammoModePair = kvp.Key; WeaponFirePredictedEffect weaponFirePredictedEffect = kvp.Value; Mod.Log.Debug?.Write($" - Evaluating ammoId: {ammoModePair.ammoId} with modeId: {ammoModePair.modeId}"); WeaponAttackEval wae = new WeaponAttackEval() { Weapon = weapon, AmmoMode = ammoModePair }; foreach (DamagePredictionRecord dpr in weaponFirePredictedEffect.predictDamage) { Hostility targetHostility = SharedState.Combat.HostilityMatrix.GetHostility(details.Attacker.team, dpr.Target.team); if (targetHostility == Hostility.FRIENDLY) { // Friendly and self damage weights directly into a self damage, and doesn't contribute to any attacks float damageMulti; if (details.Attacker.GUID == dpr.Target.GUID) { damageMulti = Mod.Config.Weights.DamageMultis.Self; } else { damageMulti = Mod.Config.Weights.DamageMultis.Friendly; } wae.EVFriendlyDmg += dpr.ToHit * dpr.Normal * damageMulti; wae.EVFriendlyDmg += dpr.ToHit * dpr.AP * damageMulti; wae.EVFriendlyDmg += dpr.ToHit * dpr.Heat * damageMulti; wae.EVFriendlyDmg += dpr.ToHit * dpr.Instability * damageMulti; } else if (targetHostility == Hostility.NEUTRAL) { // Neutrals are weighted lower, to emphasize attacking enemies more directly wae.EVDirectDmg += dpr.ToHit * dpr.Normal * Mod.Config.Weights.DamageMultis.Neutral; wae.EVStructDam += dpr.ToHit * dpr.AP * Mod.Config.Weights.DamageMultis.Neutral; wae.EVHeat += dpr.ToHit * dpr.Heat * Mod.Config.Weights.DamageMultis.Neutral; wae.EVStab += dpr.ToHit * dpr.Instability * Mod.Config.Weights.DamageMultis.Neutral; } else { wae.EVDirectDmg += dpr.ToHit * dpr.Normal; wae.EVStructDam += dpr.ToHit * dpr.AP; wae.EVHeat += dpr.ToHit * dpr.Heat; wae.EVStab += dpr.ToHit * dpr.Instability; } if (!dpr.isAoE && dpr.ToHit > wae.ToHit) { wae.ToHit = dpr.ToHit; } } if ((wae.EVDirectDmg + wae.EVStructDam) >= (damage.EVDirectDmg + damage.EVStructDam)) { damage = wae; } if (wae.EVHeat >= heat.EVHeat) { heat = wae; } if (wae.EVStructDam >= stab.EVStructDam) { stab = wae; } } } catch (Exception e) { Mod.Log.Error?.Write(e, "Failed to calculate weapon damageEV!"); } return(damage, heat, stab); }