private static List <Pair <IAttackTarget, float> > GetAvailableShootingTargetsByScore(List <IAttackTarget> rawTargets, IAttackTargetSearcher searcher, Verb verb) { ARA_AttackTargetFinder.availableShootingTargets.Clear(); if (rawTargets.Count == 0) { return(ARA_AttackTargetFinder.availableShootingTargets); } ARA_AttackTargetFinder.tmpTargetScores.Clear(); ARA_AttackTargetFinder.tmpCanShootAtTarget.Clear(); float num = 0f; IAttackTarget attackTarget = null; for (int i = 0; i < rawTargets.Count; i++) { ARA_AttackTargetFinder.tmpTargetScores.Add(-3.40282347E+38f); ARA_AttackTargetFinder.tmpCanShootAtTarget.Add(false); if (rawTargets[i] != searcher) { bool flag = ARA_AttackTargetFinder.CanShootAtFromCurrentPosition(rawTargets[i], searcher, verb); ARA_AttackTargetFinder.tmpCanShootAtTarget[i] = flag; if (flag) { float shootingTargetScore = ARA_AttackTargetFinder.GetShootingTargetScore(rawTargets[i], searcher, verb); ARA_AttackTargetFinder.tmpTargetScores[i] = shootingTargetScore; if (attackTarget == null || shootingTargetScore > num) { attackTarget = rawTargets[i]; num = shootingTargetScore; } } } } if (num < 1f) { if (attackTarget != null) { ARA_AttackTargetFinder.availableShootingTargets.Add(new Pair <IAttackTarget, float>(attackTarget, 1f)); } } else { float num2 = num - 30f; for (int j = 0; j < rawTargets.Count; j++) { if (rawTargets[j] != searcher) { if (ARA_AttackTargetFinder.tmpCanShootAtTarget[j]) { float num3 = ARA_AttackTargetFinder.tmpTargetScores[j]; if (num3 >= num2) { float second = Mathf.InverseLerp(num - 30f, num, num3); ARA_AttackTargetFinder.availableShootingTargets.Add(new Pair <IAttackTarget, float>(rawTargets[j], second)); } } } } } return(ARA_AttackTargetFinder.availableShootingTargets); }
private static IAttackTarget GetRandomShootingTargetByScore(List <IAttackTarget> targets, IAttackTargetSearcher searcher, Verb verb) { Pair <IAttackTarget, float> pair; if (ARA_AttackTargetFinder.GetAvailableShootingTargetsByScore(targets, searcher, verb).TryRandomElementByWeight((Pair <IAttackTarget, float> x) => x.Second, out pair)) { return(pair.First); } return(null); }
private static float GetShootingTargetScore(IAttackTarget target, IAttackTargetSearcher searcher, Verb verb) { float num = 60f; num -= Mathf.Min((target.Thing.Position - searcher.Thing.Position).LengthHorizontal, 40f); if (target.TargetCurrentlyAimingAt == searcher.Thing) { num += 10f; } if (searcher.LastAttackedTarget == target.Thing && Find.TickManager.TicksGame - searcher.LastAttackTargetTick <= 300) { num += 40f; } num -= CoverUtility.CalculateOverallBlockChance(target.Thing.Position, searcher.Thing.Position, searcher.Thing.Map) * 10f; Pawn pawn = target as Pawn; if (pawn != null && pawn.RaceProps.Animal && pawn.Faction != null && !pawn.IsFighting()) { num -= 50f; } return(num + ARA_AttackTargetFinder.FriendlyFireShootingTargetScoreOffset(target, searcher, verb)); }
static bool Prefix(ref JobGiver_Manhunter __instance, ref Job __result, ref Pawn pawn) { //Log.Warning("Detected Animal Attack"); bool hasRangedVerb = false; //Log.Warning("Trying to fire at pawn"); List <Verb> verbList = pawn.verbTracker.AllVerbs; //Log.Warning("Got list of verb"); List <Verb> rangeList = new List <Verb>(); for (int i = 0; i < verbList.Count; i++) { //Log.Warning("Checkity"); //It corresponds with verbs anyway if (verbList[i].verbProps.range > 1.1f) { rangeList.Add(verbList[i]); hasRangedVerb = true; } //Log.Warning("Added Ranged Verb"); } //Log.Warning("got list of ranged verb"); //If there is no ranged verb just return; if (hasRangedVerb == false) { return(true); } Verb rangeVerb = rangeList.RandomElementByWeight((Verb rangeItem) => rangeItem.verbProps.commonality); if (rangeVerb == null) { Log.Warning("Can't get random range verb"); return(true); } //Log.Warning("Range verb detected"); Thing target = (Thing)ARA_AttackTargetFinder.BestAttackTarget((IAttackTargetSearcher)pawn, TargetScanFlags.NeedThreat | TargetScanFlags.NeedReachable, (Predicate <Thing>)(x => x is Pawn || x is Building), 0.0f, 9999, new IntVec3(), float.MaxValue, false); //Seek thing hiding in embrasure. if (target == null) { target = (Thing)ARA_AttackTargetFinder.BestAttackTarget((IAttackTargetSearcher)pawn, TargetScanFlags.NeedThreat, (Predicate <Thing>)(x => x is Pawn || x is Building), 0.0f, 9999, new IntVec3(), float.MaxValue, false); } //Use normal manhunter //Can't check for target if it doesn't exist duh //Log.Warning("CurrentEffectiveVerb " + pawn.CurrentEffectiveVerb); /* * Log.Warning("Effective Range " + pawn.CurrentEffectiveVerb.verbProps.range); * if (!pawn.CurrentEffectiveVerb.verbProps.MeleeRange) * { * Log.Warning("Not melee range"); * } */ bool targetInSight = false; Thing shootable = null; if (target == null) { shootable = (Thing)ARA_AttackTargetFinder.BestShootTargetFromCurrentPosition(pawn, (Predicate <Thing>)(x => x is Pawn || x is Building), rangeVerb.verbProps.range, rangeVerb.verbProps.minRange, TargetScanFlags.NeedThreat | TargetScanFlags.NeedLOSToPawns | TargetScanFlags.LOSBlockableByGas); //Log.Warning("Shootable found, " + shootable); if (shootable == null) { //Log.Warning("No target in line of site"); return(true); } targetInSight = true; } else if (target.Position.DistanceTo(pawn.Position) < rangeVerb.verbProps.minRange || target.Position.AdjacentTo8Way(pawn.Position)) { //Log.Warning("Target too close, melee!"); //Core code can't handle animal anymore if (pawn.CanReach(target, PathEndMode.Touch, Danger.Deadly, false)) { //Log.Warning("Melee Attack"); __result = new Job(JobDefOf.AttackMelee, target) { maxNumMeleeAttacks = 1, expiryInterval = Rand.Range(420, 900), attackDoorIfTargetLost = false }; return(false); } else { return(true); } } //Log.Warning("Got target"); //Formally range attack job //if (target != null && pawn.CanReach(target, PathEndMode.Touch, Danger.Deadly, false)) //Log.Warning("Ranged verb selected, range of " + verb.verbProps.range); IntVec3 intVec; //Log.Warning("Trying to shoot"); //Searches for target within range again. if (!targetInSight) { //Log.Warning("No target"); shootable = (Thing)ARA_AttackTargetFinder.BestShootTargetFromCurrentPosition(pawn, (Predicate <Thing>)(x => x is Pawn || x is Building), rangeVerb.verbProps.range, rangeVerb.verbProps.minRange, TargetScanFlags.NeedThreat | TargetScanFlags.NeedLOSToPawns | TargetScanFlags.LOSBlockableByGas); } if (shootable != null) { //Log.Warning("Got Shootable"); if (target.Position.DistanceTo(pawn.Position) < rangeVerb.verbProps.minRange || target.Position.AdjacentTo8Way(pawn.Position)) { //Log.Warning("Target too close, melee!"); //Core code can't handle animal anymore if (pawn.CanReach(target, PathEndMode.Touch, Danger.Deadly, false)) { //Log.Warning("Melee Attack"); __result = new Job(JobDefOf.AttackMelee, target) { maxNumMeleeAttacks = 1, expiryInterval = Rand.Range(420, 900), attackDoorIfTargetLost = false }; return(false); } else { //Log.Warning("Target too close and I can't melee right away"); return(true); } } //Log.Warning("Trying initiate job"); __result = new Job(DefDatabase <JobDef> .GetNamed("AA_AlphaAnimalRangeAttack"), shootable, JobGiver_AIFightEnemy.ExpiryInterval_ShooterSucceeded.RandomInRange, true) { verbToUse = rangeVerb }; //Log.Warning("Succesfully created job"); return(false); } //Target is not null if (target != null) { //Can't shoot at target from current position. Find a new position bool canShootCondition = false; //Log.Warning("Try casting"); canShootCondition = CastPositionFinder.TryFindCastPosition(new CastPositionRequest { caster = pawn, target = target, verb = rangeVerb, maxRangeFromTarget = 9999, wantCoverFromTarget = false }, out intVec); if (!canShootCondition) { //Log.Warning("Can't find place to shoot at target"); return(true); } //Log.Warning("Going"); //Go to new destination //Protection againt not being able to find target. if (pawn.Position == intVec) { //Log.Warning(pawn + " already at position to shoot, but target not selected to shoot."); __result = new Job(JobDefOf.Wait, 100); return(false); } __result = new Job(JobDefOf.Goto, intVec) { expiryInterval = JobGiver_AIFightEnemy.ExpiryInterval_ShooterSucceeded.RandomInRange, checkOverrideOnExpire = true }; return(false); } //Log.Warning("Hit end condition"); return(true); }
public static IAttackTarget BestShootTargetFromCurrentPosition(IAttackTargetSearcher searcher, Predicate <Thing> validator, float maxDistance, float minDistance, TargetScanFlags flags) { return(ARA_AttackTargetFinder.BestAttackTarget(searcher, flags, validator, minDistance, maxDistance, default(IntVec3), 3.40282347E+38f, 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 = 3.40282347E+38f, bool canBash = false) { Thing searcherThing = searcher.Thing; Pawn searcherPawn = searcher as Pawn; Verb verb = searcher.CurrentEffectiveVerb; if (verb == null) { //Log.Error("BestAttackTarget with " + searcher + " who has no attack verb."); return(null); } bool onlyTargetMachines = verb != null && verb.IsEMP(); float minDistanceSquared = 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 (minDistanceSquared > 0f && (float)(searcherThing.Position - thing.Position).LengthHorizontalSquared < minDistanceSquared) { 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 ((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); } Pawn pawn = t as Pawn; if (onlyTargetMachines && pawn != null && 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; CellRect.CellRectIterator iterator = thing.OccupiedRect().GetIterator(); while (!iterator.Done()) { if (!iterator.Current.Fogged(thing.Map)) { flag2 = true; break; } iterator.MoveNext(); } if (!flag2) { return(false); } } return(true); }; if (ARA_AttackTargetFinder.HasRangedAttack(searcher)) { //Log.Warning("Finder: Range detected. Verb is " + verb); //Log.Warning("Finder: Pawn " + searcherPawn.Faction); ARA_AttackTargetFinder.tmpTargets.Clear(); //This needs to be fixed. Can't use searcherThing. Doing this the hard way. //Set request for all attackable. ThingRequest thingReq = ThingRequest.ForGroup(ThingRequestGroup.AttackTarget); IEnumerable <Thing> searchSet = searcherThing.Map.listerThings.ThingsMatching(thingReq); foreach (IAttackTarget iTarget in searchSet) { ARA_AttackTargetFinder.tmpTargets.Add(iTarget); } if ((byte)(flags & TargetScanFlags.NeedReachable) != 0) { Predicate <IAttackTarget> oldValidator = innerValidator; innerValidator = ((IAttackTarget t) => oldValidator(t) && ARA_AttackTargetFinder.CanReach(searcherThing, t.Thing, canBash)); } bool flag = false; if (searcherThing.Faction != Faction.OfPlayer) { //Log.Warning("Finder: Target available : " + ARA_AttackTargetFinder.tmpTargets.Count); for (int i = 0; i < ARA_AttackTargetFinder.tmpTargets.Count; i++) { IAttackTarget attackTarget = ARA_AttackTargetFinder.tmpTargets[i]; if (attackTarget.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) && innerValidator(attackTarget) && ARA_AttackTargetFinder.CanShootAtFromCurrentPosition(attackTarget, searcher, verb)) { //Log.Warning("Finder: flag is true"); flag = true; break; } } } IAttackTarget result; if (flag) { //Log.Warning("Finder: FlagTrue result"); ARA_AttackTargetFinder.tmpTargets.RemoveAll((IAttackTarget x) => !x.Thing.Position.InHorDistOf(searcherThing.Position, maxDist) || !innerValidator(x)); //Log.Warning("Finder: Target Avaliable : " + ARA_AttackTargetFinder.tmpTargets.Count); result = ARA_AttackTargetFinder.GetRandomShootingTargetByScore(ARA_AttackTargetFinder.tmpTargets, searcher, verb); } else { Predicate <Thing> validator2; if ((byte)(flags & TargetScanFlags.NeedReachableIfCantHitFromMyPos) != 0 && (byte)(flags & TargetScanFlags.NeedReachable) == 0) { //Log.Warning("Finder: Needs reachable"); validator2 = ((Thing t) => innerValidator((IAttackTarget)t) && (ARA_AttackTargetFinder.CanReach(searcherThing, t, canBash) || ARA_AttackTargetFinder.CanShootAtFromCurrentPosition((IAttackTarget)t, searcher, verb))); } else { //Log.Warning("Finder: Running normal validator"); validator2 = ((Thing t) => innerValidator((IAttackTarget)t)); } result = (IAttackTarget)GenClosest.ClosestThing_Global(searcherThing.Position, ARA_AttackTargetFinder.tmpTargets, maxDist, validator2, null); } ARA_AttackTargetFinder.tmpTargets.Clear(); //Log.Warning("Trying to return result " + result); return(result); } //Log.Warning("Returning Null"); return(null); }