protected override IEnumerable <Toil> MakeNewToils() { this.FailOnDespawnedNullOrForbidden <JobDriver_StabilizeHere>(TargetIndex.A); this.FailOnAggroMentalState <JobDriver_StabilizeHere>(TargetIndex.A); this.AddEndCondition(() => { if (HealthAIUtility.ShouldBeTendedNowByPlayer(this.Patient) || this.Patient.health.HasHediffsNeedingTend(false)) { return(JobCondition.Ongoing); } return(JobCondition.Succeeded); }); Toil toil1 = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell); yield return(toil1); Toil toil2 = Toils_General.Wait((int)(1f / this.Doctor.GetStatValue(StatDefOf.MedicalTendSpeed, true) * 600f), TargetIndex.None).FailOnCannotTouch <Toil>(TargetIndex.A, PathEndMode.InteractionCell).WithProgressBarToilDelay(TargetIndex.A, false, -0.5f).PlaySustainerOrSound(SoundDefOf.Interact_Tend); toil2.activeSkill = () => SkillDefOf.Medicine; yield return(toil2); yield return(Toils_Tend.FinalizeTend(this.Patient)); yield return(Toils_Jump.Jump(toil1)); }
public static InjurySeverity GetTendSeverity(this Pawn patient) { if (!HealthAIUtility.ShouldBeTendedNowByPlayer(patient)) // .ShouldBeTendedNow( patient ) ) { return(InjurySeverity.Minor); } var hediffs = patient.health.hediffSet.hediffs; var ticksToDeathDueToBloodLoss = HealthUtility.TicksUntilDeathDueToBloodLoss(patient); // going to die in <6 hours, or any tendable is life threathening if (ticksToDeathDueToBloodLoss <= GenDate.TicksPerHour * 6 || hediffs.Any(h => h.CurStage?.lifeThreatening ?? false) || hediffs.Any(NearLethalDisease)) { return(InjurySeverity.LifeThreathening); } // going to die in <12 hours, or any immunity < severity and can be fatal, or death by a thousand cuts imminent if (ticksToDeathDueToBloodLoss <= GenDate.TicksPerHour * 12 || hediffs.Any(PotentiallyLethalDisease) || DeathByAThousandCuts(patient)) { return(InjurySeverity.Major); } // otherwise return(InjurySeverity.Minor); }
// Token: 0x06000026 RID: 38 RVA: 0x000026A3 File Offset: 0x000008A3 protected override IEnumerable <Toil> MakeNewToils() { base.AddEndCondition(delegate() { if (this.pawn.Faction == Faction.OfPlayer && HealthAIUtility.ShouldBeTendedNowByPlayer(this.pawn)) { return(JobCondition.Ongoing); } if (this.pawn.Faction != Faction.OfPlayer && this.pawn.health.HasHediffsNeedingTend(false)) { return(JobCondition.Ongoing); } return(JobCondition.Succeeded); }); int ticks = (int)(1f / StatExtension.GetStatValue(this.pawn, StatDefOf.MedicalTendSpeed, true) * 600f); yield return(ToilEffects.PlaySustainerOrSound(ToilEffects.WithProgressBarToilDelay(Toils_General.Wait(ticks, 0), (TargetIndex)1, false, -0.5f), SoundDefOf.Interact_Tend)); Toil toil = new Toil(); toil.initAction = delegate() { Pawn actor = toil.actor; Cloakgen medkit = actor.apparel.WornApparel.OfType <Cloakgen>().FirstOrDefault <Cloakgen>(); float num = (!actor.RaceProps.Animal) ? 500f : 175f; float num2 = (medkit != null) ? medkit.kitComp.Props.medicine.MedicineTendXpGainFactor : 0.5f; actor.skills.Learn(SkillDefOf.Medicine, num * num2, false); HealthShardTendUtility.DoTend(actor, actor, medkit); }; toil.defaultCompleteMode = (ToilCompleteMode)1; yield return(toil); yield break; }
// Token: 0x0600002D RID: 45 RVA: 0x00002758 File Offset: 0x00000958 public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobParm) { bool flag = !HealthAIUtility.ShouldSeekMedicalRest(pawn); ThinkResult result; if (flag) { result = ThinkResult.NoJob; } else { bool flag2 = !HealthAIUtility.ShouldBeTendedNowByPlayer(pawn); if (flag2) { result = ThinkResult.NoJob; } else { bool flag3 = !GenCollection.Any <Apparel>(pawn.apparel.WornApparel, (Apparel x) => x.def.defName.Contains("RRY_Equipment_HunterGauntlet")); if (flag3) { result = ThinkResult.NoJob; } else { Thing thing = RestUtility.FindPatientBedFor(pawn); bool flag4 = thing == null; if (flag4) { result = ThinkResult.NoJob; } else { Thing thing2 = null; bool flag5 = Medicine.GetMedicineCountToFullyHeal(pawn) > 0; if (flag5) { thing2 = HealthAIUtility.FindBestMedicine(pawn, pawn); } bool flag6 = thing2 != null; Job job; if (flag6) { job = new Job(YautjaDefOf.RRY_Yautja_TendSelf, thing, thing2); } else { job = new Job(YautjaDefOf.RRY_Yautja_TendSelf, thing); } result = new ThinkResult(job, this, null, false); } } } } return(result); }
private bool KeepRoomUnlockedForTending(Pawn patient) { if ((Settings.KeepUnlockedForUrgentTending && HealthAIUtility.ShouldBeTendedNowByPlayerUrgent(patient)) || (Settings.KeepUnlockedForSurgery && HealthAIUtility.ShouldHaveSurgeryDoneNow(patient)) || (Settings.KeepUnlockedForAnyTending && HealthAIUtility.ShouldBeTendedNowByPlayer(patient))) { return(true); } return(false); }
public bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false) { Pawn pawn2 = t as Pawn; if (pawn2 == null || pawn.WorkTypeIsDisabled(WorkTypeDefOf.Doctor) || !GoodLayingStatusForTend(pawn2, pawn) || !HealthAIUtility.ShouldBeTendedNowByPlayer(pawn2) || !pawn.CanReserve(pawn2, 1, -1, null, forced)) { return(false); } return(true); }
public static bool Skip(Pawn pawn) { Log.Message($"Skip need tend?"); if (pawn.Map.mapPawns.AllPawnsSpawned.Any(p => HealthAIUtility.ShouldBeTendedNowByPlayer(p) && pawn.CanReserveAndReach(p, PathEndMode.ClosestTouch, Danger.Deadly, ignoreOtherReservations: true))) { return(true); } if (pawn.Map.mapPawns.AllPawnsSpawned.Any(p => p is IBillGiver billGiver && billGiver.BillStack.AnyShouldDoNow && pawn.CanReserveAndReach(p, PathEndMode.ClosestTouch, Danger.Deadly, ignoreOtherReservations: true))) { return(true); } return(false); }
private static void Postfix(ref bool __result, ref WorkGiver_Tend __instance, Pawn pawn, Thing t, bool forced) { if (__result || t == pawn && !(__instance is WorkGiver_TendSelf)) { return; } if (t is Pawn target && target.IsCaptiveOf(pawn.Faction) && !pawn.WorkTypeIsDisabled(WorkTypeDefOf.Doctor) && (!__instance.def.tendToHumanlikesOnly || target.RaceProps.Humanlike && !target.IsWildMan()) && (!__instance.def.tendToAnimalsOnly || target.AnimalOrWildMan()) && target.GetPosture() != PawnPosture.Standing && HealthAIUtility.ShouldBeTendedNowByPlayer(target) && pawn.CanReserve(target, 1, -1, null, forced)) { __result = true; } }
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false) { if (!pawn.story.traits.HasTrait(WizardryDefOf.LotRW_Istari)) { return(false); } var comp = pawn.GetComp <CompWizardry>(); var pawnAbility = comp.AbilityData.Powers.FirstOrDefault(x => x.Def == WizardryDefOf.LotRW_Nienna_HealingTouch); if (!(t is Pawn pawn2)) { return(false); } if (def.tendToHumanlikesOnly && !pawn2.RaceProps.Humanlike) { return(false); } if (def.tendToAnimalsOnly && !pawn2.RaceProps.Animal) { return(false); } if (!GoodLayingStatusForTend(pawn2, pawn)) { return(false); } if (!HealthAIUtility.ShouldBeTendedNowByPlayer(pawn2)) { return(false); } if (!HasHediffInjuries(pawn2)) { return(false); } if (pawn == pawn2) { return(false); } if (pawnAbility is { CooldownTicksLeft : > 0 })
//public class Alert_NeedDoctor : Alert public static bool get_Patients_Vamp(ref IEnumerable <Pawn> __result) { List <Map> maps = Find.Maps; for (int i = 0; i < maps.Count; i++) { if (maps[i].IsPlayerHome) { HashSet <Pawn> pawns = new HashSet <Pawn>(maps[i].mapPawns.FreeColonistsSpawned); List <Pawn> Patients = new List <Pawn>(); if (pawns != null && pawns.Count > 0 && pawns.FirstOrDefault(x => x.IsVampire()) != null) { if (pawns.FirstOrDefault(x => !x.Downed && x.workSettings != null && x.workSettings.WorkIsActive(WorkTypeDefOf.Doctor)) != null) { foreach (Pawn p2 in pawns) { if (p2.IsVampire()) { if (HealthAIUtility.ShouldBeTendedNowByPlayer(p2)) { Patients.Add(p2); } } else { if (p2.Downed && (p2?.needs?.food?.CurCategory ?? HungerCategory.Fed) < HungerCategory.Fed && p2.InBed() || HealthAIUtility.ShouldBeTendedNowByPlayer(p2)) { Patients.Add(p2); } } } } __result = null; __result = Patients; return(false); } } } return(true); }
public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobParams) { var need = pawn.needs.TryGetNeed <Need_Motivation>(); if (pawn.timetable == null) { WorkSettings.InitWorkSettings(pawn); } if (HealthAIUtility.ShouldHaveSurgeryDoneNow(pawn)) { return(ThinkResult.NoJob); } if (PrisonLaborPrefs.EnableFullHealRest && (HealthAIUtility.ShouldBeTendedNowByPlayer(pawn) || HealthAIUtility.ShouldSeekMedicalRest(pawn))) { return(ThinkResult.NoJob); } //Check medical assistance, fed, and rest if not override if (!PrisonLaborUtility.WorkTime(pawn)) { Other.Tutorials.Timetable(); if (need != null) { need.IsPrisonerWorking = false; } return(ThinkResult.NoJob); } //Check motivation if (PrisonLaborPrefs.EnableMotivationMechanics && (need == null || need.IsLazy)) { return(ThinkResult.NoJob); } //Work prisoners will do WorkSettings.InitWorkSettings(pawn); var workList = pawn.workSettings.WorkGiversInOrderNormal; //TODO check this //workList.RemoveAll(workGiver => workGiver.def.defName == "GrowerSow"); if (need != null) { need.IsPrisonerWorking = false; } var num = -999; var targetInfo = TargetInfo.Invalid; WorkGiver_Scanner workGiver_Scanner = null; for (var j = 0; j < workList.Count; j++) { var workGiver = workList[j]; if (workGiver.def.priorityInType != num && targetInfo.IsValid) { break; } if (PawnCanUseWorkGiver(pawn, workGiver)) { try { var job2 = workGiver.NonScanJob(pawn); if (job2 != null) { if (need != null) { need.IsPrisonerWorking = true; } return(new ThinkResult(job2, this, workList[j].def.tagToGive)); } var scanner = workGiver as WorkGiver_Scanner; if (scanner != null) { if (workGiver.def.scanThings) { Predicate <Thing> predicate = t => !t.IsForbidden(pawn) && scanner.HasJobOnThing(pawn, t, false); var enumerable = scanner.PotentialWorkThingsGlobal(pawn); Thing thing; if (scanner.Prioritized) { var enumerable2 = enumerable; if (enumerable2 == null) { enumerable2 = pawn.Map.listerThings.ThingsMatching(scanner.PotentialWorkThingRequest); } var validator = predicate; thing = GenClosest.ClosestThing_Global_Reachable(pawn.Position, pawn.Map, enumerable2, scanner.PathEndMode, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, x => scanner.GetPriority(pawn, x)); } else { var validator = predicate; var forceGlobalSearch = enumerable != null; thing = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, scanner.PotentialWorkThingRequest, scanner.PathEndMode, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, enumerable, 0, scanner.MaxRegionsToScanBeforeGlobalSearch, forceGlobalSearch, RegionType.Set_Passable, false); } if (thing != null) { targetInfo = thing; workGiver_Scanner = scanner; } } if (workGiver.def.scanCells) { var position = pawn.Position; var num2 = 99999f; var num3 = -3.40282347E+38f; var prioritized = scanner.Prioritized; foreach (var current in scanner.PotentialWorkCellsGlobal(pawn)) { var flag = false; float num4 = (current - position).LengthHorizontalSquared; if (prioritized) { if (!current.IsForbidden(pawn) && scanner.HasJobOnCell(pawn, current)) { var priority = scanner.GetPriority(pawn, current); if (priority > num3 || priority == num3 && num4 < num2) { flag = true; num3 = priority; } } } else if (num4 < num2 && !current.IsForbidden(pawn) && scanner.HasJobOnCell(pawn, current)) { flag = true; } if (flag) { targetInfo = new TargetInfo(current, pawn.Map, false); workGiver_Scanner = scanner; num2 = num4; } } } } } catch (Exception ex) { Log.Error(string.Concat(pawn, " threw exception in WorkGiver ", workGiver.def.defName, ": ", ex.ToString())); } finally { } if (targetInfo.IsValid) { Job job3; if (targetInfo.HasThing) { job3 = workGiver_Scanner.JobOnThing(pawn, targetInfo.Thing, false); } else { job3 = workGiver_Scanner.JobOnCell(pawn, targetInfo.Cell); } if (job3 != null) { job3.workGiverDef = workGiver.def; if (need != null) { need.IsPrisonerWorking = true; } return(new ThinkResult(job3, this, workList[j].def.tagToGive)); } Log.ErrorOnce( string.Concat(workGiver_Scanner, " provided target ", targetInfo, " but yielded no actual job for pawn ", pawn, ". The CanGiveJob and JobOnX methods may not be synchronized."), 6112651); } num = workGiver.def.priorityInType; } } return(ThinkResult.NoJob); }
protected override IEnumerable <Toil> MakeNewToils() { //Reserve the takee yield return(Toils_Reserve.Reserve(TargetIndex.A, 1)); //Reserve the bed yield return(Toils_Reserve.Reserve(TargetIndex.B, 1)); //Claim the bed for the takee Toil claimBed = new Toil(); claimBed.initAction = () => { if (Takee.ownership != null && Takee.ownership.OwnedBed != DropBed && !DropBed.Medical) { Takee.ownership.ClaimBedIfNonMedical((Building_Bed)DropBed); } }; yield return(claimBed); Func <bool> ownershipFail = () => { if (DropBed.Medical) { if (DropBed.AnyUnownedSleepingSlot && DropBed.CurOccupants != Takee) { return(true); } } else if (DropBed.OwnersForReading != null && !DropBed.OwnersForReading.Contains(Takee)) { return(true); } return(false); }; //Goto takee yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch) .FailOnDestroyedNullOrForbidden(TargetIndex.A) .FailOnDestroyedNullOrForbidden(TargetIndex.B) .FailOn(ownershipFail) //Abandon if takee loses bed ownership .FailOn(() => this.job.def == JobDefOf.Arrest && !Takee.CanBeArrestedBy(this.pawn)) //Abandon arrest if takee is not of a team who is willing to be arrested .FailOn(() => !pawn.CanReach(DropBed, PathEndMode.OnCell, Danger.Deadly))); //.FailOn(()=>!pawn.CanReach( DropBed, PathEndMode.OnCell, Danger.Deadly ) ); // From Alpha 8 //Make unconscious if needed Toil makeUnconscious = new Toil(); makeUnconscious.initAction = () => { //Log.Error("Applying Anesthetic"); //Takee.healthTracker.ApplyAnesthetic(); Does not work with AIPawn Takee.health.forceIncap = true; Takee.health.AddHediff(HediffDefOf.Anesthetic, null, null); Takee.health.forceIncap = false; }; yield return(makeUnconscious); //Start carrying the takee yield return(Toils_Haul.StartCarryThing(TargetIndex.A)); //Change takee to prisoner if necessary Toil makePrisoner = new Toil(); makePrisoner.initAction = () => { if (this.job.def == JobDefOf.Arrest || this.job.def == JobDefOf.Capture || this.job.def == JobDefOf.TakeWoundedPrisonerToBed) { if (Takee.HostFaction != Faction.OfPlayer) { Takee.guest.SetGuestStatus(Faction.OfPlayer, true); } } }; yield return(makePrisoner); yield return(Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.Touch) .FailOnDestroyedNullOrForbidden(TargetIndex.A)); //Note no failure conditions here //Because otherwise it's easy to get wardens to drop prisoners in arbitrary places. //I'd rather they just go to wherever they were going. // if( DropBed.owner != Takee ) // return true; //return !Toils.CanInteractStandard(DropBed); //Unreserve bed so takee can use it yield return(Toils_Reserve.Release(TargetIndex.B)); //Drop in or near bed Toil tuckIntoBed = new Toil(); tuckIntoBed.initAction = () => { //Note: We don't stop the task if the bed is destroyed or changes ownership //because then the wardens drop prisoners at random points and they escape //So we have to handle some ugly cases here //note this may use the position of a destroyed bed IntVec3 dropPos = DropBed.Position; Thing unused; pawn.carryTracker.TryDropCarriedThing(dropPos, ThingPlaceMode.Direct, out unused); //Should we tuck them into bed? if ((Takee.Downed || Takee.health.HasHediffsNeedingTend(false) || ((HealthAIUtility.ShouldSeekMedicalRest(Takee) || HealthAIUtility.ShouldBeTendedNowByPlayer(Takee) || HealthAIUtility.ShouldBeTendedNowByPlayerUrgent(Takee)) && DropBed.Medical)) && !DropBed.Destroyed && (DropBed.OwnersForReading.Contains(Takee) || (DropBed.Medical && DropBed.AnyUnoccupiedSleepingSlot)) //They could have lost ownership and the last toil would continue ) { Takee.jobs.Notify_TuckedIntoBed(DropBed); } if (Takee.IsPrisonerOfColony) { LessonAutoActivator.TeachOpportunity(ConceptDefOf.PrisonerTab, Takee, OpportunityType.GoodToKnow); } }; tuckIntoBed.defaultCompleteMode = ToilCompleteMode.Instant; yield return(tuckIntoBed); }
static bool Prefix(ref Pawn_JobTracker_Crutch __instance, Job newJob, bool fromQueue) { try { if (__instance == null || __instance._pawn == null || !__instance._pawn.IsColonistPlayerControlled || newJob == null || newJob.def == null) { return(true); } if (Settings.fun_police && __instance._pawn.needs?.joy != null && __instance._pawn.needs.joy.CurLevel < 0.8f) { CompJoyToppedOff c = __instance._pawn.TryGetComp <CompJoyToppedOff>(); if (c != null) { c.JoyToppedOff = false; } } if (!Settings.clean_before_work && !Settings.hauling_over_bills) { return(true); } if (!newJob.def.allowOpportunisticPrefix && newJob.def != JobDefOf.SpectateCeremony) { return(true); } Job job = null; if (newJob.def == JobDefOf.DoBill) { if (Settings.hauling_over_bills) { job = Hauling_Opportunity(newJob, __instance._pawn); } } else if (!fromQueue && !newJob.playerForced && newJob.targetA != null && newJob.targetA.Cell != null) { IntVec3 cell = newJob.targetA.Cell; if (!cell.IsValid || cell.IsForbidden(__instance._pawn) || __instance._pawn.Downed) { return(true); } if (Settings.clean_before_work && ( newJob.def == JobDefOf.PrisonerAttemptRecruit || newJob.def == JobDefOf.PrisonerConvert || newJob.def == JobDefOf.PrisonerEnslave || newJob.def == JobDefOf.SpectateCeremony || newJob.targetA.Thing != null && newJob.targetA.Thing.GetType().IsSubclassOf(typeof(Building)) && newJob.def != JobDefOf.PlaceNoCostFrame && newJob.def != JobDefOf.FinishFrame || newJob.def.joyKind != null ) && !HealthAIUtility.ShouldBeTendedNowByPlayer(__instance._pawn)) { job = Cleaning_Opportunity(newJob, cell, __instance._pawn, Settings.op_clean_num); } } if (job != null) { if (Settings.add_to_que) { __instance.jobQueue.EnqueueFirst(newJob); } __instance.jobQueue.EnqueueFirst(job); return(false); } } catch (Exception e) { Log.Warning($"CommonSense: opportunistic task skipped due to error ({e.Message}) ({__instance._pawn}, {newJob})"); } return(true); }
static bool Prefix(ref Pawn_JobTracker_Crutch __instance, Job newJob, JobCondition lastJobEndCondition, ThinkNode jobGiver, bool resumeCurJobAfterwards, bool cancelBusyStances, ThinkTreeDef thinkTree, JobTag?tag, bool fromQueue) { if (__instance == null || __instance._pawn == null || !__instance._pawn.IsColonistPlayerControlled || newJob == null || newJob.def == null) { return(true); } if (Settings.fun_police && __instance._pawn.needs.joy != null && __instance._pawn.needs.joy.CurLevel < 0.8f) { CompJoyToppedOff c = __instance._pawn.TryGetComp <CompJoyToppedOff>(); if (c != null) { c.JoyToppedOff = false; } } if (!Settings.clean_before_work && !Settings.hauling_over_bills) { return(true); } if (!newJob.def.allowOpportunisticPrefix) { return(true); } Job job = null; if (newJob.def == JobDefOf.DoBill) { if (Settings.hauling_over_bills) { job = Hauling_Opportunity(newJob, __instance._pawn); } } else if (!newJob.playerForced && newJob.targetA != null && newJob.targetA.Cell != null) { IntVec3 cell = newJob.targetA.Cell; if (!cell.IsValid || cell.IsForbidden(__instance._pawn) || __instance._pawn.Downed) { return(true); } if (Settings.clean_before_work && (newJob.targetA.Thing != null && newJob.targetA.Thing.GetType().IsSubclassOf(typeof(Building)) || newJob.def.joyKind != null) && !HealthAIUtility.ShouldBeTendedNowByPlayer(__instance._pawn)) { job = Cleaning_Opportunity(newJob, cell, __instance._pawn, Settings.op_clean_num); } } //Log.Message($"pawn={__instance._pawn},job={newJob},enque={job}, limit = {Settings.op_clean_num}"); if (job != null) { if (Settings.add_to_que) { newJob.playerForced = true; __instance.jobQueue.EnqueueFirst(newJob); } __instance.jobQueue.EnqueueFirst(job); //__instance.curJob = null; //__instance.curDriver = null; return(false); } return(true); }