private void BuildFireCone() { _fireCone = null; var pawn = Main.GetSelectedPawn(); if (pawn == null) { return; } if (!HasValidWeapon(pawn)) { return; } var targetCell = UI.MouseCell(); var pawnCell = pawn.Position; if (pawnCell.DistanceTo(targetCell) > GetEquippedWeaponRange(pawn)) { return; } var fireProperties = new FireProperties(pawn, targetCell); _fireCone = FireCalculations.GetFireCone(fireProperties); }
private HashSet <int> GetOrCreatedCachedFireConeFor(FireProperties fireProperties) { var originIndex = fireProperties.OriginIndex; var targetIndex = fireProperties.TargetIndex; if (_cachedFireCones.TryGetValue(originIndex, out var cachedFireConesFromOrigin)) { if (cachedFireConesFromOrigin.TryGetValue(targetIndex, out var cachedFireCone)) { if (!cachedFireCone.IsExpired()) { cachedFireCone.Prolong(); return(cachedFireCone.FireCone); } } } // No cached firecone, create one var newFireCone = new CachedFireCone(FireCalculations.GetFireCone(fireProperties)); if (!_cachedFireCones.ContainsKey(originIndex)) { _cachedFireCones.Add(originIndex, new Dictionary <int, CachedFireCone>()); } _cachedFireCones[originIndex][targetIndex] = newFireCone; return(newFireCone.FireCone); }
public static HashSet <int> GetFireCone(FireProperties fireProperties) { if (!fireProperties.ArePointsVisibleAndValid()) { return(null); } fireProperties.AdjustForLeaning(); var missAreaDescriptor = fireProperties.GetMissAreaDescriptor(); var result = new HashSet <int>(); result.Clear(); var map = Find.CurrentMap; for (var i = 0; i < missAreaDescriptor.AdjustmentCount; i++) { var splashTarget = fireProperties.Target + missAreaDescriptor.AdjustmentVector[i]; result.UnionWith(GetShootablePointsBetween(fireProperties.Origin, splashTarget, map)); } return(result); }
public static bool HasValidWeapon(Pawn pawn) { var primaryWeaponVerb = FireProperties.GetEquippedWeaponVerb(pawn); if (primaryWeaponVerb?.verbProps?.defaultProjectile?.projectile == null) { return(false); } if (primaryWeaponVerb.verbProps.defaultProjectile.projectile.explosionRadius > 0.2f) { // Can't handle explosive projectiles yet return(false); } // TODO check if projectile is flyOverhead return(true); }
public static float GetEquippedWeaponRange(Pawn pawn) { var primaryWeaponVerb = FireProperties.GetEquippedWeaponVerb(pawn); return(primaryWeaponVerb?.verbProps.range ?? 0); }
public bool CanHitTargetSafely(FireProperties fireProperties) { if (SkipNextCheck) { SkipNextCheck = false; return(true); } Main.Instance.PawnStatusTracker.Remove(fireProperties.Caster); HashSet <int> fireCone = GetOrCreatedCachedFireConeFor(fireProperties); if (fireCone == null) { return(true); } var map = fireProperties.CasterMap; foreach (var pawn in map.mapPawns.AllPawns) { if (pawn?.RaceProps == null || pawn.Dead) { continue; } if (pawn.Faction == null) { continue; } if (pawn.RaceProps.Humanlike) { if (pawn.IsPrisoner) { continue; } if (pawn.HostileTo(Faction.OfPlayer)) { continue; } } else if (!ShouldProtectAnimal(pawn)) { continue; } var pawnCell = pawn.Position; if (pawnCell == fireProperties.Origin || pawnCell == fireProperties.Target) { continue; } var pawnIndex = map.cellIndices.CellToIndex(pawnCell); if (!fireCone.Contains(pawnIndex)) { continue; } if (IsPawnWearingUsefulShield(pawn)) { continue; } Main.Instance.PawnStatusTracker.AddBlockedShooter(fireProperties.Caster, pawn); return(false); } return(true); }