示例#1
0
        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;
                }
            }
        }