public static bool trySwapToMoreAccurateRangedWeapon(Pawn pawn, LocalTargetInfo target, bool dropCurrent, bool skipManualUse, bool skipDangerous = true, bool skipEMP = true) { CompSidearmMemory pawnMemory = CompSidearmMemory.GetMemoryCompForPawn(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, skipManualUse, skipDangerous, skipEMP, 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, Settings.SpeedSelectionBiasRanged, bestWeapon.averageSpeed, range); if (bestWeapon.dps < currentDPS + MiscUtils.ANTI_OSCILLATION_FACTOR) { return(false); } equipSpecificWeaponFromInventory(pawn, bestWeapon.weapon, dropCurrent, false); return(true); }
// Verse.Verb // Token: 0x060022E2 RID: 8930 RVA: 0x000D4A4C File Offset: 0x000D2C4C public new bool TryFindShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine) { if (targ.HasThing && targ.Thing.Map != this.Caster.Map) { resultingLine = default(ShootLine); return(false); } if (this.verbProps.IsMeleeAttack || this.EffectiveRange <= 1.42f) { resultingLine = new ShootLine(root, targ.Cell); return(ReachabilityImmediate.CanReachImmediate(root, targ, this.Caster.Map, PathEndMode.Touch, null)); } CellRect cellRect = targ.HasThing ? targ.Thing.OccupiedRect() : CellRect.SingleCell(targ.Cell); float num = this.verbProps.EffectiveMinRange(targ, this.Caster); float num2 = cellRect.ClosestDistSquaredTo(root); if (num2 > this.EffectiveRange * this.EffectiveRange || num2 < num * num) { resultingLine = new ShootLine(root, targ.Cell); return(false); } if (!this.verbProps.requireLineOfSight) { resultingLine = new ShootLine(root, targ.Cell); return(true); } if (this.CasterIsPawn) { if (this.CanHitFromCellIgnoringRange(root, targ, out IntVec3 dest)) { resultingLine = new ShootLine(root, dest); return(true); } ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), this.Caster.Map, Verb_ShootCompMountedCE.tempLeanShootSources); for (int i = 0; i < Verb_ShootCompMountedCE.tempLeanShootSources.Count; i++) { IntVec3 intVec = Verb_ShootCompMountedCE.tempLeanShootSources[i]; if (this.CanHitFromCellIgnoringRange(intVec, targ, out dest)) { resultingLine = new ShootLine(intVec, dest); return(true); } } } else { IntVec2 size = new IntVec2(Caster.def.size.x + 1, Caster.def.size.z + 1); foreach (IntVec3 intVec2 in GenAdj.OccupiedRect(Caster.Position, Caster.Rotation, size)) { if (this.CanHitFromCellIgnoringRange(intVec2, targ, out IntVec3 dest)) { resultingLine = new ShootLine(intVec2, dest); return(true); } } } resultingLine = new ShootLine(root, targ.Cell); return(false); }
public bool TryFindCEShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine) { if (targ.HasThing && targ.Thing.Map != caster.Map) { resultingLine = default(ShootLine); return(false); } if (verbProps.range <= ShootTuning.MeleeRange) // If this verb has a MAX range up to melee range (NOT a MIN RANGE!) { resultingLine = new ShootLine(root, targ.Cell); return(ReachabilityImmediate.CanReachImmediate(root, targ, caster.Map, PathEndMode.Touch, null)); } CellRect cellRect = (!targ.HasThing) ? CellRect.SingleCell(targ.Cell) : targ.Thing.OccupiedRect(); float num = cellRect.ClosestDistSquaredTo(root); if (num > verbProps.range * verbProps.range || num < verbProps.minRange * verbProps.minRange) { resultingLine = new ShootLine(root, targ.Cell); return(false); } //if (!this.verbProps.NeedsLineOfSight) This method doesn't consider the currently loaded projectile if (Projectile.projectile.flyOverhead) { resultingLine = new ShootLine(root, targ.Cell); return(true); } // First check current cell for early opt-out IntVec3 dest; var shotSource = root.ToVector3Shifted(); shotSource.y = ShotHeight; if (CanHitFromCellIgnoringRange(shotSource, targ, out dest)) { resultingLine = new ShootLine(root, dest); return(true); } // For pawns, calculate possible lean locations if (CasterIsPawn) { // Next check lean sources ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), caster.Map, tempLeanShootSources); foreach (var leanLoc in tempLeanShootSources) { var leanOffset = (leanLoc - root).ToVector3() * 0.5f; if (CanHitFromCellIgnoringRange(shotSource + leanOffset, targ, out dest)) { resultingLine = new ShootLine(leanLoc, dest); return(true); } } } resultingLine = new ShootLine(root, targ.Cell); return(false); }
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); } }
private static void StanceTick(Stance_Warmup __instance) { if (SimpleSidearms.RangedCombatAutoSwitch == false) { return; } Pawn pawn = __instance.stanceTracker.pawn; if (SwapControlsHandler.GetHandlerForPawn(pawn).currentWeaponLocked) { return; } if (IsHunting(pawn)) { return; } if (!SimpleSidearms.CEOverride && !(__instance.verb is Verb_Shoot)) { return; } if (SimpleSidearms.CEOverride && !(CERangedVerb.IsAssignableFrom(__instance.verb.GetType()))) { return; } float statValue = pawn.GetStatValue(StatDefOf.AimingDelayFactor, true); int ticks = (__instance.verb.verbProps.warmupTime * statValue).SecondsToTicks(); if (__instance.ticksLeft / (float)ticks < 1f - SimpleSidearms.RangedCombatAutoSwitchMaxWarmup.Value) { return; } LocalTargetInfo targ = __instance.focusTarg; if (pawn.inventory.innerContainer.Any((Thing x) => x.def.IsRangedWeapon)) { CellRect cellRect = (!targ.HasThing) ? CellRect.SingleCell(targ.Cell) : targ.Thing.OccupiedRect(); float range = cellRect.ClosestDistSquaredTo(pawn.Position); WeaponAssingment.trySwapToMoreAccurateRangedWeapon(pawn, MiscUtils.shouldDrop(DroppingModeEnum.Range), range, pawn.IsColonistPlayerControlled); } else { } }
/* * public bool CanSeeTarget(LocalTargetInfo targ) * { * var glow = targ.Thing.Map.glowGrid.GameGlowAt(targ.Cell); * var glowmultiplier = Mathf.Lerp(1, 5, Mathf.Clamp(glow * 5f, 0f, 1f)); * * float lengthToTarget = Mathf.Abs((targ.Cell - caster.Position).LengthHorizontal); * if (targ.Thing.Map.glowGrid.GameGlowAt(targ.Cell) <= 0.2f) * { * Log.Message("target: " + targ.Thing + " glow: " + glow.ToString() + " glowmult: " + glowmultiplier.ToString()); * if (lengthToTarget > glowmultiplier) * { * Log.Message("cant see: " + targ.Thing.ToString()); * return false; * } * } * return true; * } */ public bool TryFindCEShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine) { // Log.Message("root: " + root.ToString() + " target: " + targ.Thing.ToString() + " pos: " + targ.Cell.ToString()); if (targ.HasThing && targ.Thing.Map != this.caster.Map) { resultingLine = default(ShootLine); // Log.Message("shootline false: 1" + " line: " + resultingLine.ToString()); return(false); } // Log.Message("effminrange: " + this.verbProps.EffectiveMinRange(targ, this.caster).ToString() + " meleerange: " + ShootTuning.MeleeRange); if (this.verbProps.IsMeleeAttack) { resultingLine = new ShootLine(root, targ.Cell); var ri = ReachabilityImmediate.CanReachImmediate(root, targ, this.caster.Map, PathEndMode.Touch, null); // Log.Message("ri: " + ri.ToString() + " line: " + resultingLine.ToString()); return(ri); } CellRect cellRect = (!targ.HasThing) ? CellRect.SingleCell(targ.Cell) : targ.Thing.OccupiedRect(); float num = cellRect.ClosestDistSquaredTo(root); if (num > this.verbProps.range * this.verbProps.range || num < this.verbProps.minRange * this.verbProps.minRange) { resultingLine = new ShootLine(root, targ.Cell); // Log.Message("shootline false: 2" + " line: " + resultingLine.ToString()); return(false); } //if (!this.verbProps.NeedsLineOfSight) This method doesn't consider the currently loaded projectile if (Projectile.projectile.flyOverhead) { resultingLine = new ShootLine(root, targ.Cell); // Log.Message("shootline true: 3" + " line: " + resultingLine.ToString()); return(true); } if (this.CasterIsPawn) { IntVec3 dest; ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), this.caster.Map, tempLeanShootSources); if (tempLeanShootSources.Count < 2) { if (this.CanHitFromCellIgnoringRange(root, root, targ, out dest)) { resultingLine = new ShootLine(root, dest); // Log.Message("shootline true: 4" + " line: " + resultingLine.ToString()); return(true); } } if (tempLeanShootSources.Count >= 2) { int bestZ = 0; int bestX = 0; int cachedbz = -1; int cachedbx = -1; // Log.Message("pawn: " + CasterPawn.ToString() + " pawn pos: " + root.ToString() + " target: " + targ.Thing.ToString() + " target pos: " + targ.Cell.ToString()); foreach (var bsp in tempLeanShootSources) { var bz = Mathf.Abs(bsp.z - targ.Cell.z); if (cachedbz < 0 || (bz < cachedbz)) { cachedbz = bz; bestZ = bsp.z; } var bx = Mathf.Abs(bsp.x - targ.Cell.x); if (cachedbx < 0 || (bx < cachedbx)) { cachedbx = bx; bestX = bsp.x; } } bestshootposition = new IntVec3(bestX, root.y, bestZ); // Log.Message("bestshootposition: " + bestshootposition.ToString()); if (this.CanHitFromCellIgnoringRange(bestshootposition, root, targ, out dest)) { resultingLine = new ShootLine(bestshootposition, dest); // Log.Message("shootline true: 5" + " line: " + resultingLine.ToString()); return(true); } } else { for (int i = 0; i < tempLeanShootSources.Count; i++) { IntVec3 intVec = tempLeanShootSources[i]; if (this.CanHitFromCellIgnoringRange(intVec, root, targ, out dest)) { resultingLine = new ShootLine(intVec, dest); // Log.Message("shootline true: 6" + " line: " + resultingLine.ToString()); return(true); } } } } else { CellRect.CellRectIterator iterator = this.caster.OccupiedRect().GetIterator(); while (!iterator.Done()) { IntVec3 current = iterator.Current; IntVec3 dest; if (this.CanHitFromCellIgnoringRange(current, root, targ, out dest)) { resultingLine = new ShootLine(current, dest); // Log.Message("shootline true: 7: " + " line: " + resultingLine.ToString()); return(true); } iterator.MoveNext(); } } resultingLine = new ShootLine(root, targ.Cell); // Log.Message("shootline false: 8" + " line: " + resultingLine.ToString()); return(false); }
public static bool TryFindShootLineFromTo(Verb __instance, ref bool __result, IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine) { if (targ.HasThing && targ.Thing.Map != __instance.caster.Map) { resultingLine = default; __result = false; return(false); } if (__instance.verbProps.IsMeleeAttack || __instance.verbProps.range <= 1.42f) { resultingLine = new ShootLine(root, targ.Cell); __result = ReachabilityImmediate.CanReachImmediate(root, targ, __instance.caster.Map, PathEndMode.Touch, null); return(false); } CellRect cellRect = targ.HasThing ? targ.Thing.OccupiedRect() : CellRect.SingleCell(targ.Cell); float num = __instance.verbProps.EffectiveMinRange(targ, __instance.caster); float num2 = cellRect.ClosestDistSquaredTo(root); if (num2 > __instance.verbProps.range * __instance.verbProps.range || num2 < num * num) { resultingLine = new ShootLine(root, targ.Cell); __result = false; return(false); } if (!__instance.verbProps.requireLineOfSight) { resultingLine = new ShootLine(root, targ.Cell); __result = true; return(false); } IntVec3 goodDest; if (__instance.CasterIsPawn) { if (CanHitFromCellIgnoringRange2(__instance, root, targ, out goodDest)) { resultingLine = new ShootLine(root, goodDest); __result = true; return(false); } List <IntVec3> tempLeanShootSources = new List <IntVec3>(); //ADDED ShootLeanUtility.LeanShootingSourcesFromTo( root, cellRect.ClosestCellTo(root), __instance.caster.Map, tempLeanShootSources); //CHANGED tempLeanShootSources for (int i = 0; i < tempLeanShootSources.Count; i++) //CHANGED tempLeanShootSources { IntVec3 intVec = tempLeanShootSources[i]; //CHANGED tempLeanShootSources if (CanHitFromCellIgnoringRange2(__instance, intVec, targ, out goodDest)) { resultingLine = new ShootLine(intVec, goodDest); __result = true; return(false); } } } else { foreach (IntVec3 item in __instance.caster.OccupiedRect()) { if (CanHitFromCellIgnoringRange2(__instance, item, targ, out goodDest)) { resultingLine = new ShootLine(item, goodDest); __result = true; return(false); } } } resultingLine = new ShootLine(root, targ.Cell); __result = false; return(false); }
public static (ThingWithComps weapon, float dps, float averageSpeed) findBestRangedWeapon(Pawn pawn, LocalTargetInfo?target = null, bool skipManualUse = true, bool skipDangerous = true, bool skipEMP = 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 => t.def.IsRangedWeapon); if (!Settings.AllowBlockedWeaponUse) { options = options.Where(t => StatCalculator.canUseSidearmInstance(t, pawn, out _)); } options = options.Where(t => !pawn.IsColonistPlayerControlled || !isManualUse(t)); if (skipManualUse) { options = options.Where(t => (!isManualUse(t))); } if (skipDangerous) { options = options.Where(t => (!isDangerousWeapon(t))); } if (skipEMP) { options = options.Where(t => !isEMPWeapon(t)); } if (options.Count() == 0) { return(null, -1, 0); } float averageSpeed = AverageSpeedRanged(options); if (target.HasValue) { CellRect cellRect = (!target.Value.HasThing) ? CellRect.SingleCell(target.Value.Cell) : target.Value.Thing.OccupiedRect(); float targetDistance = cellRect.ClosestDistSquaredTo(pawn.Position); options = options.Where(t => { VerbProperties atkProps = (t.GetComp <CompEquippable>())?.PrimaryVerb?.verbProps; if (atkProps == null) { return(false); } return(atkProps.range >= targetDistance); }); if (options.Count() == 0) { return(null, -1, 0); } //TODO: handle DPS vs. armor? (ThingWithComps thing, float dps, float averageSpeed)best = (null, -1, averageSpeed); foreach (ThingWithComps candidate in options) { float dps = StatCalculator.RangedDPS(candidate, Settings.SpeedSelectionBiasRanged, averageSpeed, targetDistance); 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, Settings.SpeedSelectionBiasRanged, averageSpeed); if (dps > best.dps) { best = (candidate, dps, averageSpeed); } } return(best); } }
public bool TryFindCEShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine) { if (targ.HasThing && targ.Thing.Map != this.caster.Map) { resultingLine = default(ShootLine); return(false); } if (this.verbProps.range <= ShootTuning.MeleeRange) // If this verb has a MAX range up to melee range (NOT a MIN RANGE!) { resultingLine = new ShootLine(root, targ.Cell); return(ReachabilityImmediate.CanReachImmediate(root, targ, this.caster.Map, PathEndMode.Touch, null)); } CellRect cellRect = (!targ.HasThing) ? CellRect.SingleCell(targ.Cell) : targ.Thing.OccupiedRect(); float num = cellRect.ClosestDistSquaredTo(root); if (num > this.verbProps.range * this.verbProps.range || num < this.verbProps.minRange * this.verbProps.minRange) { resultingLine = new ShootLine(root, targ.Cell); return(false); } //if (!this.verbProps.NeedsLineOfSight) This method doesn't consider the currently loaded projectile if (Projectile.projectile.flyOverhead) { resultingLine = new ShootLine(root, targ.Cell); return(true); } if (this.CasterIsPawn) { IntVec3 dest; if (this.CanHitFromCellIgnoringRange(root, targ, out dest)) { resultingLine = new ShootLine(root, dest); return(true); } ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), this.caster.Map, tempLeanShootSources); for (int i = 0; i < tempLeanShootSources.Count; i++) { IntVec3 intVec = tempLeanShootSources[i]; if (this.CanHitFromCellIgnoringRange(intVec, targ, out dest)) { resultingLine = new ShootLine(intVec, dest); return(true); } } } else { CellRect.CellRectIterator iterator = this.caster.OccupiedRect().GetIterator(); while (!iterator.Done()) { IntVec3 current = iterator.Current; IntVec3 dest; if (this.CanHitFromCellIgnoringRange(current, targ, out dest)) { resultingLine = new ShootLine(current, dest); return(true); } iterator.MoveNext(); } } resultingLine = new ShootLine(root, targ.Cell); return(false); }
public new bool TryFindShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine) { // Log.Message("Verb_MeleeAttackDamage_Polearm TryFindShootLineFromTo"); if (targ.HasThing && targ.Thing.Map != this.caster.Map) { resultingLine = default(ShootLine); return(false); } /* * if (this.verbProps.IsMeleeAttack || this.EffectiveRange <= 1.42f) * { * resultingLine = new ShootLine(root, targ.Cell); * * return this.CanReachImmediate(root, targ, this.caster.Map, PathEndMode.Touch, null); * } */ CellRect cellRect = targ.HasThing ? targ.Thing.OccupiedRect() : CellRect.SingleCell(targ.Cell); float num = this.verbProps.EffectiveMinRange(targ, this.caster); float num2 = cellRect.ClosestDistSquaredTo(root); if (num2 > this.EffectiveRange * this.EffectiveRange || num2 < num * num) { resultingLine = new ShootLine(root, targ.Cell); return(false); } if (!this.verbProps.requireLineOfSight) { resultingLine = new ShootLine(root, targ.Cell); return(true); } if (this.CasterIsPawn) { if (this.CanHitFromCellIgnoringRange(root, targ, out IntVec3 dest)) { resultingLine = new ShootLine(root, dest); return(true); } ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), this.caster.Map, Verb_MeleeAttackDamage_Polearm.tempLeanShootSources); for (int i = 0; i < Verb_MeleeAttackDamage_Polearm.tempLeanShootSources.Count; i++) { IntVec3 intVec = Verb_MeleeAttackDamage_Polearm.tempLeanShootSources[i]; if (this.CanHitFromCellIgnoringRange(intVec, targ, out dest)) { resultingLine = new ShootLine(intVec, dest); return(true); } } } else { foreach (IntVec3 intVec2 in this.caster.OccupiedRect()) { if (this.CanHitFromCellIgnoringRange(intVec2, targ, out IntVec3 dest)) { resultingLine = new ShootLine(intVec2, dest); return(true); } } } resultingLine = new ShootLine(root, targ.Cell); return(false); }
public bool TryFindCEShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine) { if (targ.HasThing && targ.Thing.Map != caster.Map) { resultingLine = default(ShootLine); return(false); } if (verbProps.range <= ShootTuning.MeleeRange) // If this verb has a MAX range up to melee range (NOT a MIN RANGE!) { resultingLine = new ShootLine(root, targ.Cell); return(ReachabilityImmediate.CanReachImmediate(root, targ, caster.Map, PathEndMode.Touch, null)); } CellRect cellRect = (!targ.HasThing) ? CellRect.SingleCell(targ.Cell) : targ.Thing.OccupiedRect(); float num = cellRect.ClosestDistSquaredTo(root); if (num > verbProps.range * verbProps.range || num < verbProps.minRange * verbProps.minRange) { resultingLine = new ShootLine(root, targ.Cell); return(false); } //if (!this.verbProps.NeedsLineOfSight) This method doesn't consider the currently loaded projectile if (Projectile.projectile.flyOverhead) { resultingLine = new ShootLine(root, targ.Cell); return(true); } // First check current cell for early opt-out IntVec3 dest; var shotSource = root.ToVector3Shifted(); shotSource.y = ShotHeight; // Adjust for multi-tile turrets if (caster.def.building?.IsTurret ?? false) { shotSource = ShotSource; } if (CanHitFromCellIgnoringRange(shotSource, targ, out dest)) { resultingLine = new ShootLine(root, dest); return(true); } // For pawns, calculate possible lean locations if (CasterIsPawn) { ShootLeanUtility.LeanShootingSourcesFromTo(root, cellRect.ClosestCellTo(root), caster.Map, tempLeanShootSources); foreach (var leanLoc in tempLeanShootSources.OrderBy(c => c.DistanceTo(targ.Cell))) { var leanOffset = (leanLoc - root).ToVector3() * 0.51f; //using exactly 0.5f makes it always round up, which causes issues if offset is negative, when adding leanOffset to shotSource. Setting to 0.51f to fix. if (CanHitFromCellIgnoringRange(shotSource + leanOffset, targ, out dest)) { resultingLine = new ShootLine(leanLoc, dest); return(true); } } } resultingLine = new ShootLine(root, targ.Cell); return(false); }