public static InjurySeverity GetTendSeverity(this Pawn patient) { if (!HealthAIUtility.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)) { return(InjurySeverity.LifeThreathening); } // going to die in <12 hours, or any immunity < severity and can be fatal if (ticksToDeathDueToBloodLoss <= GenDate.TicksPerHour * 12 || hediffs.Any(PotentiallyLethalDisease)) { return(InjurySeverity.Major); } // otherwise return(InjurySeverity.Minor); }
protected override Job TryGiveJob(Pawn pawn) { Log.Message(pawn + " JobGiver_StockUp"); if (pawn.StockUpIsFull()) { return(null); } Log.Message("Skip need tend?"); if (pawn.Map.mapPawns.AllPawnsSpawned.Any(p => HealthAIUtility.ShouldBeTendedNow(p) && pawn.CanReserveAndReach(p, PathEndMode.ClosestTouch, Danger.Deadly))) { return(null); } Log.Message("any things?"); IEnumerable <Thing> things = pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.HaulableEver); Predicate <Thing> validator = (Thing t) => pawn.StockingUpOn(t) && pawn.StockUpNeeds(t) > 0 && pawn.CanReserve(t, FindBestMedicine.maxPawns, 1) && !t.IsForbidden(pawn); Thing thing = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.HaulableEver), PathEndMode.ClosestTouch, TraverseParms.For(pawn), 9999, validator); if (thing != null) { int pickupCount = Math.Min(pawn.StockUpNeeds(thing), MassUtility.CountToPickUpUntilOverEncumbered(pawn, thing)); Log.Message(pawn + " stock thing is " + thing + ", count " + pickupCount); if (pickupCount > 0) { return new Job(SmartMedicineJobDefOf.StockUp, thing) { count = pickupCount } } ; } Log.Message(pawn + " looking to return"); Thing toReturn = pawn.StockUpThingToReturn(); if (toReturn == null) { return(null); } Log.Message("returning " + toReturn); int dropCount = -pawn.StockUpNeeds(toReturn); Log.Message("dropping " + dropCount); if (StoreUtility.TryFindBestBetterStoreCellFor(toReturn, pawn, pawn.Map, StoragePriority.Unstored, pawn.Faction, out IntVec3 dropLoc, true)) { return new Job(SmartMedicineJobDefOf.StockDown, toReturn, dropLoc) { count = dropCount } } ; Log.Message("nowhere to store"); return(null); } } }
public override void Tick() { base.Tick(); if (OwnerPawn != null && OwnerPawn.Position != this.InteractionCell) { OwnerPawn = null; count = 0; foundInj = null; oldCount = 0; } if (JobPawn != null) { if (OwnerPawn != null) { string messageText1; messageText1 = "Dermal Regenerator in use."; Messages.Message(messageText1, MessageSound.Benefit); JobPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); JobPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); JobPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); JobPawn = null; return; } else { if (this.UsableNow) { if (JobPawn.Position == this.InteractionCell) { OwnerPawn = JobPawn; JobPawn = null; return; } } else if (OwnerPawn == null && !this.UsableNow) { string messageText2; messageText2 = "Dermal Regenerator doesnt have power."; Messages.Message(messageText2, MessageSound.Benefit); JobPawn.jobs.jobQueue.Clear(); JobPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); JobPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); JobPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); JobPawn = null; return; } } } if (OwnerPawn != null && !this.UsableNow) { string messageText3; messageText3 = "Dermal Regenerator power interupted."; Messages.Message(messageText3, MessageSound.Benefit); OwnerPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); OwnerPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); OwnerPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); OwnerPawn.health.AddHediff(HediffDef.Named("DermalRegeneratorSickness"), null, null); OwnerPawn = null; count = 0; foundInj = null; oldCount = 0; return; } if (OwnerPawn != null && OwnerPawn.Position == this.InteractionCell && this.UsableNow) { Map.glowGrid.VisualGlowAt(Position); if (count < 4500) { if (count % 90 == 0) { ThrowMicroSparksBlue(Position.ToVector3(), Map); } if (count % 200 == 0) { ThrowLightningGlowBlue(Position.ToVector3(), Map, 1f); } } else if (count > 4500) { if (count % 90 == 0) { ThrowMicroSparksGreen(Position.ToVector3(), Map); } if (count % 200 == 0) { ThrowLightningGlowGreen(Position.ToVector3(), Map, 1f); } } count++; foreach (Hediff current in OwnerPawn.health.hediffSet.GetHediffs <Hediff>()) { if (current is Hediff_Injury && current.IsOld() && (current.Label.Contains("scar") || current.Label.Contains("Scar"))) { oldCount++; foundInj = current; } } if (count >= 9000) { OwnerPawn.health.hediffSet.hediffs.Remove(foundInj); OwnerPawn.health.Notify_HediffChanged(foundInj); foundInj = null; if (!HealthAIUtility.ShouldBeTendedNow(OwnerPawn)) { string messageText4; messageText4 = "Treatment complete."; Messages.Message(messageText4, MessageSound.Benefit); OwnerPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); OwnerPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); OwnerPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); OwnerPawn.health.AddHediff(HediffDef.Named("DermalRegeneratorSickness"), null, null); count = 0; foundInj = null; oldCount = 0; OwnerPawn = null; } } if (count == 4500) { if (foundInj == null) { string messageText5; messageText5 = "No surface injuries discovered."; Messages.Message(messageText5, MessageSound.Benefit); OwnerPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); OwnerPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); OwnerPawn.jobs.EndCurrentJob(JobCondition.InterruptForced); OwnerPawn.health.AddHediff(HediffDef.Named("DermalRegeneratorSickness"), null, null); OwnerPawn = null; count = 0; foundInj = null; oldCount = 0; return; } } } }
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.owners != null && !DropBed.owners.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.ShouldBeTendedNow(Takee)) && DropBed.Medical)) && !DropBed.Destroyed && (DropBed.owners.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); }