internal static ThingWithComps findBestRangedWeaponAtRanged(Pawn pawn, float range, bool skipDangerous, out float resultDPS) { List <Thing> weapons; weapons = getWeaponsOfType(pawn, WeaponSearchType.Ranged); float bestSoFar = float.MinValue; Thing best = null; foreach (Thing thing in weapons) { if (!(thing is ThingWithComps)) { continue; } if (skipDangerous) { if (isDangerousWeapon(thing as ThingWithComps)) { continue; } } float DPS = StatCalculator.RangedDPS(thing as ThingWithComps, SpeedSelectionBiasRanged.Value, range); if (DPS > bestSoFar) { bestSoFar = DPS; best = thing; } } resultDPS = bestSoFar; return(best as ThingWithComps); }
internal static bool trySwapToMoreAccurateRangedWeapon(Pawn pawn, bool dropCurrent, float range, bool skipDangerous) { if (pawn.Dead) return false; Thing betterWeapon = null; float betterDPS; if (pawn.inventory.innerContainer.Any((Thing x) => x.def.IsRangedWeapon)) { betterWeapon = GettersFilters.findBestRangedWeaponAtRanged(pawn, range, skipDangerous, out betterDPS); } else { return false; } if (betterWeapon == null) return false; float currentDPS = StatCalculator.RangedDPS(pawn.equipment.Primary, SpeedSelectionBiasRanged.Value, range); if (betterDPS < currentDPS + ANTI_OSCILLATION_FACTOR) return false; if (betterWeapon is ThingWithComps) { SetPrimary(pawn, betterWeapon, false, true, dropCurrent, false); return true; } return false; }
public static bool trySwapToMoreAccurateRangedWeapon(Pawn pawn, LocalTargetInfo target, bool dropCurrent, bool skipDangerous = true) { GoldfishModule pawnMemory = GoldfishModule.GetGoldfishForPawn(pawn); if (pawn == null || pawn.Dead || pawnMemory == null || pawn.equipment == null || pawn.inventory == null) { return(false); } if (pawnMemory.IsCurrentWeaponForced(false)) { return(false); } (ThingWithComps weapon, float dps, float averageSpeed)bestWeapon = GettersFilters.findBestRangedWeapon(pawn, target, skipDangerous, true); if (bestWeapon.weapon == null) { return(false); } CellRect cellRect = (!target.HasThing) ? CellRect.SingleCell(target.Cell) : target.Thing.OccupiedRect(); float range = cellRect.ClosestDistSquaredTo(pawn.Position); float currentDPS = StatCalculator.RangedDPS(pawn.equipment.Primary, SpeedSelectionBiasRanged.Value, bestWeapon.averageSpeed, range); if (bestWeapon.dps < currentDPS + ANTI_OSCILLATION_FACTOR) { return(false); } equipSpecificWeaponFromInventory(pawn, bestWeapon.weapon, dropCurrent, false); return(true); }
internal static ThingWithComps findBestMeleeWeapon(Pawn pawn, bool skipDangerous /*, SelectionMode mode*/, Pawn target) { List <Thing> weapons = getWeaponsOfType(pawn, WeaponSearchType.MeleeCapable); if (pawn.equipment != null && pawn.equipment.Primary != null) { weapons.Add(pawn.equipment.Primary); } weapons.Add(null); //for considering unarmed attacks /*string candList = ""; * foreach (Thing thing in weapons) * candList += (thing == null) ? " unarmed" : " " + thing.def.defName; * Log.Message("Considering melee swap, candidates:"+candList);*/ Thing best = null; float bestSoFar = float.MinValue; foreach (Thing thing in weapons) { if (skipDangerous) { if (isDangerousWeapon(thing as ThingWithComps)) { continue; } } float dpsAvg = -1f; dpsAvg = StatCalculator.MeleeDPS(pawn, thing as ThingWithComps, SpeedSelectionBiasMelee.Value, target); /*if(thing == null) * Log.Message("DPS for unarmed is " + dpsAvg); * else * Log.Message("DPS for " + thing.def.defName + " is " + dpsAvg);*/ if (dpsAvg > bestSoFar) { bestSoFar = dpsAvg; best = thing; } } /*if (best == null) * Log.Message("best: unarmed"); * else * Log.Message("best: " + best.def.defName);*/ return(best as ThingWithComps); }
public static (ThingWithComps weapon, float dps, float averageSpeed) findBestRangedWeapon(Pawn pawn, LocalTargetInfo?target = null, bool skipDangerous = true, bool includeEquipped = true) { if (pawn == null || pawn.Dead || pawn.equipment == null || pawn.inventory == null) { return(null, -1, 0); } IEnumerable <ThingWithComps> options = pawn.getCarriedWeapons(includeEquipped).Where(t => { return(t.def.IsRangedWeapon); }); if (options.Count() == 0) { return(null, -1, 0); } float averageSpeed = AverageSpeedRanged(options); if (target.HasValue) { //TODO: handle DPS vs. armor? CellRect cellRect = (!target.Value.HasThing) ? CellRect.SingleCell(target.Value.Cell) : target.Value.Thing.OccupiedRect(); float range = cellRect.ClosestDistSquaredTo(pawn.Position); (ThingWithComps thing, float dps, float averageSpeed)best = (null, -1, averageSpeed); foreach (ThingWithComps candidate in options) { float dps = StatCalculator.RangedDPS(candidate, SpeedSelectionBiasRanged.Value, averageSpeed, range); if (dps > best.dps) { best = (candidate, dps, averageSpeed); } } return(best); } else { (ThingWithComps thing, float dps, float averageSpeed)best = (null, -1, averageSpeed); foreach (ThingWithComps candidate in options) { float dps = StatCalculator.RangedDPSAverage(candidate, SpeedSelectionBiasRanged.Value, averageSpeed); if (dps > best.dps) { best = (candidate, dps, averageSpeed); } } return(best); } }
internal static bool trySwapToMoreAccurateRangedWeapon(Pawn pawn, bool dropCurrent, float range, bool skipDangerous) { //Log.Message("attempting swap"); if (pawn.Dead) { return(false); } Thing betterWeapon = null; float betterDPS; //Log.Message("looking for ranged weapon in inventory"); if (pawn.inventory.innerContainer.Any((Thing x) => x.def.IsRangedWeapon)) { //Log.Message("found ranged weapon in inventory"); betterWeapon = GettersFilters.findBestRangedWeaponAtRanged(pawn, range, skipDangerous, out betterDPS); } else { return(false); } if (betterWeapon == null) { return(false); } float currentDPS = StatCalculator.RangedDPS(pawn.equipment.Primary, SpeedSelectionBiasRanged.Value, range); //Log.Message("current DPS is "+currentDPS+ " ("+pawn.equipment.Primary.LabelShort+")"); //Log.Message("best sidearm DPS is " + betterDPS + " (" + betterWeapon.LabelShort + ")"); if (betterDPS < currentDPS + ANTI_OSCILLATION_FACTOR) { return(false); } //Log.Message("sorted out best (" + best.LabelShort + ")"); if (betterWeapon is ThingWithComps) { //Log.Message("converted to ThingWithComps"); SetPrimary(pawn, betterWeapon, false, true, dropCurrent, false); return(true); } return(false); }
public static float AverageSpeedMelee(IEnumerable <Thing> options, Pawn pawn) { int i = 0; float total = 0; foreach (Thing thing in options) { total += StatCalculator.MeleeSpeed(thing as ThingWithComps, pawn); i++; } if (i > 0) { return(total / i); } else { return(0); } }
internal static ThingWithComps findBestMeleeWeapon(Pawn pawn, bool skipDangerous /*, SelectionMode mode*/, Pawn target) { List <Thing> weapons = getWeaponsOfType(pawn, WeaponSearchType.Melee); Thing best = pawn.equipment.Primary; float bestSoFar = best == null ? float.MinValue : StatCalculator.MeleeDPS(pawn, best as ThingWithComps, SpeedSelectionBiasMelee.Value, target); foreach (Thing thing in weapons) { if (!(thing is ThingWithComps)) { continue; } if (skipDangerous) { if (isDangerousWeapon(thing as ThingWithComps)) { continue; } } float dpsAvg = -1f; dpsAvg = StatCalculator.MeleeDPS(pawn, thing as ThingWithComps, SpeedSelectionBiasMelee.Value, target); if (dpsAvg > bestSoFar) { bestSoFar = dpsAvg; best = thing; } } if (StatCalculator.MeleeDPS(pawn, null, SpeedSelectionBiasMelee.Value, target) > bestSoFar) { best = null; } return(best as ThingWithComps); }
public static bool findBestMeleeWeapon(Pawn pawn, out ThingWithComps result, bool includeEquipped = true, bool includeRangedWithBash = true, Pawn target = null) { result = null; if (pawn == null || pawn.Dead || pawn.equipment == null || pawn.inventory == null) { return(false); } IEnumerable <Thing> options = pawn.getCarriedWeapons(includeEquipped).Where(t => { return (t.def.IsMeleeWeapon || (includeRangedWithBash && t.def.IsWeapon && !t.def.tools.NullOrEmpty())); }); if (options.Count() < 1) { return(false); } float averageSpeed = AverageSpeedMelee(options, pawn); /*if (target != null) * { * //handle DPS vs. armor? * } * else*/ { float resultDPS = options.Max(t => StatCalculator.getMeleeDPSBiased(t as ThingWithComps, pawn, SpeedSelectionBiasMelee.Value, averageSpeed)); result = options.MaxBy(t => StatCalculator.getMeleeDPSBiased(t as ThingWithComps, pawn, SpeedSelectionBiasMelee.Value, averageSpeed)) as ThingWithComps; //check if pawn is better when punching if (pawn.GetStatValue(StatDefOf.MeleeDPS) > resultDPS) { result = null; } return(true); } }
internal static ThingWithComps findBestRangedWeapon(Pawn pawn, bool skipDangerous /*, SelectionMode mode*/) { List <Thing> weapons = getWeaponsOfType(pawn, WeaponSearchType.Ranged); float bestSoFar = float.MinValue; Thing best = null; foreach (Thing thing in weapons) { if (!(thing is ThingWithComps)) { continue; } if (skipDangerous) { if (isDangerousWeapon(thing as ThingWithComps)) { continue; } } float dpsAvg = -1f; if (thing.def.IsRangedWeapon) { dpsAvg = StatCalculator.RangedDPSAverage(thing as ThingWithComps, SpeedSelectionBiasRanged.Value); } if (dpsAvg > bestSoFar) { bestSoFar = dpsAvg; best = thing; } } return(best as ThingWithComps); }
internal static ThingWithComps findBestMeleeWeapon(Pawn pawn, bool skipDangerous, out bool unarmedIsBetter /*, SelectionMode mode*/) { List <Thing> weapons = getWeaponsOfType(pawn, WeaponSearchType.Melee); float bestSoFar = float.MinValue; Thing best = null; foreach (Thing thing in weapons) { if (!(thing is ThingWithComps)) { continue; } if (skipDangerous) { if (isDangerousWeapon(thing as ThingWithComps)) { continue; } } float dpsAvg = -1f; dpsAvg = StatCalculator.MeleeDPS(pawn, thing as ThingWithComps, SpeedSelectionBiasMelee.Value); if (dpsAvg > bestSoFar) { bestSoFar = dpsAvg; best = thing; } } unarmedIsBetter = StatCalculator.UnarmedDPS(pawn, SpeedSelectionBiasMelee.Value) > bestSoFar; return(best as ThingWithComps); }
public static IEnumerable <ThingStuffPair> getValidSidearms() { return(getValidWeapons().Where(w => StatCalculator.isValidSidearm(w, out _))); }