private static bool Prefix(ref JobGiver_AIFightEnemy __instance, ref Job __result, ref Pawn pawn) { bool flag = !pawn.RaceProps.Animal; bool result; if (flag) { result = true; } else { bool flag2 = false; List <Verb> allVerbs = pawn.verbTracker.AllVerbs; List <Verb> list = new List <Verb>(); for (int i = 0; i < allVerbs.Count; i++) { bool flag3 = allVerbs[i].verbProps.range > 1.1f; if (flag3) { list.Add(allVerbs[i]); flag2 = true; } } bool flag4 = !flag2; if (flag4) { result = true; } else { Verb verb = GenCollection.RandomElementByWeight <Verb>(list, (Verb rangeItem) => rangeItem.verbProps.commonality); bool flag5 = verb == null; if (flag5) { result = true; } else { Thing thing = (Thing)AttackTargetFinder.BestAttackTarget(pawn, TargetScanFlags.NeedThreat, (Thing x) => x is Pawn || x is Building, 0f, verb.verbProps.range, default(IntVec3), float.MaxValue, false, true); bool flag6 = thing == null; if (flag6) { result = true; } else { bool flag7 = IntVec3Utility.DistanceTo(thing.Position, pawn.Position) < verb.verbProps.minRange; if (flag7) { bool flag8 = GenAdj.AdjacentTo8Way(thing.Position, pawn.Position); if (flag8) { __result = new Job(JobDefOf.AttackMelee, thing) { maxNumMeleeAttacks = 1, expiryInterval = Rand.Range(420, 900), attackDoorIfTargetLost = false }; return(false); } bool flag9 = pawn.Faction != null && !pawn.Faction.def.isPlayer; if (!flag9) { bool flag10 = ReachabilityUtility.CanReach(pawn, thing, PathEndMode.Touch, Danger.Deadly, false, 0) && pawn.playerSettings.Master.playerSettings.animalsReleased; if (flag10) { __result = new Job(JobDefOf.AttackMelee, thing) { maxNumMeleeAttacks = 1, expiryInterval = Rand.Range(420, 900), attackDoorIfTargetLost = false }; return(false); } return(true); } } bool flag11 = (double)CoverUtility.CalculateOverallBlockChance(pawn.Position, thing.Position, pawn.Map) > 0.00999999977648258; bool flag12 = GenGrid.Standable(pawn.Position, pawn.Map); bool flag13 = verb.CanHitTarget(thing); bool flag14 = (pawn.Position - thing.Position).LengthHorizontalSquared < 25; bool flag15 = (flag11 && flag12 && flag13) || (flag14 && flag13); if (flag15) { JobDef named = DefDatabase <JobDef> .GetNamed("PI_AnimalRangeAttack", true); LocalTargetInfo localTargetInfo = thing; IntRange expiryInterval_ShooterSucceeded = JobGiver_AIFightEnemy.ExpiryInterval_ShooterSucceeded; __result = new Job(named, localTargetInfo, expiryInterval_ShooterSucceeded.RandomInRange, true) { verbToUse = verb }; result = false; } else { CastPositionRequest castPositionRequest = default(CastPositionRequest); castPositionRequest.caster = pawn; castPositionRequest.target = thing; castPositionRequest.verb = verb; castPositionRequest.maxRangeFromTarget = verb.verbProps.range; castPositionRequest.wantCoverFromTarget = (pawn.training.HasLearned(TrainableDefOf.Release) && (double)verb.verbProps.range > 7.0); castPositionRequest.locus = pawn.playerSettings.Master.Position; castPositionRequest.maxRangeFromLocus = Traverse.Create(__instance).Method("GetFlagRadius", new object[] { pawn }).GetValue <float>(); castPositionRequest.maxRegions = 50; IntVec3 intVec = new IntVec3(); bool flag16 = CastPositionFinder.TryFindCastPosition(castPositionRequest, out intVec); bool flag17 = !flag16; if (flag17) { result = true; } else { bool flag18 = intVec == pawn.Position; if (flag18) { JobDef named2 = DefDatabase <JobDef> .GetNamed("PI_AnimalRangeAttack", true); LocalTargetInfo localTargetInfo2 = thing; IntRange expiryInterval_ShooterSucceeded = JobGiver_AIFightEnemy.ExpiryInterval_ShooterSucceeded; __result = new Job(named2, localTargetInfo2, expiryInterval_ShooterSucceeded.RandomInRange, true) { verbToUse = verb }; result = false; } else { Job job = new Job(JobDefOf.Goto, intVec); IntRange expiryInterval_ShooterSucceeded = JobGiver_AIFightEnemy.ExpiryInterval_ShooterSucceeded; job.expiryInterval = expiryInterval_ShooterSucceeded.RandomInRange; job.checkOverrideOnExpire = true; __result = job; result = false; } } } } } } } return(result); }
// Verse.AI.CastPositionFinder public bool TryFindCastPosition(CastPositionRequest req, out IntVec3 dest) { ByteGrid avoidGrid = null; int inRadiusMark = 0; if (this.pawn.CurJob.verbToUse == null) { Log.Error(this.pawn + " tried to find casting position without a verb."); dest = IntVec3.Invalid; return(false); } if (req.maxRegionsRadius > 0) { Region region = req.caster.PositionHeld.GetRegion(this.pawn.Map); if (region == null) { Log.Error("TryFindCastPosition requiring region traversal but root region is null."); dest = IntVec3.Invalid; return(false); } inRadiusMark = Rand.Int; RegionTraverser.MarkRegionsBFS(region, null, req.maxRegionsRadius, inRadiusMark); if (req.maxRangeFromLocus > 0.01f) { Region region2 = req.locus.GetRegion(this.pawn.Map); if (region2 == null) { Log.Error("locus " + req.locus + " has no region"); dest = IntVec3.Invalid; return(false); } if (region2.mark != inRadiusMark) { Log.Error(string.Concat(new object[] { req.caster, " can't possibly get to locus ", req.locus, " as it's not in a maxRegionsRadius of ", req.maxRegionsRadius, ". Overriding maxRegionsRadius." })); req.maxRegionsRadius = 0; } } } CellRect cellRect = CellRect.WholeMap(req.caster.Map); if (req.maxRangeFromCaster > 0.01f) { int numSolo = Mathf.CeilToInt(req.maxRangeFromCaster); CellRect otherRect = new CellRect(this.pawn.PositionHeld.x - numSolo, this.pawn.PositionHeld.z - numSolo, numSolo * 2 + 1, numSolo * 2 + 1); cellRect.ClipInsideRect(otherRect); } int num2 = Mathf.CeilToInt(req.maxRangeFromTarget); CellRect otherRect2 = new CellRect(this.TargetA.Cell.x - num2, this.TargetA.Cell.z - num2, num2 * 2 + 1, num2 * 2 + 1); cellRect.ClipInsideRect(otherRect2); if (req.maxRangeFromLocus > 0.01f) { int numThree = Mathf.CeilToInt(req.maxRangeFromLocus); CellRect otherRect3 = new CellRect(this.TargetA.Cell.x - numThree, this.TargetA.Cell.z - numThree, numThree * 2 + 1, numThree * 2 + 1); cellRect.ClipInsideRect(otherRect3); } IntVec3 bestSpot = IntVec3.Invalid; float bestSpotPref = 0.001f; float maxRangeFromCasterSquared = req.maxRangeFromCaster * req.maxRangeFromCaster; float maxRangeFromTargetSquared = req.maxRangeFromTarget * req.maxRangeFromTarget; float maxRangeFromLocusSquared = req.maxRangeFromLocus * req.maxRangeFromLocus; float rangeFromTarget = (req.caster.Position - this.TargetA.Cell).LengthHorizontal; float rangeFromTargetSquared = (req.caster.Position - this.TargetA.Cell).LengthHorizontalSquared; float rangeFromCasterToCellSquared = 0f; float optimalRangeSquared = this.pawn.CurJob.verbToUse.verbProps.range * 0.8f * (this.pawn.CurJob.verbToUse.verbProps.range * 0.8f); /////////////////// Evaluate Cell method IntVec3 c = req.caster.PositionHeld; EvaluateCell(c, req, maxRangeFromTargetSquared, maxRangeFromLocusSquared, maxRangeFromCasterSquared, rangeFromCasterToCellSquared, inRadiusMark); float num = -1f; /////////////////// CAST POSITION PREFERENCE bool flag = true; List <Thing> list = req.caster.Map.thingGrid.ThingsListAtFast(c); for (int i = 0; i < list.Count; i++) { Thing thing = list[i]; if (thing is Fire fire && fire.parent == null) { num = -1f; goto MainSequenceTwo; } if (thing.def.passability == Traversability.PassThroughOnly) { flag = false; } } num = 0.3f; if (req.caster.kindDef.aiAvoidCover) { num += 8f - CoverUtility.TotalSurroundingCoverScore(c, req.caster.Map); } if (req.wantCoverFromTarget) { num += CoverUtility.CalculateOverallBlockChance(c, this.TargetLocA, req.caster.Map); } float numTwo = (req.caster.Position - c).LengthHorizontal; if (rangeFromTarget > 100f) { numTwo -= rangeFromTarget - 100f; if (numTwo < 0f) { numTwo = 0f; } } num *= Mathf.Pow(0.967f, num2); float num3 = 1f; float rangeFromTargetToCellSquared = (c - this.TargetLocA).LengthHorizontalSquared; //rangeFromCasterToCellSquared = (req.target.Position - c).LengthHorizontalSquared; float num4 = Mathf.Abs(rangeFromTargetToCellSquared - optimalRangeSquared) / optimalRangeSquared; num4 = 1f - num4; num4 = 0.7f + 0.3f * num4; num3 *= num4; if (rangeFromTargetToCellSquared < 25f) { num3 *= 0.5f; } num *= num3; if (rangeFromCasterToCellSquared > rangeFromTargetSquared) { num *= 0.4f; } if (!flag) { num *= 0.2f; } /////////////////////////////////////////////// MainSequenceTwo: if (avoidGrid != null) { byte b = avoidGrid[c]; num *= Mathf.Max(0.1f, (37f - b) / 37f); } if (DebugViewSettings.drawCastPositionSearch) { req.caster.Map.debugDrawer.FlashCell(c, num / 4f, num.ToString("F3")); } if (num < bestSpotPref) { goto MainSequence; } if (!this.pawn.CurJob.verbToUse.CanHitTargetFrom(c, this.TargetLocA)) { if (DebugViewSettings.drawCastPositionSearch) { req.caster.Map.debugDrawer.FlashCell(c, 0.6f, "can't hit"); } goto MainSequence; } if (req.caster.Map.pawnDestinationManager.DestinationIsReserved(c, req.caster)) { if (DebugViewSettings.drawCastPositionSearch) { req.caster.Map.debugDrawer.FlashCell(c, num * 0.9f, "resvd"); } goto MainSequence; } bestSpot = c; bestSpotPref = num; ///////////////////////////////////////////////////// MainSequence: if (bestSpotPref >= 1.0) { dest = req.caster.Position; return(true); } float slope = -1f / CellLine.Between(this.TargetLocA, req.caster.Position).Slope; CellLine cellLine = new CellLine(this.TargetLocA, slope); bool flagTwo = cellLine.CellIsAbove(req.caster.Position); CellRect.CellRectIterator iterator = cellRect.GetIterator(); while (!iterator.Done()) { IntVec3 current = iterator.Current; if (cellLine.CellIsAbove(current) == flagTwo && cellRect.Contains(current)) { EvaluateCell(current, req, maxRangeFromTargetSquared, maxRangeFromLocusSquared, maxRangeFromCasterSquared, rangeFromCasterToCellSquared, inRadiusMark); } iterator.MoveNext(); } if (bestSpot.IsValid && bestSpotPref > 0.33f) { dest = bestSpot; return(true); } CellRect.CellRectIterator iterator2 = cellRect.GetIterator(); while (!iterator2.Done()) { IntVec3 current2 = iterator2.Current; if (cellLine.CellIsAbove(current2) != flag && cellRect.Contains(current2)) { EvaluateCell(current2, req, maxRangeFromTargetSquared, maxRangeFromLocusSquared, maxRangeFromCasterSquared, rangeFromCasterToCellSquared, inRadiusMark); } iterator2.MoveNext(); } if (bestSpot.IsValid) { dest = bestSpot; return(true); } dest = req.caster.PositionHeld; return(false); }
// Token: 0x06000011 RID: 17 RVA: 0x00002D14 File Offset: 0x00000F14 private static Toil MarvsGotoCastPosition(TargetIndex targetInd, bool closeIfDowned = false) { var toil = new Toil(); toil.initAction = delegate { var actor = toil.actor; var curJob = actor.jobs.curJob; var thing = curJob.GetTarget(targetInd).Thing; if (thing is not Pawn pawn) { return; } var curWeatherAccuracyMultiplier = pawn.Map.weatherManager.CurWeatherAccuracyMultiplier; var newReq = new CastPositionRequest { caster = toil.actor, target = thing, verb = curJob.verbToUse, wantCoverFromTarget = false }; if (!pawn.Downed && !pawn.Awake() && pawn.def.race.predator) { toil.actor.jobs.EndCurrentJob(JobCondition.Incompletable); return; } if (closeIfDowned && (pawn.Downed || Hunting_Loader.settings.shouldApprochSleepers && !pawn.Awake())) { newReq.maxRangeFromTarget = Mathf.Min(curJob.verbToUse.verbProps.range, pawn.RaceProps.executionRange); } else { var def = actor.equipment.Primary.def; var num = GetGoodWeaponHuntingRange(def); if (IsPawnTriggerHappy(actor) && !def.IsMeleeWeapon) { num += TriggerHappyRangeReduction; } if (!def.IsMeleeWeapon) { num *= curWeatherAccuracyMultiplier; } var safeHuntingDistance = GetSafeHuntingDistance(pawn); newReq.maxRangeFromTarget = Mathf.Max(num, safeHuntingDistance); } if (!CastPositionFinder.TryFindCastPosition(newReq, out var intVec)) { toil.actor.jobs.EndCurrentJob(JobCondition.Incompletable); } else { if (intVec != toil.actor.Position) { toil.actor.pather.StartPath(intVec, PathEndMode.OnCell); actor.Map.pawnDestinationReservationManager.Reserve(actor, curJob, intVec); } else { toil.actor.pather.StopDead(); toil.actor.jobs.curDriver.ReadyForNextToil(); } } }; toil.FailOnDespawnedOrNull(targetInd); toil.defaultCompleteMode = ToilCompleteMode.PatherArrival; return(toil); }