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); }
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)); }