public static List <DamagePredictRecord> getWeaponDamagePredict(AbstractActor unit, ICombatant target, Weapon weapon) { List <DamagePredictRecord> result = new List <DamagePredictRecord>(); ExtWeaponDef extWeapon = CustomAmmoCategories.getExtWeaponDef(weapon.defId); if (extWeapon.Modes.Count < 1) { CustomAmmoCategoriesLog.Log.LogWrite("WARNING! " + weapon.defId + " has no modes. Even base mode. This means something is very very wrong\n", true); return(result); } string currentMode = extWeapon.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>(); } foreach (var mode in extWeapon.Modes) { HashSet <string> ammos = CustomAmmoCategories.getWeaponAvaibleAmmoForMode(weapon, mode.Value.Id); List <int> hitLocations = null; float AverageArmor = float.NaN; foreach (var ammo in ammos) { DamagePredictRecord record = new DamagePredictRecord(ammo, mode.Value.Id); CustomAmmoCategories.fillWeaponPredictRecord(ref record, unit, target, weapon, ref hitLocations, ref AverageArmor); result.Add(record); } } CustomAmmoCategories.applyWeaponAmmoMode(weapon, currentMode, currentAmmo); return(result); }
public static void ChooseBestWeaponForTarget(AbstractActor unit, ICombatant target, bool isStationary) { Stopwatch stopWatch = new Stopwatch(); Dictionary <string, Weapon> weapons = new Dictionary <string, Weapon>(); Dictionary <string, List <DamagePredictRecord> > damagePredict = new Dictionary <string, List <DamagePredictRecord> >(); foreach (Weapon weapon in unit.Weapons) { weapons.Add(weapon.uid, weapon); damagePredict.Add(weapon.uid, CustomAmmoCategories.getWeaponDamagePredict(unit, target, weapon)); } foreach (var weapon in weapons) { CustomAmmoCategoriesLog.Log.LogWrite("Weapon " + weapon.Key + " " + weapon.Value.defId + "\n"); foreach (var fireType in damagePredict[weapon.Key]) { CustomAmmoCategoriesLog.Log.LogWrite(" mode:" + fireType.Id.modeId + " ammo:" + fireType.Id.ammoId + " heat:" + fireType.HeatDamageCoeff + " dmg:" + fireType.NormDamageCoeff + "\n"); } } Mech targetMech = target as Mech; if (targetMech != null) { CustomAmmoCategoriesLog.Log.LogWrite("Try overheat\n"); float overallPredictHeatDamage = 0f; Dictionary <string, int> weaponsWithHeatFireMode = new Dictionary <string, int>(); foreach (var weapon in weapons) { if (damagePredict.ContainsKey(weapon.Key) == false) { CustomAmmoCategoriesLog.Log.LogWrite("WARNING! " + weapon.Value.defId + " has no predict damage record something is very very wrong\n", true); continue; } if (damagePredict[weapon.Key].Count <= 0) { CustomAmmoCategoriesLog.Log.LogWrite("WARNING! " + weapon.Value.defId + " has empty predict damage record something is very very wrong\n", true); continue; } float HeatDamageCoeff = damagePredict[weapon.Key][0].HeatDamageCoeff; int heatDamageIndex = 0; bool haveDiffHeatMode = false; for (int index = 1; index < damagePredict[weapon.Key].Count; ++index) { DamagePredictRecord fireMode = damagePredict[weapon.Key][index]; if (HeatDamageCoeff < fireMode.HeatDamageCoeff) { HeatDamageCoeff = fireMode.HeatDamageCoeff; heatDamageIndex = index; haveDiffHeatMode = true; } ; } overallPredictHeatDamage += damagePredict[weapon.Key][heatDamageIndex].PredictHeatDamage; if (haveDiffHeatMode) { weaponsWithHeatFireMode.Add(weapon.Key, heatDamageIndex); } } CustomAmmoCategoriesLog.Log.LogWrite(" Current target heat:" + targetMech.CurrentHeat + " predicted:" + overallPredictHeatDamage + "\n"); if ((targetMech.CurrentHeat + overallPredictHeatDamage) > targetMech.OverheatLevel) { CustomAmmoCategoriesLog.Log.LogWrite(" worth it\n"); foreach (var weapon in weaponsWithHeatFireMode) { CustomAmmoCategories.applyWeaponAmmoMode(weapons[weapon.Key], damagePredict[weapon.Key][weapon.Value].Id.modeId, damagePredict[weapon.Key][weapon.Value].Id.ammoId); weapons.Remove(weapon.Key); damagePredict.Remove(weapon.Key); } } else { CustomAmmoCategoriesLog.Log.LogWrite(" not worth it\n"); } } CustomAmmoCategoriesLog.Log.LogWrite("Normal damage\n"); foreach (var weapon in weapons) { CustomAmmoCategoriesLog.Log.LogWrite("Weapon " + weapon.Key + " " + weapon.Value.defId + "\n"); foreach (var fireType in damagePredict[weapon.Key]) { CustomAmmoCategoriesLog.Log.LogWrite(" mode:" + fireType.Id.modeId + " ammo:" + fireType.Id.ammoId + " heat:" + fireType.HeatDamageCoeff + " dmg:" + fireType.NormDamageCoeff + "\n"); } } foreach (var weapon in weapons) { if (damagePredict.ContainsKey(weapon.Key) == false) { CustomAmmoCategoriesLog.Log.LogWrite("WARNING! " + weapon.Value.defId + " has no predict damage record something is very very wrong\n", true); continue; } if (damagePredict[weapon.Key].Count <= 0) { CustomAmmoCategoriesLog.Log.LogWrite("WARNING! " + weapon.Value.defId + " has empty predict damage record something is very very wrong\n", true); continue; } float DamageCoeff = damagePredict[weapon.Key][0].HeatDamageCoeff; int DamageIndex = 0; for (int index = 1; index < damagePredict[weapon.Key].Count; ++index) { DamagePredictRecord fireMode = damagePredict[weapon.Key][index]; if (DamageCoeff < fireMode.NormDamageCoeff) { DamageCoeff = fireMode.NormDamageCoeff; DamageIndex = index; } ; } CustomAmmoCategories.applyWeaponAmmoMode(weapons[weapon.Key], damagePredict[weapon.Key][DamageIndex].Id.modeId, damagePredict[weapon.Key][DamageIndex].Id.ammoId); } }
public static void fillWeaponPredictRecord(ref DamagePredictRecord record, AbstractActor unit, ICombatant target, Weapon weapon, ref List <int> hitLocations, ref float AverageArmor) { CustomAmmoCategoriesLog.Log.LogWrite("fillWeaponPredictRecord " + unit.DisplayName + " target " + target.DisplayName + " weapon " + weapon.defId + "\n"); CustomAmmoCategories.applyWeaponAmmoMode(weapon, record.Id.modeId, record.Id.ammoId); AbstractActor targetActor = target as AbstractActor; if (hitLocations == null) { hitLocations = target.GetPossibleHitLocations(unit); foreach (int hitLocation in hitLocations) { CustomAmmoCategoriesLog.Log.LogWrite("Hit Location " + hitLocation + "\n"); } } if (float.IsNaN(AverageArmor)) { AverageArmor = CustomAmmoCategories.getTargetAvarageArmor(hitLocations, target); } float toHit = 0; if (weapon.WillFireAtTargetFromPosition(target, unit.CurrentPosition) == true) { toHit = weapon.GetToHitFromPosition(target, 1, unit.CurrentPosition, target.CurrentPosition, true, (targetActor != null) ? targetActor.IsEvasive : false, false); } if (toHit < Epsilon) { record.HeatDamageCoeff = 0f; record.NormDamageCoeff = 0f; record.PredictHeatDamage = 0f; } ; float coolDownCoeff = 1.0f / (1.0f + CustomAmmoCategories.getWeaponCooldown(weapon)); float jammCoeff = 1.0f - CustomAmmoCategories.getWeaponFlatJammingChance(weapon); float damageJammCoeff = CustomAmmoCategories.getWeaponDamageOnJamming(weapon) ? 0.5f : 1.0f; float damageShotsCount = (float)weapon.ShotsWhenFired; float damagePerShot = weapon.DamagePerShot; float heatPerShot = weapon.HeatDamagePerShot; if (weapon.componentDef.ComponentTags.Contains("wr-clustered_shots") || (CustomAmmoCategories.getWeaponDisabledClustering(weapon) == false)) { damageShotsCount *= (float)weapon.ProjectilesPerShot; } float piercedLocationsCount = (float)CustomAmmoCategories.getWeaponPierceLocations(hitLocations, target, damagePerShot); float hitLocationsCount = (hitLocations.Count > 0) ? (float)hitLocations.Count : 1.0f; float clusterCoeff = 1.0f + ((piercedLocationsCount / hitLocationsCount) * damageShotsCount) * CustomAmmoCategories.Settings.ClusterAIMult; float pierceCoeff = 1.0f; if (AverageArmor > damagePerShot) { pierceCoeff += (damagePerShot / AverageArmor) * CustomAmmoCategories.Settings.PenetrateAIMult; } record.NormDamageCoeff = damagePerShot * damageShotsCount * toHit * coolDownCoeff * jammCoeff * damageJammCoeff * clusterCoeff * pierceCoeff; record.HeatDamageCoeff = heatPerShot * damageShotsCount * toHit * jammCoeff * damageJammCoeff; record.PredictHeatDamage = heatPerShot * damageShotsCount * toHit; CustomAmmoCategoriesLog.Log.LogWrite(" toHit = " + toHit + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" coolDownCoeff = " + coolDownCoeff + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" jammCoeff = " + jammCoeff + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" damageJammCoeff = " + damageJammCoeff + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" damageShotsCount = " + damageShotsCount + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" damagePerShot = " + damagePerShot + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" heatPerShot = " + heatPerShot + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" piercedLocationsCount = " + piercedLocationsCount + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" hitLocationsCount = " + hitLocationsCount + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" AverageArmor = " + AverageArmor + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" clusterCoeff = " + clusterCoeff + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" pierceCoeff = " + pierceCoeff + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" NormDamageCoeff = " + record.NormDamageCoeff + "\n"); CustomAmmoCategoriesLog.Log.LogWrite(" HeatDamageCoeff = " + record.HeatDamageCoeff + "\n"); }