public static Toil LayDown(TargetIndex bedOrRestSpotIndex, bool hasBed, bool lookForOtherJobs, bool canSleep = true, bool gainRestAndHealth = true)
        {
            Toil layDown = new Toil();

            layDown.initAction = delegate
            {
                Pawn actor = layDown.actor;
                actor.pather.StopDead();
                JobDriver curDriver = actor.jobs.curDriver;
                if (hasBed)
                {
                    Building_Bed t = (Building_Bed)actor.CurJob.GetTarget(bedOrRestSpotIndex).Thing;
                    if (!t.OccupiedRect().Contains(actor.Position))
                    {
                        Log.Error("Can't start LayDown toil because pawn is not in the bed. pawn=" + actor, false);
                        actor.jobs.EndCurrentJob(JobCondition.Errored, true);
                        return;
                    }
                    actor.jobs.posture = PawnPosture.LayingInBed;
                }
                else
                {
                    actor.jobs.posture = PawnPosture.LayingOnGroundNormal;
                }
                curDriver.asleep = false;
                if (actor.mindState.applyBedThoughtsTick == 0)
                {
                    actor.mindState.applyBedThoughtsTick    = Find.TickManager.TicksGame + Rand.Range(2500, 10000);
                    actor.mindState.applyBedThoughtsOnLeave = false;
                }
                if (actor.ownership != null && actor.CurrentBed() != actor.ownership.OwnedBed)
                {
                    ThoughtUtility.RemovePositiveBedroomThoughts(actor);
                }
            };

            layDown.tickAction = delegate
            {
                Pawn         actor        = layDown.actor;
                Job          curJob       = actor.CurJob;
                JobDriver    curDriver    = actor.jobs.curDriver;
                Building_Bed building_Bed = (Building_Bed)curJob.GetTarget(bedOrRestSpotIndex).Thing;
                actor.GainComfortFromCellIfPossible();

                if (actor.IsHashIntervalTick(100) && !actor.Position.Fogged(actor.Map))
                {
                    if (curDriver.asleep)
                    {
                        MoteMaker.ThrowMetaIcon(actor.Position, actor.Map, ThingDefOf.Mote_SleepZ);
                    }
                    if (gainRestAndHealth && actor.health.hediffSet.GetNaturallyHealingInjuredParts().Any <BodyPartRecord>())
                    {
                        MoteMaker.ThrowMetaIcon(actor.Position, actor.Map, ThingDefOf.Mote_HealingCross);
                    }
                }
                if (actor.ownership != null && building_Bed != null && !building_Bed.Medical && !building_Bed.OwnersForReading.Contains(actor))
                {
                    if (actor.Downed)
                    {
                        actor.Position = CellFinder.RandomClosewalkCellNear(actor.Position, actor.Map, 1, null);
                    }
                    actor.jobs.EndCurrentJob(JobCondition.Incompletable, true);
                    return;
                }
                if (lookForOtherJobs && actor.IsHashIntervalTick(211))
                {
                    actor.jobs.CheckForJobOverride();
                    return;
                }

                //Fin recharche ou pod non alimenté ou non operationel
                if (actor.needs.food.CurLevelPercentage >= 1.0f ||
                    building_Bed.Destroyed || building_Bed.IsBrokenDown() ||
                    !building_Bed.TryGetComp <CompPowerTrader>().PowerOn)
                {
                    actor.jobs.EndCurrentJob(JobCondition.Succeeded, true);
                }
            };
            layDown.defaultCompleteMode = ToilCompleteMode.Never;
            if (hasBed)
            {
                layDown.FailOnBedNoLongerUsable(bedOrRestSpotIndex);
            }
            layDown.AddFinishAction(delegate
            {
                Pawn actor          = layDown.actor;
                JobDriver curDriver = actor.jobs.curDriver;
                curDriver.asleep    = false;
            });
            return(layDown);
        }
예제 #2
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            if (Find.TickManager.TicksGame - pawn.mindState.lastDisturbanceTick < 400)
            {
                return(null);
            }
            // find your own bed
            Building_Bed catbed = RestUtility.FindBedFor(pawn);

            // sleep in your own bed 3/4 of the time
            if (catbed != null && Rand.Range(0f, 1f) > .75f)
            {
                return(new Job(JobDefOf.LayDown, catbed));
            }

            // sleep in owners bed 1/3 of the remainder
            if (Rand.Range(0f, 1f) > .33f && pawn.playerSettings.master != null)
            {
                Building_Bed masterbed = pawn.playerSettings.master.ownership.OwnedBed;
                if (masterbed != null)
                {
                    List <IntVec3> bedcells = masterbed.OccupiedRect().Cells.ToList();
                    bedcells.Remove(masterbed.Position);
                    return(new Job(JobDefOf.LayDown, bedcells.RandomElement()));
                }
            }

            // find all non-prisoner, non-medical beds
            IEnumerable <Building_Bed> pawnbeds = from b in pawn.Map.listerBuildings.AllBuildingsColonistOfClass <Building_Bed>()
                                                  where !b.ForPrisoners && !b.Medical && pawn.CanReach(b.Position, PathEndMode.OnCell, Danger.Some)
                                                  select b;

            // find all buildings labeled as having a surface, specifically exclude core stove
            IEnumerable <Building> surfaces = from t in pawn.Map.listerBuildings.allBuildingsColonist
                                              where t.def.surfaceType != SurfaceType.None &&
                                              pawn.CanReach(t.Position, PathEndMode.OnCell, Danger.Some) &&
                                              t.def.defName != "CookStove"
                                              select t;


            // try to sleep on beds that occupy more than one space, and don't already have a cat on them.
            // if two cats decide to sleep on the same spot, they will sleep on top of eachother, but I'm going to call that a feature.
            // they also probably don't get restefficiency bonuses from better beds, but I'm not sure cats ever do.
            if (pawnbeds != null && pawnbeds.Any())
            {
                // all cells in all non-prisoner, non-medical beds and all surfaces
                IEnumerable <IntVec3> bedcells     = pawnbeds.SelectMany(b => b.OccupiedRect().Cells);
                IEnumerable <IntVec3> surfacecells = surfaces.SelectMany(t => t.OccupiedRect().Cells);
                IEnumerable <IntVec3> cells        = bedcells.Union(surfacecells);

                // all cells that will be occupied by colonists (beds only)
                IEnumerable <IntVec3> pawnspots = pawnbeds.Select(b => b.Position);

                // all bed cells that will not be occupied by colonists
                IEnumerable <IntVec3> catspots = cells.Except(pawnspots);

                // reachable, and not already occupied
                IEnumerable <IntVec3> viable = from c in catspots
                                               where pawn.CanReach(c, PathEndMode.OnCell, Danger.Some) &&
                                               c.GetFirstThing(pawn.Map, ThingDef.Named("Fluffy_DomesticCat")) == null
                                               select c;

                if (viable != null && viable.Any())
                {
                    return(new Job(JobDefOf.LayDown, viable.RandomElement()));
                }
            }

            // sleep on floor as last resort
            IntVec3 vec = CellFinder.RandomClosewalkCellNear(pawn.Position, pawn.Map, 4);

            return(new Job(JobDefOf.LayDown, vec));
        }