public static bool BestAttackTarget(ref IAttackTarget __result, IAttackTargetSearcher searcher, TargetScanFlags flags, Predicate <Thing> validator = null, float minDist = 0f, float maxDist = 9999f, IntVec3 locus = default(IntVec3), float maxTravelRadiusFromLocus = 3.40282347E+38f, bool canBash = false, bool canTakeTargetsCloserThanEffectiveMinRange = true) { Thing searcherThing = searcher.Thing; Pawn searcherPawn = searcher as Pawn; Verb verb = searcher.CurrentEffectiveVerb; if (verb == null) { Log.Error("BestAttackTarget with " + searcher.ToStringSafe <IAttackTargetSearcher>() + " who has no attack verb.", false); __result = null; return(false); } bool onlyTargetMachines = verb.IsEMP(); float minDistSquared = minDist * minDist; float num = maxTravelRadiusFromLocus + verb.verbProps.range; float maxLocusDistSquared = num * num; Func <IntVec3, bool> losValidator = null; if ((flags & TargetScanFlags.LOSBlockableByGas) != TargetScanFlags.None) { losValidator = delegate(IntVec3 vec3) { Gas gas = vec3.GetGas(searcherThing.Map); return(gas == null || !gas.def.gas.blockTurretTracking); }; } Predicate <IAttackTarget> innerValidator = delegate(IAttackTarget t) { Thing thing = t.Thing; if (t == searcher) { return(false); } if (minDistSquared > 0f && (float)(searcherThing.Position - thing.Position).LengthHorizontalSquared < minDistSquared) { return(false); } if (!canTakeTargetsCloserThanEffectiveMinRange) { float num2 = verb.verbProps.EffectiveMinRange(thing, searcherThing); if (num2 > 0f && (float)(searcherThing.Position - thing.Position).LengthHorizontalSquared < num2 * num2) { return(false); } } if (maxTravelRadiusFromLocus < 9999f && (float)(thing.Position - locus).LengthHorizontalSquared > maxLocusDistSquared) { return(false); } if (!searcherThing.HostileTo(thing)) { return(false); } if (validator != null && !validator(thing)) { return(false); } if (searcherPawn != null) { Lord lord = searcherPawn.GetLord(); if (lord != null && !lord.LordJob.ValidateAttackTarget(searcherPawn, thing)) { return(false); } } if ((flags & TargetScanFlags.NeedNotUnderThickRoof) != TargetScanFlags.None) { RoofDef roof = thing.Position.GetRoof(thing.Map); if (roof != null && roof.isThickRoof) { return(false); } } if ((flags & TargetScanFlags.NeedLOSToAll) != TargetScanFlags.None) { if (losValidator != null && (!losValidator(searcherThing.Position) || !losValidator(thing.Position))) { return(false); } if (!searcherThing.CanSee(thing, losValidator)) { if (t is Pawn) { if ((flags & TargetScanFlags.NeedLOSToPawns) != TargetScanFlags.None) { return(false); } } else if ((flags & TargetScanFlags.NeedLOSToNonPawns) != TargetScanFlags.None) { return(false); } } } if (((flags & TargetScanFlags.NeedThreat) != TargetScanFlags.None || (flags & TargetScanFlags.NeedAutoTargetable) != TargetScanFlags.None) && t.ThreatDisabled(searcher)) { return(false); } if ((flags & TargetScanFlags.NeedAutoTargetable) != TargetScanFlags.None && !AttackTargetFinder.IsAutoTargetable(t)) { return(false); } if ((flags & TargetScanFlags.NeedActiveThreat) != TargetScanFlags.None && !GenHostility.IsActiveThreatTo(t, searcher.Thing.Faction)) { return(false); } Pawn pawn = t as Pawn; if (onlyTargetMachines && pawn != null && pawn.RaceProps.IsFlesh) { return(false); } if ((flags & TargetScanFlags.NeedNonBurning) != TargetScanFlags.None && thing.IsBurning()) { return(false); } if (searcherThing.def.race != null && searcherThing.def.race.intelligence >= Intelligence.Humanlike) { CompExplosive compExplosive = thing.TryGetComp <CompExplosive>(); if (compExplosive != null && compExplosive.wickStarted) { return(false); } } if (thing.def.size.x == 1 && thing.def.size.z == 1) { if (thing.Position.Fogged(thing.Map)) { return(false); } } else { bool flag2 = false; using (CellRect.Enumerator enumerator = thing.OccupiedRect().GetEnumerator()) { while (enumerator.MoveNext()) { if (!enumerator.Current.Fogged(thing.Map)) { flag2 = true; break; } } } if (!flag2) { return(false); } } return(true); }; if (HasRangedAttack(searcher) && (searcherPawn == null || !searcherPawn.InAggroMentalState)) { List <IAttackTarget> tmpTargets = new List <IAttackTarget>(); //AttackTargetFinder.tmpTargets.Clear(); tmpTargets.AddRange(searcherThing.Map.attackTargetsCache.GetPotentialTargetsFor(searcher)); if ((flags & TargetScanFlags.NeedReachable) != TargetScanFlags.None) { Predicate <IAttackTarget> oldValidator = innerValidator; innerValidator = ((IAttackTarget t) => oldValidator(t) && CanReach(searcherThing, t.Thing, canBash)); } bool flag = false; for (int i = 0; i < tmpTargets.Count; i++) { IAttackTarget attackTarget = tmpTargets[i]; if (attackTarget.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) && innerValidator(attackTarget) && CanShootAtFromCurrentPosition(attackTarget, searcher, verb)) { flag = true; break; } } IAttackTarget result = null; if (flag) { tmpTargets.RemoveAll((IAttackTarget x) => !x.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) || !innerValidator(x)); _ = GetRandomShootingTargetByScore(ref result, tmpTargets, searcher, verb); } else { Predicate <Thing> validator2; if ((flags & TargetScanFlags.NeedReachableIfCantHitFromMyPos) != TargetScanFlags.None && (flags & TargetScanFlags.NeedReachable) == TargetScanFlags.None) { validator2 = ((Thing t) => innerValidator((IAttackTarget)t) && (CanReach(searcherThing, t, canBash) || CanShootAtFromCurrentPosition((IAttackTarget)t, searcher, verb))); } else { validator2 = ((Thing t) => innerValidator((IAttackTarget)t)); } result = (IAttackTarget)GenClosest.ClosestThing_Global(searcherThing.Position, tmpTargets, maxDist, validator2, null); } tmpTargets.Clear(); __result = result; return(false); } if (searcherPawn != null && searcherPawn.mindState.duty != null && searcherPawn.mindState.duty.radius > 0f && !searcherPawn.InMentalState) { Predicate <IAttackTarget> oldValidator = innerValidator; innerValidator = ((IAttackTarget t) => oldValidator(t) && t.Thing.Position.InHorDistOf(searcherPawn.mindState.duty.focus.Cell, searcherPawn.mindState.duty.radius)); } IAttackTarget attackTarget2 = (IAttackTarget)GenClosest.ClosestThingReachable(searcherThing.Position, searcherThing.Map, ThingRequest.ForGroup(ThingRequestGroup.AttackTarget), PathEndMode.Touch, TraverseParms.For(searcherPawn, Danger.Deadly, TraverseMode.ByPawn, canBash), maxDist, (Thing x) => innerValidator((IAttackTarget)x), null, 0, (maxDist > 800f) ? -1 : 40, false, RegionType.Set_Passable, false); if (attackTarget2 != null && PawnUtility.ShouldCollideWithPawns(searcherPawn)) { IAttackTarget attackTarget3 = FindBestReachableMeleeTarget(innerValidator, searcherPawn, maxDist, canBash); if (attackTarget3 != null) { float lengthHorizontal = (searcherPawn.Position - attackTarget2.Thing.Position).LengthHorizontal; float lengthHorizontal2 = (searcherPawn.Position - attackTarget3.Thing.Position).LengthHorizontal; if (Mathf.Abs(lengthHorizontal - lengthHorizontal2) < 50f) { attackTarget2 = attackTarget3; } } } __result = attackTarget2; return(false); }
public static IAttackTarget BestAttackTarget(IAttackTargetSearcher searcher, TargetScanFlags flags, Predicate <Thing> validator = null, float minDist = 0f, float maxDist = 9999f, IntVec3 locus = default(IntVec3), float maxTravelRadiusFromLocus = float.MaxValue, bool canBash = false, bool canTakeTargetsCloserThanEffectiveMinRange = true) { Thing searcherThing = searcher.Thing; Pawn searcherPawn = searcher as Pawn; Verb verb = searcher.CurrentEffectiveVerb; if (verb == null) { Log.Error("BestAttackTarget with " + searcher.ToStringSafe() + " who has no attack verb."); return(null); } bool onlyTargetMachines = verb.IsEMP(); float minDistSquared = minDist * minDist; float num = maxTravelRadiusFromLocus + verb.verbProps.range; float maxLocusDistSquared = num * num; Func <IntVec3, bool> losValidator = null; if ((flags & TargetScanFlags.LOSBlockableByGas) != 0) { losValidator = delegate(IntVec3 vec3) { Gas gas = vec3.GetGas(searcherThing.Map); return(gas == null || !gas.def.gas.blockTurretTracking); }; } Predicate <IAttackTarget> innerValidator = delegate(IAttackTarget t) { Thing thing = t.Thing; if (t == searcher) { return(false); } if (minDistSquared > 0f && (float)(searcherThing.Position - thing.Position).LengthHorizontalSquared < minDistSquared) { return(false); } if (!canTakeTargetsCloserThanEffectiveMinRange) { float num2 = verb.verbProps.EffectiveMinRange(thing, searcherThing); if (num2 > 0f && (float)(searcherThing.Position - thing.Position).LengthHorizontalSquared < num2 * num2) { return(false); } } if (maxTravelRadiusFromLocus < 9999f && (float)(thing.Position - locus).LengthHorizontalSquared > maxLocusDistSquared) { return(false); } if (!searcherThing.HostileTo(thing)) { return(false); } if (validator != null && !validator(thing)) { return(false); } if (searcherPawn != null) { Lord lord = searcherPawn.GetLord(); if (lord != null && !lord.LordJob.ValidateAttackTarget(searcherPawn, thing)) { // Log.Messageage(thing + " lord ValidateAttackTarget: false"); return(false); } } if ((flags & TargetScanFlags.NeedNotUnderThickRoof) != 0) { RoofDef roof = thing.Position.GetRoof(thing.Map); if (roof != null && roof.isThickRoof) { // Log.Messageage(thing + " isThickRoof: false"); return(false); } } if ((flags & TargetScanFlags.NeedLOSToAll) != 0) { if (losValidator != null && (!losValidator(searcherThing.Position) || !losValidator(thing.Position))) { // Log.Messageage(thing + " LOSToAll: false"); return(false); } if (!searcherThing.CanSee(thing, losValidator)) { if (t is Pawn) { if ((flags & TargetScanFlags.NeedLOSToPawns) != 0) { // Log.Messageage(thing + " LOSToPawns: false"); return(false); } } else if ((flags & TargetScanFlags.NeedLOSToNonPawns) != 0) { // Log.Messageage(thing + " LOSToNonPawns: false"); return(false); } } } if (((flags & TargetScanFlags.NeedThreat) != 0 || (flags & TargetScanFlags.NeedAutoTargetable) != 0) && t.ThreatDisabled(searcher)) { // Log.Messageage(thing + " NeedThreat: false"); return(false); } if ((flags & TargetScanFlags.NeedAutoTargetable) != 0 && !IsAutoTargetable(t)) { // Log.Messageage(thing + " NeedAutoTargetable: false"); return(false); } if ((flags & TargetScanFlags.NeedActiveThreat) != 0 && !GenHostility.IsActiveThreatTo(t, searcher.Thing.Faction)) { // Log.Messageage(thing + " NeedActiveThreat: false"); return(false); } Pawn pawn = t as Pawn; if (onlyTargetMachines && pawn != null && pawn.RaceProps.IsFlesh) { // Log.Messageage(thing + " onlyTargetMachines: false"); return(false); } if ((flags & TargetScanFlags.NeedNonBurning) != 0 && thing.IsBurning()) { // Log.Messageage(thing + " NeedNonBurning: false"); return(false); } if (searcherThing.def.race != null && (int)searcherThing.def.race.intelligence >= 2) { CompExplosive compExplosive = thing.TryGetCompFast <CompExplosive>(); if (compExplosive != null && compExplosive.wickStarted) { // Log.Messageage(thing + " wickStarted: false"); return(false); } } if (thing.def.size.x == 1 && thing.def.size.z == 1) { if (thing.Position.Fogged(thing.Map)) { // Log.Messageage(thing + " Fogged: false"); return(false); } } else { bool flag2 = false; foreach (IntVec3 item in thing.OccupiedRect()) { if (!item.Fogged(thing.Map)) { flag2 = true; break; } } if (!flag2) { // Log.Messageage(thing + " Fogged: false"); return(false); } } // Log.Messageage(thing + " valid: true"); return(true); }; if (HasRangedAttack(searcher) && (searcherPawn == null || !searcherPawn.InAggroMentalState)) { // Log.Messageage(searcher + "AttackTargetFinder.HasRangedAttack 0"); tmpTargets.Clear(); // Log.Messageage(searcher + "AttackTargetFinder.HasRangedAttack 1"); tmpTargets.AddRange(searcherThing.Map.attackTargetsCache.GetPotentialTargetsFor(searcher)); // Log.Messageage(searcher + "AttackTargetFinder.HasRangedAttack 2 tmpTargets: " + tmpTargets.Count); if ((flags & TargetScanFlags.NeedReachable) != 0) { Predicate <IAttackTarget> oldValidator2 = innerValidator; innerValidator = ((IAttackTarget t) => oldValidator2(t) && CanReach(searcherThing, t.Thing, canBash)); } // Log.Messageage(searcher + "AttackTargetFinder.HasRangedAttack 3"); bool flag = false; for (int i = 0; i < tmpTargets.Count; i++) { IAttackTarget attackTarget = tmpTargets[i]; if (attackTarget.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) && innerValidator(attackTarget) && CanShootAtFromCurrentPosition(attackTarget, searcher, verb)) { flag = true; break; } } // Log.Messageage(searcher + "AttackTargetFinder.HasRangedAttack 4 "); IAttackTarget attackTarget2; if (flag) { tmpTargets.RemoveAll((IAttackTarget x) => !x.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) || !innerValidator(x)); attackTarget2 = GetRandomShootingTargetByScore(tmpTargets, searcher, verb); } else { attackTarget2 = (IAttackTarget)GenClosest.ClosestThing_Global(validator: ((flags & TargetScanFlags.NeedReachableIfCantHitFromMyPos) == 0 || (flags & TargetScanFlags.NeedReachable) != 0) ? ((Predicate <Thing>)((Thing t) => innerValidator((IAttackTarget)t))) : ((Predicate <Thing>)((Thing t) => innerValidator((IAttackTarget)t) && (CanReach(searcherThing, t, canBash) || CanShootAtFromCurrentPosition((IAttackTarget)t, searcher, verb)))), center: searcherThing.Position, searchSet: tmpTargets, maxDistance: maxDist); } // Log.Messageage(searcher + "AttackTargetFinder.HasRangedAttack 5"); tmpTargets.Clear(); // Log.Messageage(searcher + "AttackTargetFinder.HasRangedAttack tgt found: " + (attackTarget2 != null).ToString()); return(attackTarget2); } // Log.Messageage(searcher + "AttackTargetFinder.HasRangedAttack no ranged attack found"); if (searcherPawn != null && searcherPawn.mindState.duty != null && searcherPawn.mindState.duty.radius > 0f && !searcherPawn.InMentalState) { Predicate <IAttackTarget> oldValidator = innerValidator; innerValidator = ((IAttackTarget t) => oldValidator(t) && t.Thing.Position.InHorDistOf(searcherPawn.mindState.duty.focus.Cell, searcherPawn.mindState.duty.radius)); } IAttackTarget attackTarget3 = (IAttackTarget)GenClosest.ClosestThingReachable(searcherThing.Position, searcherThing.Map, ThingRequest.ForGroup(ThingRequestGroup.AttackTarget), PathEndMode.Touch, TraverseParms.For(searcherPawn, Danger.Deadly, TraverseMode.ByPawn, canBash), maxDist, (Thing x) => innerValidator((IAttackTarget)x), null, 0, (maxDist > 800f) ? (-1) : 40); if (attackTarget3 != null && PawnUtility.ShouldCollideWithPawns(searcherPawn)) { IAttackTarget attackTarget4 = FindBestReachableMeleeTarget(innerValidator, searcherPawn, maxDist, canBash); if (attackTarget4 != null) { float lengthHorizontal = (searcherPawn.Position - attackTarget3.Thing.Position).LengthHorizontal; float lengthHorizontal2 = (searcherPawn.Position - attackTarget4.Thing.Position).LengthHorizontal; if (Mathf.Abs(lengthHorizontal - lengthHorizontal2) < 50f) { attackTarget3 = attackTarget4; } } } return(attackTarget3); }
public static IAttackTarget BestAttackTarget(IAttackTargetSearcher searcher, Verb verb, TargetScanFlags flags, Predicate <Thing> validator = null, float minDist = 0f, float maxDist = 9999f, IntVec3 locus = default(IntVec3), float maxTravelRadiusFromLocus = 3.40282347E+38f, bool canBash = false, bool canTakeTargetsCloserThanEffectiveMinRange = true) { Thing searcherThing = searcher.Thing; Pawn searcherPawn = searcher as Pawn; if (verb == null) { Log.Error("BestAttackTarget with " + searcher.ToStringSafe <IAttackTargetSearcher>() + " who has no attack verb."); return(null); } bool onlyTargetMachines = verb.IsEMP(); float minDistSquared = minDist * minDist; float num = maxTravelRadiusFromLocus + verb.verbProps.range; float maxLocusDistSquared = num * num; Func <IntVec3, bool> losValidator = null; if ((byte)(flags & TargetScanFlags.LOSBlockableByGas) != 0) { losValidator = delegate(IntVec3 vec3) { Gas gas = vec3.GetGas(searcherThing.Map); return(gas == null || !gas.def.gas.blockTurretTracking); }; } Predicate <IAttackTarget> innerValidator = delegate(IAttackTarget t) { Thing thing = t.Thing; if (t == searcher) { return(false); } if (minDistSquared > 0f && (float)(searcherThing.Position - thing.Position).LengthHorizontalSquared < minDistSquared) { return(false); } if (!canTakeTargetsCloserThanEffectiveMinRange) { float num2 = verb.verbProps.EffectiveMinRange(thing, searcherThing); if (num2 > 0f && (float)(searcherThing.Position - thing.Position).LengthHorizontalSquared < num2 * num2) { return(false); } } if (maxTravelRadiusFromLocus < 9999f && (float)(thing.Position - locus).LengthHorizontalSquared > maxLocusDistSquared) { return(false); } if (!searcherThing.HostileTo(thing)) { return(false); } if (validator != null && !validator(thing)) { return(false); } if (searcherPawn != null) { Lord lord = searcherPawn.GetLord(); if (lord != null && !lord.LordJob.ValidateAttackTarget(searcherPawn, thing)) { return(false); } } if ((byte)(flags & TargetScanFlags.NeedLOSToAll) != 0 && !searcherThing.CanSee(thing, losValidator)) { if (t is Pawn) { if ((byte)(flags & TargetScanFlags.NeedLOSToPawns) != 0) { return(false); } } else if ((byte)(flags & TargetScanFlags.NeedLOSToNonPawns) != 0) { return(false); } } if ((byte)(flags & TargetScanFlags.NeedThreat) != 0 && t.ThreatDisabled(searcher)) { return(false); } if (onlyTargetMachines && t is Pawn pawn && pawn.RaceProps.IsFlesh) { return(false); } if ((byte)(flags & TargetScanFlags.NeedNonBurning) != 0 && thing.IsBurning()) { return(false); } if (searcherThing.def.race != null && searcherThing.def.race.intelligence >= Intelligence.Humanlike) { CompExplosive compExplosive = thing.TryGetComp <CompExplosive>(); if (compExplosive != null && compExplosive.wickStarted) { return(false); } } if (thing.def.size.x == 1 && thing.def.size.z == 1) { if (thing.Position.Fogged(thing.Map)) { return(false); } } else { bool flag2 = false; foreach (IntVec3 cellRect in thing.OccupiedRect()) { if (cellRect.Fogged(thing.Map)) { flag2 = true; break; } } if (!flag2) { return(false); } } return(true); }; if (PCF_AttackTargetFinder.HasRangedAttack(searcher, verb)) { PCF_AttackTargetFinder.tmpTargets.Clear(); PCF_AttackTargetFinder.tmpTargets.AddRange(searcherThing.Map.attackTargetsCache.GetPotentialTargetsFor(searcher)); if ((byte)(flags & TargetScanFlags.NeedReachable) != 0) { Predicate <IAttackTarget> oldValidator = innerValidator; innerValidator = ((IAttackTarget t) => oldValidator(t) && PCF_AttackTargetFinder.CanReach(searcherThing, t.Thing, canBash)); } bool flag = false; for (int i = 0; i < PCF_AttackTargetFinder.tmpTargets.Count; i++) { IAttackTarget attackTarget = PCF_AttackTargetFinder.tmpTargets[i]; if (attackTarget.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) && innerValidator(attackTarget) && PCF_AttackTargetFinder.CanShootAtFromCurrentPosition(attackTarget, searcher, verb)) { flag = true; break; } } IAttackTarget result; if (flag) { PCF_AttackTargetFinder.tmpTargets.RemoveAll((IAttackTarget x) => !x.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) || !innerValidator(x)); result = PCF_AttackTargetFinder.GetRandomShootingTargetByScore(PCF_AttackTargetFinder.tmpTargets, searcher, verb); } else { Predicate <Thing> validator2; if ((byte)(flags & TargetScanFlags.NeedReachableIfCantHitFromMyPos) != 0 && (byte)(flags & TargetScanFlags.NeedReachable) == 0) { validator2 = ((Thing t) => innerValidator((IAttackTarget)t) && (PCF_AttackTargetFinder.CanReach(searcherThing, t, canBash) || PCF_AttackTargetFinder.CanShootAtFromCurrentPosition((IAttackTarget)t, searcher, verb))); } else { validator2 = ((Thing t) => innerValidator((IAttackTarget)t)); } result = (IAttackTarget)GenClosest.ClosestThing_Global(searcherThing.Position, PCF_AttackTargetFinder.tmpTargets, maxDist, validator2, null); } PCF_AttackTargetFinder.tmpTargets.Clear(); return(result); } if (searcherPawn != null && searcherPawn.mindState.duty != null && searcherPawn.mindState.duty.radius > 0f && !searcherPawn.InMentalState) { Predicate <IAttackTarget> oldValidator = innerValidator; innerValidator = ((IAttackTarget t) => oldValidator(t) && t.Thing.Position.InHorDistOf(searcherPawn.mindState.duty.focus.Cell, searcherPawn.mindState.duty.radius)); } IntVec3 position = searcherThing.Position; Map map = searcherThing.Map; ThingRequest thingReq = ThingRequest.ForGroup(ThingRequestGroup.AttackTarget); PathEndMode peMode = PathEndMode.Touch; Pawn searcherPawn2 = searcherPawn; Danger maxDanger = Danger.Deadly; bool canBash2 = canBash; TraverseParms traverseParams = TraverseParms.For(searcherPawn2, maxDanger, TraverseMode.ByPawn, canBash2); float maxDist2 = maxDist; bool validator3(Thing x) => innerValidator((IAttackTarget)x); int searchRegionsMax = (maxDist <= 800f) ? 40 : -1; IAttackTarget attackTarget2 = (IAttackTarget)GenClosest.ClosestThingReachable(position, map, thingReq, peMode, traverseParams, maxDist2, validator3, null, 0, searchRegionsMax, false, RegionType.Set_Passable, false); if (attackTarget2 != null && PawnUtility.ShouldCollideWithPawns(searcherPawn)) { IAttackTarget attackTarget3 = PCF_AttackTargetFinder.FindBestReachableMeleeTarget(innerValidator, searcherPawn, maxDist, canBash); if (attackTarget3 != null) { float lengthHorizontal = (searcherPawn.Position - attackTarget2.Thing.Position).LengthHorizontal; float lengthHorizontal2 = (searcherPawn.Position - attackTarget3.Thing.Position).LengthHorizontal; if (Mathf.Abs(lengthHorizontal - lengthHorizontal2) < 50f) { attackTarget2 = attackTarget3; } } } return(attackTarget2); }