public static bool CanReach(Reachability __instance, ref bool __result, IntVec3 start, LocalTargetInfo dest, PathEndMode peMode, TraverseParms traverseParams) { /* * if (working) * { * Log.ErrorOnce("Called CanReach() while working. This should never happen. Suppressing further errors.", 7312233); * return false; * } */ Map this_map = map(__instance); if (traverseParams.pawn != null) { if (!traverseParams.pawn.Spawned) { __result = false; return(false); } if (traverseParams.pawn.Map != this_map) { Log.Error("Called CanReach() with a pawn spawned not on this map. This means that we can't check his reachability here. Pawn's current map should have been used instead of this one. pawn=" + (object)traverseParams.pawn + " pawn.Map=" + (object)traverseParams.pawn.Map + " map=" + (object)map(__instance), false); __result = false; return(false); } } if (ReachabilityImmediate.CanReachImmediate(start, dest, this_map, peMode, traverseParams.pawn)) { __result = true; return(false); } if (!dest.IsValid || dest.HasThing && dest.Thing.Map != this_map || (!start.InBounds(this_map) || !dest.Cell.InBounds(this_map))) { __result = false; return(false); } if ((peMode == PathEndMode.OnCell || peMode == PathEndMode.Touch || peMode == PathEndMode.ClosestTouch) && (traverseParams.mode != TraverseMode.NoPassClosedDoorsOrWater && traverseParams.mode != TraverseMode.PassAllDestroyableThingsNotWater)) { Room room = RegionAndRoomQuery.RoomAtFast(start, this_map, RegionType.Set_Passable); if (room != null && room == RegionAndRoomQuery.RoomAtFast(dest.Cell, this_map, RegionType.Set_Passable)) { __result = true; return(false); } } if (traverseParams.mode == TraverseMode.PassAllDestroyableThings) { TraverseParms traverseParams1 = traverseParams; traverseParams1.mode = TraverseMode.PassDoors; if (__instance.CanReach(start, dest, peMode, traverseParams1)) { __result = true; return(false); } } dest = (LocalTargetInfo)GenPath.ResolvePathMode(traverseParams.pawn, dest.ToTargetInfo(this_map), ref peMode); //working = true; try { uint this_reachedIndex; //Replaced reachedIndex lock (reachedIndexLock) //Added { this_reachedIndex = offsetReachedIndex; //Added offsetReachedIndex += 100000; //Added } HashSet <Region> regionsReached = new HashSet <Region>(); //Added PathGrid pathGrid = this_map.pathGrid; //Replaced pathGrid RegionGrid regionGrid = this_map.regionGrid; //Replaced regionGrid ++this_reachedIndex; //Replaced reachedIndex //this_destRegions.Clear(); List <Region> this_destRegions = new List <Region>(); //Replaced destRegions switch (peMode) { case PathEndMode.OnCell: Region region = dest.Cell.GetRegion(this_map, RegionType.Set_Passable); if (region != null && region.Allows(traverseParams, true)) { this_destRegions.Add(region); break; } break; case PathEndMode.Touch: TouchPathEndModeUtility.AddAllowedAdjacentRegions(dest, traverseParams, this_map, this_destRegions); break; } if (this_destRegions.Count == 0 && traverseParams.mode != TraverseMode.PassAllDestroyableThings && traverseParams.mode != TraverseMode.PassAllDestroyableThingsNotWater) { //this.FinalizeCheck(); __result = false; return(false); } this_destRegions.RemoveDuplicates <Region>(); //this_openQueue.Clear(); Queue <Region> this_openQueue = new Queue <Region>(); //Replaced openQueue int this_numRegionsOpened = 0; //Replaced numRegionsOpened List <Region> this_startingRegions = new List <Region>(); DetermineStartRegions2(__instance, start, this_startingRegions, pathGrid, regionGrid, this_reachedIndex, this_openQueue, ref this_numRegionsOpened, regionsReached); if (this_openQueue.Count == 0 && traverseParams.mode != TraverseMode.PassAllDestroyableThings && traverseParams.mode != TraverseMode.PassAllDestroyableThingsNotWater) { //this.FinalizeCheck(); __result = false; return(false); } ReachabilityCache this_cache = cache(__instance); if (this_startingRegions.Any <Region>() && this_destRegions.Any <Region>() && CanUseCache(traverseParams.mode)) { switch (GetCachedResult2(traverseParams, this_startingRegions, this_destRegions, this_cache)) { case BoolUnknown.True: //this.FinalizeCheck(); __result = true; return(false); case BoolUnknown.False: //this.FinalizeCheck(); __result = false; return(false); } } if (traverseParams.mode == TraverseMode.PassAllDestroyableThings || traverseParams.mode == TraverseMode.PassAllDestroyableThingsNotWater || traverseParams.mode == TraverseMode.NoPassClosedDoorsOrWater) { int num = CheckCellBasedReachability(start, dest, peMode, traverseParams, regionGrid, __instance, this_startingRegions, this_cache, this_destRegions ) ? 1 : 0; //this.FinalizeCheck(); __result = num != 0; return(false); } int num1 = CheckRegionBasedReachability(traverseParams, this_openQueue, this_reachedIndex, this_destRegions, this_startingRegions, this_cache, ref this_numRegionsOpened, regionsReached ) ? 1 : 0; //this.FinalizeCheck(); __result = num1 != 0; return(false); } finally { } }
protected override IEnumerable <Toil> MakeNewToils() { // Just on the off-chance the rock is on fire... this.FailOnBurningImmobile(TargetIndex.A); // Reserve the target yield return(Toils_Reserve.Reserve(TargetIndex.A)); // Go to the target Toil toilGoto = Toils_Goto.GotoCell(TargetIndex.A, PathEndMode.Touch); // Fail going to the target if it becomes unreachable ToilFailConditions.FailOn <Toil>(toilGoto, (Func <bool>)(() => { if (Reachability.CanReach(pawn, (TargetInfo)TargetLocA, PathEndMode.Touch, pawn.NormalMaxDanger())) { return(false); } return(true); })); yield return(toilGoto); // Now the work toil itself Toil toilWork = new Toil { // Continue until done defaultCompleteMode = ToilCompleteMode.Never, // When the job starts... initAction = new Action(() => { smoothTicks = 0; }), // The work tick tickAction = new Action(() => { if (pawn.skills != null) { const float constructionXP = 0.11f / 5f; const float miningXP = 0.11f / 5f; const float artisticXP = 0.11f / 5f; pawn.skills.Learn(SkillDefOf.Construction, constructionXP); pawn.skills.Learn(SkillDefOf.Mining, miningXP); pawn.skills.Learn(SkillDefOf.Artistic, artisticXP); } smoothTicks += 1; if (smoothTicks < nextSmoothStrike) { return; } // Reset counter, damage rock smoothTicks = 0; mineable.HitPoints -= DamagePerStrike; }) }; // When should we stop? toilWork.endConditions.Add((Func <JobCondition>)(() => { // Go until the rock is fully damaged if (mineable.HitPoints > 0) { return(JobCondition.Ongoing); } return(JobCondition.Succeeded); })); // Do something when done toilWork.AddFinishAction(new Action(() => { // If the job failed, abort if (mineable.HitPoints > 0) { return; } // Clear the designation at this cell Common.RemoveDesignationDefOfAt(SmoothWall.designationDef, TargetA.Cell); // Better have associated stone blocks... string blocksDef = "Blocks" + mineable.def.defName; ThingDef stoneBlocks = DefDatabase <ThingDef> .GetNamed(blocksDef, true); // Replace the rock with a stone wall var wallThing = ThingMaker.MakeThing(SmoothWall.thingDef, stoneBlocks); if (wallThing != null) { var wall = GenSpawn.Spawn(wallThing, TargetA.Cell); if (wall != null) { wall.SetFaction(Faction.OfColony); } } })); // Some fun sounds while working ToilEffects.WithSustainer(toilWork, (Func <SoundDef>)(() => { return(SmoothWall.soundDef); })); // Some fun effects while working ToilEffects.WithEffect(toilWork, "Mine", TargetIndex.A); yield return(toilWork); // And we're done. yield break; }
protected override void UpdateEnemyTarget(Pawn pawn) { var thing = pawn.mindState.enemyTarget; if (thing != null) { if (thing.Destroyed || Find.TickManager.TicksGame - pawn.mindState.lastEngageTargetTick > 400 || !pawn.CanReach(thing, PathEndMode.Touch, Danger.Deadly, true) || (pawn.Position - thing.Position).LengthHorizontalSquared > targetKeepRadius * targetKeepRadius) { thing = null; } Pawn pawn2 = thing as Pawn; if (pawn2 != null && pawn2.Downed) { thing = null; } Building_Door door = thing as Building_Door; if (door != null && door.Open) { thing = null; } } // Select only flesh stuff Predicate <Thing> validatorPawn = t => t is Pawn && !t.Destroyed && !(t as Pawn).Downed && t.def.race != null && t.def.race.isFlesh; Predicate <Thing> validatorDoor = t => t is Building_Door && !t.Destroyed && !(t as Building_Door).Open; // Method is internal (duh) MethodInfo notifyEngagedTarget = typeof(Pawn_MindState).GetMethod("Notify_EngagedTarget", BindingFlags.NonPublic | BindingFlags.Instance); if (thing == null) { //Log.Message(pawn.Label + ": trying to find target..."); const TargetScanFlags targetScanFlags = TargetScanFlags.NeedLOSToPawns | TargetScanFlags.NeedReachable; thing = AttackTargetFinder.BestAttackTarget(pawn, validatorPawn, targetAcquireRadius, 0f, targetScanFlags); if (thing != null) { //Log.Message("Selected pawn " + thing.Label); notifyEngagedTarget.Invoke(pawn.mindState, null); Brain brain = Find.SquadBrainManager.SquadBrainFor(pawn); if (brain != null) { brain.Notify_PawnAcquiredTarget(pawn, thing); } } else { //Thing thing2 = GenAI.BestAttackTarget(pawn.Position, pawn, validatorDoor, targetAcquireRadius, 0f, targetScanFlags2); Building_Door thing2 = Find.ListerBuildings.AllBuildingsColonistOfClass <Building_Door>() .Where( b => validatorDoor(b) && Reachability.CanReach(b.Position, pawn.Position, PathEndMode.Touch, TraverseMode.PassDoors, Danger.Deadly)) .OrderBy(door => door.Position.DistanceToSquared(pawn.Position)).FirstOrDefault(); if (thing2 != null && thing2 != thing) { notifyEngagedTarget.Invoke(pawn.mindState, null); //Log.Message("Selected door " + thing2.Label); thing = thing2; } } if (thing != pawn.mindState.enemyTarget) { if (pawn.CurJob != null) { pawn.CurJob.SetTarget(TargetIndex.A, thing); } pawn.mindState.enemyTarget = thing; } } }