protected override IEnumerable <Toil> MakeNewToils() { if (!ModLister.RoyaltyInstalled) { Log.ErrorOnce("Bestowing cermonies are a Royalty-specific game system. If you want to use this code please check ModLister.RoyaltyInstalled before calling it. See rules on the Ludeon forum for more info.", 5464564); yield break; } AddFailCondition(() => Bestower.GetLord() == null || Bestower.GetLord().CurLordToil == null || !(Bestower.GetLord().CurLordToil is LordToil_BestowingCeremony_Wait)); yield return(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.OnCell)); Toil waitToil = Toils_General.Wait(471); waitToil.AddPreInitAction(delegate { Messages.Message("MessageBestowingCeremonyStarted".Translate(pawn.Named("PAWN")), Bestower, MessageTypeDefOf.PositiveEvent); }); waitToil.AddPreInitAction(delegate { if (!AnalyzeThroneRoom(Bestower, pawn)) { Messages.Message("BestowingCeremonyThroneroomRequirementsNotSatisfied".Translate(pawn.Named("PAWN"), pawn.royalty.GetTitleAwardedWhenUpdating(Bestower.Faction, pawn.royalty.GetFavor(Bestower.Faction)).label.Named("TITLE")), pawn, MessageTypeDefOf.NegativeEvent); ((LordJob_BestowingCeremony)Bestower.GetLord().LordJob).MakeCeremonyFail(); } }); waitToil.AddPreInitAction(delegate { SoundDefOf.Bestowing_Start.PlayOneShot(pawn); }); waitToil.tickAction = delegate { pawn.rotationTracker.FaceTarget(Bestower); if (mote == null || mote.Destroyed) { Vector3 loc = (pawn.TrueCenter() + Bestower.TrueCenter()) / 2f; mote = MoteMaker.MakeStaticMote(loc, pawn.Map, ThingDefOf.Mote_Bestow); } mote.Maintain(); if ((sound == null || sound.Ended) && waitToil.actor.jobs.curDriver.ticksLeftThisToil <= 307) { sound = SoundDefOf.Bestowing_Warmup.TrySpawnSustainer(SoundInfo.InMap(new TargetInfo(pawn.Position, pawn.Map), MaintenanceType.PerTick)); } if (sound != null) { sound.Maintain(); } }; waitToil.handlingFacing = false; waitToil.socialMode = RandomSocialMode.Off; waitToil.WithProgressBarToilDelay(TargetIndex.A); yield return(waitToil); yield return(Toils_General.Do(delegate { CeremonyJob.FinishCeremony(pawn); MoteMaker.MakeStaticMote((pawn.TrueCenter() + Bestower.TrueCenter()) / 2f, pawn.Map, ThingDefOf.Mote_PsycastAreaEffect, 2f); SoundDefOf.Bestowing_Finished.PlayOneShot(pawn); })); }
public static void _ctor(Toil __instance) { if (SimpleSidearms.ToolAutoSwitch == true) { Toil toil = __instance; toil.AddPreInitAction(delegate { if (toil.activeSkill != null && toil.activeSkill() != null && toil.GetActor() != null) { //Log.Message("Pawn " + toil.GetActor().Label + " initializing toil that uses skill " + toil.activeSkill().label); bool usingAppropriateTool = WeaponAssingment.equipBestWeaponFromInventoryByStatModifiers(toil.GetActor(), SkillStatMap.Map[toil.activeSkill()]); if (usingAppropriateTool) { GoldfishModule pawnMemory = GoldfishModule.GetGoldfishForPawn(toil.GetActor()); if (pawnMemory != null) { pawnMemory.autotoolToil = toil; } } } }); toil.AddFinishAction(delegate { GoldfishModule pawnMemory = GoldfishModule.GetGoldfishForPawn(toil.GetActor()); if (pawnMemory != null && pawnMemory.autotoolToil == toil) { pawnMemory.delayIdleSwitchTimestamp = Find.TickManager.TicksGame; } pawnMemory.autotoolToil = null; }); } }
public static void Postfix(Toil __instance) { if (__instance == null) { return; } __instance.AddPreInitAction(delegate { Pawn pawn = __instance.GetActor(); if (pawn == null || pawn.Dead || pawn.equipment == null || pawn.inventory == null || !pawn.RaceProps.Humanlike) { return; } if (pawn.Drafted) { GrabYourToolMod.Instance.ClearMemory(pawn); return; } SkillDef activeSkill = pawn.CurJob?.RecipeDef?.workSkill; if (__instance.activeSkill != null && __instance.activeSkill() != null) { activeSkill = __instance.activeSkill(); } if (activeSkill != null) { ToolMemory memory = GrabYourToolMod.Instance.GetMemory(pawn); if (!memory.UpdateSkill(activeSkill)) { return; } // Don't do it if this job uses weapons (i.e. hunting) if (activeSkill == SkillDefOf.Shooting || activeSkill == SkillDefOf.Melee) { memory.UpdateUsingTool(null, false); } // Check currently equipped item else if (pawn.equipment.Primary != null && ToolMemoryTracker.HasReleventStatModifiers(pawn.equipment.Primary, activeSkill)) { memory.UpdateUsingTool(null, true); } // Try and find something else in inventory else { memory.UpdateUsingTool(pawn.equipment.Primary, ToolMemoryTracker.EquipAppropriateWeapon(pawn, activeSkill)); } } else { GrabYourToolMod.Instance.ClearMemory(pawn); } }); }
protected override void ModifyPlayToil(Toil toil) { base.ModifyPlayToil(toil); toil.AddPreInitAction(delegate { MusicalInstrument.StartPlaying(pawn); }); toil.AddFinishAction(delegate { MusicalInstrument.StopPlaying(); }); }
public static Toil PlaceBookInShelf(TargetIndex book, TargetIndex shelf, Pawn pawn) { ReadableBooks bookint = (ReadableBooks)pawn.jobs.curJob.GetTarget(book).Thing; Bookshelf bookshelf = (Bookshelf)pawn.jobs.curJob.GetTarget(shelf).Thing; Log.Message("Trying to place book"); Toil toil = new Toil(); toil.defaultCompleteMode = ToilCompleteMode.Instant; toil.AddPreInitAction(delegate { bookint.Destroy(DestroyMode.Vanish); bookshelf.AddBookToLibrary(bookint.Tdef); }); return(toil); }
protected override IEnumerable <Toil> MakeNewToils() { this.FailOn(() => Find.World.GetComponent <WorldComponent_Uvhash>().CurrentBloodMage != null); this.EndOnDespawnedOrNull(InvestigateeIndex, JobCondition.Incompletable); //this.EndOnDespawnedOrNull(Build, JobCondition.Incompletable); yield return(Toils_Reserve.Reserve(InvestigateeIndex, this.job.def.joyMaxParticipants)); var gotoInvestigatee = Toils_Goto.GotoThing(InvestigateeIndex, PathEndMode.ClosestTouch); yield return(gotoInvestigatee); yield return(Toils_Goto.GotoCell(Investigatee.InteractionCell, PathEndMode.OnCell)); var watchToil = new Toil { defaultCompleteMode = ToilCompleteMode.Delay, defaultDuration = this.job.def.joyDuration }; watchToil.AddPreInitAction(() => { ticksLeft = this.job.def.joyDuration; }); watchToil.WithProgressBar(TargetIndex.A, () => 1f - (float)watchToil.actor.jobs.curDriver.ticksLeftThisToil / Mathf.Round((float)watchToil.actor.CurJob.def.joyDuration)); watchToil.AddPreTickAction(() => { ticksLeft--; this.pawn.rotationTracker.FaceCell(this.TargetA.Cell); this.pawn.GainComfortFromCellIfPossible(); }); watchToil.AddFinishAction(() => { Find.World.GetComponent <WorldComponent_Uvhash>().Notify_BloodBond(this.pawn); }); yield return(watchToil); }
/// <summary> /// 行为过程 /// </summary> /// <returns></returns> protected override IEnumerable <Toil> MakeNewToils() { this.FailOnDestroyedOrNull(TargetIndex.A); this.FailOnDestroyedOrNull(TargetIndex.B); this.FailOnAggroMentalStateAndHostile(TargetIndex.B); //B精神不正常 yield return(Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.ClosestTouch)); //走到囚犯身边 yield return(Toils_Haul.StartCarryThing(TargetIndex.B, false, false, false)); //搬运囚犯 yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch).FailOnForbidden(TargetIndex.A)); //走到dark家具旁边 Pawn prisoner = (Pawn)Target; Building_ElectricChair chair = (Building_ElectricChair)Thing; if (!prisoner.Dead) { Toil toilWaitWith = Toils_General.WaitWith(TargetIndex.A, 180, true, true); //交互3秒 var cpt = chair.GetComp <CompPowerTrader>() ?? throw new Exception("cant find comp:CompPowerTrader"); toilWaitWith.AddPreInitAction(() => { chair.OnOrOff(true); }); //启动电椅 提高电力负载 toilWaitWith.AddFinishAction(() => { chair.OnOrOff(false); }); //恢复电力负载 toilWaitWith.tickAction = delegate() { if (!cpt.PowerOn) { ////Power interruption leads to { 0 } electrocution failure Messages.Message("SR_ElectrocutionFailure".Translate(prisoner.Label), MessageTypeDefOf.NeutralEvent); pawn.jobs.EndCurrentJob(JobCondition.Incompletable, true, true); } }; yield return(toilWaitWith); //交互 yield return(new Toil { initAction = delegate() { this.pawn.carryTracker.TryDropCarriedThing(this.Thing.Position, ThingPlaceMode.Direct, out Verse.Thing thing, null);//把囚犯扔下去 }, defaultCompleteMode = ToilCompleteMode.Instant });
public static void Postfix(Toil __result, TargetIndex cellInd) { // make the "initAction" a final action: //TODO:::: Make a wrapper around old initAction that doesn't put // stuff down if failure happens? // __result.preInitActions.Add(delegate () { __result.actor.jobs.debugLog = true; }); // __result.AddFinishAction(__result.initAction); // replace it with a test for Deep Storage // and if it IS deep storage, set up wait: Action placeStuff = __result.initAction; __result.AddPreInitAction(delegate() { __result.tickAction = null; Pawn actor = __result.actor; Job curJob = actor.jobs.curJob; IntVec3 cell = curJob.GetTarget(cellInd).Cell; if (actor.carryTracker.CarriedThing == null) { Log.Error(actor + " tried to place hauled thing in cell but is not hauling anything?", false); return; } SlotGroup slotGroup = actor.Map.haulDestinationManager.SlotGroupAt(cell); ThingComp comp; if (slotGroup == null || !(slotGroup?.parent is ThingWithComps) || (comp = ((ThingWithComps)slotGroup.parent).TryGetComp <CompDeepStorage>()) == null) { __result.initAction = placeStuff; return; } int timeStoringTakes = ((LWM.DeepStorage.Properties)comp.props).timeStoringTakes; if (timeStoringTakes <= 0) // just like vanilla { __result.initAction = placeStuff; return; } __result.initAction = null; __result.tickAction = delegate() { if (actor.jobs.curDriver.ticksLeftThisToil == 1) // last tick is 1, not 0 { placeStuff(); } }; actor.jobs.curDriver.ticksLeftThisToil = timeStoringTakes; __result.WithProgressBar(TargetIndex.B, () => 1f - (float)__result.actor.jobs.curDriver.ticksLeftThisToil / timeStoringTakes, true); Thing t = actor.CurJob.GetTarget(TargetIndex.A).Thing; // Add some end conditions: if (t != null) { __result.FailOn(() => !slotGroup.parent.Accepts(t)); } }); // added pre-init action! // HMM...let's get rid of stuff: __result.initAction = null; __result.atomicWithPrevious = false; __result.defaultCompleteMode = ToilCompleteMode.Delay; __result.defaultDuration = 0; // changed by initAction, if needed __result.FailOnBurningImmobile(TargetIndex.B); // TODO: FailOn&c, EndOn&c // Other fails..... // No longer allowed in that area? // No longer accepts what we're puttin there? // Um? } // end Postfix
public static void Postfix(Toil __result, TargetIndex cellInd) { Utils.Err(PlaceHauledThingInCell, "Starting new haul job, toils created"); //TODO? Make a wrapper around old initAction that doesn't put // stuff down if failure happens? SlotGroup groupAt = __result?.actor?.Map?.haulDestinationManager?.SlotGroupAt(__result.actor?.CurJob?.GetTarget(cellInd).Cell ?? IntVec3.Invalid); if ((groupAt?.parent as ThingWithComps)?.GetComp <CompDeepStorage>() == null) { Utils.Err(PlaceHauledThingInCell, "Not going into Deep Storage, exiting ASAP without modifying anything."); return; } Action placeStuff = __result.initAction; // NOTE: none of this PreInitAtion happens if the game is being loaded while storing is going on: // This means, among other things, that pawns don't get progress bars on reload // I could make it happen if it ever gets to be important... __result.AddPreInitAction(delegate() { Pawn actor = __result.actor; Job curJob = actor.jobs.curJob; IntVec3 cell = curJob.GetTarget(cellInd).Cell; Utils.Err(PlaceHauledThingInCell, "PreInitAction called for " + actor + "'s haul job " + curJob.def.driverClass + " to " + cell); // Log.Error("Place Hauled Thing in Cell: Toil preInit! Putting in "+cell.ToString()); // actor.jobs.debugLog = true; if (actor.carryTracker.CarriedThing == null) { // error as per original toil code Log.Error(actor + " tried to place hauled thing in cell but is not hauling anything?", false); return; } SlotGroup slotGroup = actor.Map.haulDestinationManager.SlotGroupAt(cell); CompDeepStorage cds; if (!(slotGroup?.parent is ThingWithComps) || (cds = (((ThingWithComps)slotGroup?.parent)?.GetComp <CompDeepStorage>())) == null) { Utils.Warn(PlaceHauledThingInCell, "not going into Deep Storage"); return; // initAction still around, will handle } int timeStoringTakes = cds.timeStoringTakes(cell); if (timeStoringTakes <= 0) { // just like vanilla Utils.Warn(PlaceHauledThingInCell, "Instantaneous storing time"); return; } // Remove the initAction so it doesn't happen before waiting starts: __result.initAction = null; if (actor.jobs.curDriver.ticksLeftThisToil < 1) // test is probably superfluous { actor.jobs.curDriver.ticksLeftThisToil = timeStoringTakes; } // It'd be nice to have a progress bar for deep storage __result.WithProgressBar(TargetIndex.B, () => 1f - (float)__result.actor.jobs.curDriver.ticksLeftThisToil / timeStoringTakes, true); /***** Add some end conditions: *****/ Thing t = actor.CurJob.GetTarget(TargetIndex.A).Thing; if (t != null) { __result.FailOn(() => !slotGroup.parent.Accepts(t)); } // TODO: any other end conditions? Fail conditions? // TODO: Any reservations? }); // added pre-init action! // The tickAction is only called if we are going into Deep Storage, // otherwise the toil is over after initAction and no ticks happen. // This will still get called even on load/save, because ticks count down. __result.tickAction = delegate() { Pawn pawn = __result.actor; Utils.Warn(PlaceHauledThingInCell, " " + pawn + "'s ticks left: " + __result.actor.jobs.curDriver.ticksLeftThisToil); if (pawn.jobs.curDriver.ticksLeftThisToil <= 1) // last tick is 1, not 0 { Utils.Err(PlaceHauledThingInCell, "Hit 0 ticks"); placeStuff(); } }; // ToilCompleteMode.Delay is acceptable in vanilla case, as duration is 0: __result.defaultCompleteMode = ToilCompleteMode.Delay; __result.defaultDuration = 0; // changed by PreInitAction, if needed __result.FailOnBurningImmobile(TargetIndex.B); // todo reservations (possibly?) // also todo, undo reservations (possibly?) (as another final action?) // TODO: FailOn&c, EndOn&c // Other fails..... // No longer allowed in that area? <--- Very definitely TODO // Um? } // end Postfix
public static void _ctor(Toil __instance) { if (SimpleSidearms.ToolAutoSwitch == true) { Toil toil = __instance; if (toil == null) { return; } toil.AddPreInitAction(delegate { Pawn pawn = toil.GetActor(); if (pawn == null || !pawn.IsValidSidearmsCarrier()) { return; } CompSidearmMemory pawnMemory = CompSidearmMemory.GetMemoryCompForPawn(pawn); if (pawnMemory == null) { return; } pawnMemory.CheckIfStillOnAutotoolJob(); StatDef activeStat = pawn.CurJob?.RecipeDef?.workSpeedStat; SkillDef activeSkill = null; if (toil.activeSkill != null && toil.activeSkill() != null) { activeSkill = toil.activeSkill(); } else { activeSkill = pawn.CurJob?.RecipeDef?.workSkill; } List <StatDef> possiblyActiveStats = new List <StatDef>(); if (activeStat != null) { possiblyActiveStats.Add(activeStat); } else if (activeSkill != null && SkillStatMap.Map.ContainsKey(activeSkill)) { possiblyActiveStats.AddRange(SkillStatMap.Map[activeSkill]); } bool usingAppropriateTool = WeaponAssingment.equipBestWeaponFromInventoryByStatModifiers(toil.GetActor(), possiblyActiveStats); if (usingAppropriateTool) { if (pawnMemory != null) { pawnMemory.autotoolToil = toil; pawnMemory.autotoolJob = pawn.CurJobDef; } } }); toil.AddFinishAction(delegate { Pawn pawn = toil.GetActor(); if (!pawn.IsValidSidearmsCarrier()) { return; } CompSidearmMemory pawnMemory = CompSidearmMemory.GetMemoryCompForPawn(pawn); if (pawnMemory != null) { if (pawnMemory.autotoolToil == toil) { pawnMemory.delayIdleSwitchTimestamp = Find.TickManager.TicksGame; } else { pawnMemory.autotoolToil = null; } } }); } }
protected override IEnumerable <Toil> MakeNewToils() { this.EndOnDespawnedOrNull(Executioner, JobCondition.Incompletable); if (CultUtility.AreOccultGrimoiresAvailable(pawn.Map)) { pawn.Map.GetComponent <MapComponent_LocalCultTracker>().CurrentSeedState = CultSeedState.NeedTable; } else { IntVec3 destination = IntVec3.Invalid; //First, let's try and find a typewriter. //If we find one, let's go to it and start typing. Thing Typewriter = null; if (Cthulhu.Utility.IsIndustrialAgeLoaded()) { Cthulhu.Utility.DebugReport("Industrial age check"); if (this.pawn.Map != null) { if (this.pawn.Map.listerBuildings != null) { foreach (Building thing in this.pawn.Map.listerBuildings.allBuildingsColonist) { if (thing.def.defName == "Estate_TableTypewriter") { Typewriter = thing; Cthulhu.Utility.DebugReport("Found typewriter"); Toil gotoDestination = Toils_Goto.GotoCell(Typewriter.InteractionCell, PathEndMode.OnCell); atTypeWriter = true; yield return(gotoDestination); goto SkipRoom; } } } } } //If we don't have a typewriter, then let's go to our personal room or near our bed. Room destinationRoom = this.pawn.ownership.OwnedRoom; Building destinationBed = this.pawn.ownership.OwnedBed; if (destinationRoom != null) { if (destinationRoom.Cells.TryRandomElement <IntVec3>(out destination)) { IntVec3 cellInsideRoom = IntVec3.Invalid; if (Cthulhu.Utility.IsRandomWalkable8WayAdjacentOf(destination, Map, out cellInsideRoom)) { Toil gotoRoom; gotoRoom = Toils_Goto.GotoCell(cellInsideRoom, PathEndMode.OnCell); yield return(gotoRoom); goto SkipRoom; } } } else if (destinationBed != null) { IntVec3 cellNearBed = IntVec3.Invalid; if (Cthulhu.Utility.IsRandomWalkable8WayAdjacentOf(destinationBed.Position, Map, out cellNearBed)) { Toil gotoBedArea; gotoBedArea = Toils_Goto.GotoCell(cellNearBed, PathEndMode.OnCell); } } SkipRoom: Toil altarToil = new Toil(); altarToil.defaultCompleteMode = ToilCompleteMode.Delay; if (atTypeWriter) { altarToil.PlaySustainerOrSound(SoundDef.Named("Estate_SoundManualTypewriter")); } else { altarToil.PlaySustainerOrSound(SoundDef.Named("PencilWriting")); } altarToil.WithProgressBarToilDelay(TargetIndex.A); altarToil.defaultDuration = this.job.def.joyDuration; altarToil.AddPreTickAction(() => { if (Typewriter != null) { this.pawn.rotationTracker.FaceCell(Typewriter.Position); this.pawn.GainComfortFromCellIfPossible(); } }); altarToil.AddPreInitAction(() => { Messages.Message(this.pawn.LabelCap + "WritingStrangeSymbols".Translate(), MessageTypeDefOf.NeutralEvent); }); yield return(altarToil); Toil finishedAction = new Toil(); finishedAction.defaultCompleteMode = ToilCompleteMode.Instant; finishedAction.initAction = delegate { Map.GetComponent <MapComponent_LocalCultTracker>().CurrentSeedState = CultSeedState.FinishedWriting; }; yield return(finishedAction); this.AddFinishAction(() => { if (Map.GetComponent <MapComponent_LocalCultTracker>().CurrentSeedState == CultSeedState.FinishedWriting) { CultUtility.FinishedTheBook(this.pawn); } }); } }
protected override IEnumerable <Toil> MakeNewToils() { this.AddFinishAction(delegate() { if (Patient.CurrentBed() == Bed && Patient.CurJobDef == JobDefOf.LayDown) { Patient.jobs.EndCurrentJob(JobCondition.Succeeded); } }); this.FailOnDestroyedNullOrForbidden(TargetIndex.A); this.FailOnDestroyedNullOrForbidden(TargetIndex.B); this.FailOnDestroyedNullOrForbidden(TargetIndex.C); yield return(Toils_Reserve.Reserve(TargetIndex.A)); yield return(Toils_Reserve.Reserve(TargetIndex.B)); yield return(Toils_Reserve.Reserve(TargetIndex.C)); //Go and get the thing to carry. yield return(Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.OnCell)); yield return(Toils_Haul.StartCarryThing(TargetIndex.B)); yield return(Toils_Goto.GotoThing(TargetIndex.C, PathEndMode.ClosestTouch)); yield return(Toils_Haul.PlaceCarriedThingInCellFacing(TargetIndex.C)); yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell)); yield return(Toils_Haul.StartCarryThing(TargetIndex.A)); yield return(Toils_Goto.GotoThing(TargetIndex.C, PathEndMode.ClosestTouch)); yield return(Toils_Haul.PlaceHauledThingInCell(TargetIndex.C, null, false)); yield return(Toils_Reserve.Release(TargetIndex.C)); Toil applyBrainTemplateToil = new Toil() { defaultCompleteMode = ToilCompleteMode.Never, initAction = delegate() { Patient.pather.StopDead(); Patient.jobs.StartJob(new Job(JobDefOf.LayDown, TargetC) { forceSleep = true }); }, tickAction = delegate() { ticksWork -= 1f * pawn.GetStatValue(StatDefOf.ResearchSpeed); if (ticksWork <= 0) { BrainManipUtility.ApplyBrainScanTemplateOnPawn(Patient, BrainTemplate); Patient.jobs.EndCurrentJob(JobCondition.Succeeded); //Give headache Patient.health.AddHediff(QEHediffDefOf.QE_Headache, Patient.health.hediffSet.GetBrain()); } } }.WithProgressBar(TargetIndex.A, () => (workRequired - ticksWork) / workRequired).WithEffect(EffecterDefOf.Research, TargetIndex.A); applyBrainTemplateToil.AddPreInitAction(delegate() { ticksWork = workRequired; workStarted = true; //Log.Message("preInitAction: ticksWork = " + ticksWork); }); applyBrainTemplateToil.AddEndCondition(delegate() { if (workStarted && ticksWork <= 0) { //Log.Message("Succeeded: ticksWork = " + ticksWork); return(JobCondition.Succeeded); } //Log.Message("Ongoing: ticksWork = " + ticksWork); return(JobCondition.Ongoing); }); applyBrainTemplateToil.AddFailCondition(() => workStarted && Patient.CurJobDef != JobDefOf.LayDown); yield return(applyBrainTemplateToil); }
protected override IEnumerable <Toil> MakeNewToils() { /* * * Toil Configurations * */ Toil prepareToSpin = new Toil(); prepareToSpin.initAction = delegate { if (Prey == null && Corpse == null) { this.pawn.jobs.EndCurrentJob(JobCondition.Incompletable, true); return; } if (Prey.Dead) { this.pawn.CurJob.SetTarget(TargetIndex.A, Prey.Corpse); } }; Toil gotoBody = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch); gotoBody.AddPreInitAction(new Action(delegate { this.pawn.ClearAllReservations(); this.pawn.Reserve(TargetA, this.job); //this.Map.physicalInteractionReservationManager.ReleaseAllForTarget(TargetA); //this.Map.physicalInteractionReservationManager.Reserve(this.GetActor(), TargetA); currentActivity = "Spinning Cocoon"; })); Toil spinDelay = new Toil { defaultCompleteMode = ToilCompleteMode.Delay, defaultDuration = 500, initAction = delegate { currentActivity = "Spinning Cocoon"; } }; spinDelay.WithProgressBarToilDelay(TargetIndex.B); Toil spinBody = new Toil { initAction = delegate { //Log.Message("5"); var spinner = this.GetActor() as Spider; if (spinner != null) { Building_Cocoon newCocoon; Thing toLoad; IntVec3 newPosition; if (Prey.Dead) { toLoad = Prey.Corpse; newPosition = Prey.Corpse.Position; } else { toLoad = Prey; newPosition = Prey.Position; } if (!toLoad.Spawned) { this.EndJobWith(JobCondition.Incompletable); return; } toLoad.DeSpawn(); toLoad.holdingOwner = null; if (!GenConstruct.CanPlaceBlueprintAt(CocoonDef, newPosition, Rot4.North, this.pawn.Map).Accepted) { var cells = GenAdj.CellsAdjacent8Way(new TargetInfo(newPosition, this.pawn.Map)); foreach (IntVec3 cell in cells) { if (GenConstruct.CanPlaceBlueprintAt(CocoonDef, cell, Rot4.North, this.Map).Accepted) { newPosition = cell; break; } } } newCocoon = (Building_Cocoon)GenSpawn.Spawn(CocoonDef, newPosition, spinner.Map); //Log.Message("New Spinner: " + newCocoon.Spinner.Label); newCocoon.TryGetInnerInteractableThingOwner().TryAdd(toLoad); this.pawn?.CurJob?.SetTarget(TargetIndex.B, newCocoon); } }, defaultCompleteMode = ToilCompleteMode.Instant }; Toil pickupCocoon = Toils_Haul.StartCarryThing(TargetIndex.B); pickupCocoon.AddPreInitAction(new Action(delegate { //this.TargetB.Thing.DeSpawn(); this.pawn.CurJob.SetTarget(TargetIndex.C, TargetB.Thing); this.pawn.Reserve(TargetC, this.job); //this.pawn.Map.physicalInteractionReservationManager.Reserve(this.pawn, TargetC); })); Toil relocateCocoon = Toils_Haul.CarryHauledThingToCell(TargetIndex.C); Toil dropCocoon = Toils_Haul.PlaceHauledThingInCell(TargetIndex.C, relocateCocoon, false).FailOn(() => !GenConstruct.CanPlaceBlueprintAt(CocoonDef, TargetC.Cell, Rot4.North, this.Map).Accepted); this.AddFinishAction(new Action(delegate { this.pawn.Map.physicalInteractionReservationManager.ReleaseAllClaimedBy(this.pawn); })); /* * * Toil Execution * */ yield return(new Toil { initAction = delegate { this.Map.attackTargetsCache.UpdateTarget(this.pawn); }, atomicWithPrevious = true, defaultCompleteMode = ToilCompleteMode.Instant }); Action onHitAction = delegate { Pawn prey = this.Prey; bool surpriseAttack = this.firstHit && !prey.IsColonist; if (this.pawn.meleeVerbs.TryMeleeAttack(prey, this.job.verbToUse, surpriseAttack)) { if (!this.notifiedPlayer && PawnUtility.ShouldSendNotificationAbout(prey)) { this.notifiedPlayer = true; Messages.Message("MessageAttackedByPredator".Translate(new object[] { prey.LabelShort, this.pawn.LabelIndefinite() }).CapitalizeFirst(), prey, MessageTypeDefOf.ThreatBig);// MessageSound.SeriousAlert); } this.Map.attackTargetsCache.UpdateTarget(this.pawn); } this.firstHit = false; }; //yield return Toils_Combat.FollowAndMeleeAttack(TargetIndex.A, onHitAction).JumpIf(() => Prey.Downed || Prey.Dead, prepareToSpin).FailOn(() => Find.TickManager.TicksGame > this.startTick + 5000 && (float)(this.job.GetTarget(TargetIndex.A).Cell - this.pawn.Position).LengthHorizontalSquared > 4f); yield return(prepareToSpin.FailOn(() => Prey == null)); yield return(gotoBody.FailOn(() => Prey == null)); yield return(spinDelay.FailOn(() => Prey == null)); yield return(spinBody.FailOn(() => Prey == null)); //yield return pickupCocoon; //yield return relocateCocoon; //yield return dropCocoon; //float durationMultiplier = 1f / this.pawn.GetStatValue(StatDefOf.EatingSpeed, true); //yield return Toils_Ingest.ChewIngestible(this.pawn, durationMultiplier, TargetIndex.A, TargetIndex.None).FailOnDespawnedOrNull(TargetIndex.A).FailOnCannotTouch(TargetIndex.A, PathEndMode.Touch); //yield return Toils_Ingest.FinalizeIngest(this.pawn, TargetIndex.A); //yield return Toils_Jump.JumpIf(gotoCorpse, () => this.pawn.needs.food.CurLevelPercentage < 0.9f); }
public override IEnumerable <Toil> MakeNewToils() { AddEndCondition(delegate { Thing thing = GetActor().jobs.curJob.GetTarget(TargetIndex.A).Thing; if (thing is Building && !thing.Spawned) { return(JobCondition.Incompletable); } return(JobCondition.Ongoing); }); this.FailOnBurningImmobile(TargetIndex.A); this.FailOn(delegate() { IBillGiver billGiver = job.GetTarget(TargetIndex.A).Thing as IBillGiver; if (billGiver != null) { if (job.bill.DeletedOrDereferenced) { return(true); } if (!billGiver.CurrentlyUsableForBills()) { return(true); } } if (inShelf && !bookOut && !shelf.innerContainer.Contains(book)) { return(true); } return(false); }); AddFinishAction(delegate { if (inShelf && bookOut) { shelf.CheckBookOut(book, true); } }); Toil gotoBillGiver = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell); yield return(Toils_Jump.JumpIf(gotoBillGiver, () => job.GetTargetQueue(TargetIndex.B).NullOrEmpty <LocalTargetInfo>())); Toil extract = Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.B, true); yield return(extract); Toil getToHaulTarget = Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.ClosestTouch).FailOnDespawnedNullOrForbidden(TargetIndex.B).FailOnSomeonePhysicallyInteracting(TargetIndex.B); yield return(getToHaulTarget); yield return(inShelf ? TakeFromShelf(TargetIndex.B) : Toils_Haul.StartCarryThing(TargetIndex.B, true, false, true)); yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell).FailOnDestroyedOrNull(TargetIndex.B)); Toil findPlaceTarget = Toils_JobTransforms.SetTargetToIngredientPlaceCell(TargetIndex.A, TargetIndex.B, TargetIndex.C); yield return(findPlaceTarget); yield return(Toils_Haul.PlaceHauledThingInCell(TargetIndex.C, findPlaceTarget, false, false)); extract = null; getToHaulTarget = null; findPlaceTarget = null; yield return(gotoBillGiver); yield return(Toils_Recipe.DoRecipeWork().FailOnDespawnedNullOrForbiddenPlacedThings().FailOnCannotTouch(TargetIndex.A, PathEndMode.InteractionCell)); Toil upload = new Toil(); upload.initAction = delegate() { Pawn actor = upload.actor; Job curJob = actor.jobs.curJob; JobDriver_DoBill jobDriver_DoBill = (JobDriver_DoBill)actor.jobs.curDriver; if (curJob.RecipeDef.workSkill != null) { float xp = (float)jobDriver_DoBill.ticksSpentDoingRecipeWork * 0.1f * curJob.RecipeDef.workSkillLearnFactor; actor.skills.GetSkill(curJob.RecipeDef.workSkill).Learn(xp, false); } project.Unlock(TargetThingA, false); Thing scanned = TargetB.Thing; if (scanned.def == TechDefOf.TechDrive) { Toils_Recipe_Patch.ConsumeIngredients(new List <Thing> { scanned }, curJob.RecipeDef, actor.Map); } curJob.bill.Notify_IterationCompleted(actor, new List <Thing>()); }; yield return(upload); //Put it back! if (inShelf) { yield return(Toils_Haul.StartCarryThing(TargetIndex.B, true, false, true)); yield return(Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.B, true)); yield return(Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.Touch).FailOnDestroyedOrNull(TargetIndex.B)); Toil handOver = Toils_Haul.DepositHauledThingInContainer(TargetIndex.B, TargetIndex.A); handOver.AddPreInitAction(delegate { bookOut = false; }); yield return(handOver); } yield return(new Toil() { initAction = delegate() { pawn.jobs.EndCurrentJob(JobCondition.Succeeded, true, true); } }); yield break; }
protected override IEnumerable <Toil> MakeNewToils() { //A - Sleeper B - Brain template C - Bed this.FailOnDestroyedNullOrForbidden(TargetIndex.A); this.FailOnDestroyedNullOrForbidden(TargetIndex.B); this.FailOnDestroyedNullOrForbidden(TargetIndex.C); yield return(Toils_Reserve.Reserve(TargetIndex.B)); if (Patient.CurJobDef != JobDefOf.LayDown || Patient.CurrentBed() != Bed) { QEEMod.TryLog("Patient not in bed, carrying them to bed"); //get the patient and carry them to the bed yield return(Toils_Reserve.Reserve(TargetIndex.A)); yield return(Toils_Reserve.Reserve(TargetIndex.C)); yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell)); yield return(Toils_Haul.StartCarryThing(TargetIndex.A)); yield return(Toils_Goto.GotoThing(TargetIndex.C, PathEndMode.InteractionCell)); yield return(Toils_Haul.PlaceHauledThingInCell(TargetIndex.C, null, false)); yield return(Toils_Reserve.Release(TargetIndex.C)); } //anesthetize the patient Toil anesthetizePatient = new Toil() { initAction = delegate() { Toils_Reserve.Reserve(TargetIndex.A); Patient.health.AddHediff(HediffDefOf.Anesthetic); if (Patient.CurJobDef != JobDefOf.LayDown) { Patient.pather.StopDead(); Patient.jobs.StartJob(new Job(JobDefOf.LayDown, TargetC) { forceSleep = true }); } }, }; yield return(anesthetizePatient); //Surgeon gets the brain template, carries it, then travel to bed QEEMod.TryLog("Carrying brain template to bed"); yield return(Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.OnCell)); yield return(Toils_Haul.StartCarryThing(TargetIndex.B)); yield return(Toils_Goto.GotoThing(TargetIndex.C, PathEndMode.ClosestTouch)); Toil applyBrainTemplateToil = new Toil() { defaultCompleteMode = ToilCompleteMode.Never, tickAction = delegate() { ticksWork -= StatDefOf.ResearchSpeed.Worker.IsDisabledFor(pawn) ? 1f : 1f * pawn.GetStatValue(StatDefOf.ResearchSpeed); if (ticksWork <= 0) { BrainManipUtility.ApplyBrainScanTemplateOnPawn(Patient, BrainTemplate); //Give headache Patient.health.AddHediff(QEHediffDefOf.QE_Headache, Patient.health.hediffSet.GetBrain()); } } }.WithProgressBar(TargetIndex.A, () => (workRequired - ticksWork) / workRequired).WithEffect(EffecterDefOf.Research, TargetIndex.A); applyBrainTemplateToil.AddPreInitAction(delegate() { ticksWork = workRequired; workStarted = true; //Log.Message("preInitAction: ticksWork = " + ticksWork); }); applyBrainTemplateToil.AddEndCondition(delegate() { if (workStarted && ticksWork <= 0) { //Log.Message("Succeeded: ticksWork = " + ticksWork); return(JobCondition.Succeeded); } //Log.Message("Ongoing: ticksWork = " + ticksWork); return(JobCondition.Ongoing); }); applyBrainTemplateToil.AddFailCondition(() => workStarted && Patient.CurJobDef != JobDefOf.LayDown); yield return(applyBrainTemplateToil); }
protected override IEnumerable <Toil> MakeNewToils() { this.FailOnDestroyedOrNull(TargetIndex.A); this.FailOnDestroyedOrNull(TargetIndex.B); this.FailOnAggroMentalStateAndHostile(TargetIndex.A); this.FailOn(delegate() { if (this.job.def.makeTargetPrisoner) { if (!this.DropBed.ForPrisoners) { return(true); } } else if (this.DropBed.ForPrisoners != this.Takee.IsPrisoner) { return(true); } return(false); }); yield return(Toils_Bed.ClaimBedIfNonMedical(TargetIndex.B, TargetIndex.A)); base.AddFinishAction(delegate { if (this.job.def.makeTargetPrisoner && this.Takee.ownership.OwnedBed == this.DropBed && this.Takee.Position != RestUtility.GetBedSleepingSlotPosFor(this.Takee, this.DropBed)) { this.Takee.ownership.UnclaimBed(); } }); yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch).FailOnDespawnedNullOrForbidden(TargetIndex.A).FailOnDespawnedNullOrForbidden(TargetIndex.B).FailOn(() => this.job.def == JobDefOf.Arrest && !this.Takee.CanBeArrestedBy(this.pawn)).FailOn(() => !this.pawn.CanReach(this.DropBed, PathEndMode.OnCell, Danger.Deadly, false, TraverseMode.ByPawn)).FailOn(() => this.job.def == JobDefOf.Rescue && !this.Takee.Downed).FailOnSomeonePhysicallyInteracting(TargetIndex.A)); yield return(new Toil { initAction = delegate() { if (this.job.def.makeTargetPrisoner) { Pawn pawn = (Pawn)this.job.targetA.Thing; Lord lord = pawn.GetLord(); if (lord != null) { lord.Notify_PawnAttemptArrested(pawn); } GenClamor.DoClamor(pawn, 10f, ClamorDefOf.Harm); if (this.job.def == JobDefOf.Arrest && !pawn.CheckAcceptArrest(this.pawn)) { this.pawn.jobs.EndCurrentJob(JobCondition.Incompletable, true); } } } }); Toil startCarrying = Toils_Haul.StartCarryThing(TargetIndex.A, false, false, false).FailOnNonMedicalBedNotOwned(TargetIndex.B, TargetIndex.A); startCarrying.AddPreInitAction(new Action(this.CheckMakeTakeeGuest)); yield return(startCarrying); yield return(Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.Touch)); yield return(new Toil { initAction = delegate() { this.CheckMakeTakeePrisoner(); if (this.Takee.playerSettings == null) { this.Takee.playerSettings = new Pawn_PlayerSettings(this.Takee); } } }); yield return(Toils_Reserve.Release(TargetIndex.B)); yield return(new Toil { initAction = delegate() { IntVec3 position = this.DropBed.Position; Thing thing; this.pawn.carryTracker.TryDropCarriedThing(position, ThingPlaceMode.Direct, out thing, null); if (!this.DropBed.Destroyed && (this.DropBed.owners.Contains(this.Takee) || (this.DropBed.Medical && this.DropBed.AnyUnoccupiedSleepingSlot) || this.Takee.ownership == null)) { this.Takee.jobs.Notify_TuckedIntoBed(this.DropBed); if (this.Takee.RaceProps.Humanlike && this.job.def != JobDefOf.Arrest && !this.Takee.IsPrisonerOfColony) { this.Takee.relations.Notify_RescuedBy(this.pawn); } this.Takee.mindState.Notify_TuckedIntoBed(); } if (this.Takee.IsPrisonerOfColony) { LessonAutoActivator.TeachOpportunity(ConceptDefOf.PrisonerTab, this.Takee, OpportunityType.GoodToKnow); } }, defaultCompleteMode = ToilCompleteMode.Instant }); yield break; }
protected override IEnumerable <Toil> MakeNewToils() { this.FailOnDestroyedOrNull(TargetIndex.A); this.FailOnDestroyedOrNull(TargetIndex.B); this.FailOnAggroMentalStateAndHostile(TargetIndex.A); this.FailOn(delegate { if (job.def.makeTargetPrisoner) { if (!DropBed.ForPrisoners) { return(true); } } else if (DropBed.ForPrisoners != Takee.IsPrisoner) { return(true); } return(false); }); yield return(Toils_Bed.ClaimBedIfNonMedical(TargetIndex.B, TargetIndex.A)); AddFinishAction(delegate { if (job.def.makeTargetPrisoner && Takee.ownership.OwnedBed == DropBed && Takee.Position != RestUtility.GetBedSleepingSlotPosFor(Takee, DropBed)) { Takee.ownership.UnclaimBed(); } }); yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch).FailOnDespawnedNullOrForbidden(TargetIndex.A).FailOnDespawnedNullOrForbidden(TargetIndex.B) .FailOn(() => job.def == JobDefOf.Arrest && !Takee.CanBeArrestedBy(pawn)) .FailOn(() => !pawn.CanReach(DropBed, PathEndMode.OnCell, Danger.Deadly)) .FailOn(() => (job.def == JobDefOf.Rescue || job.def == JobDefOf.Capture) && !Takee.Downed) .FailOnSomeonePhysicallyInteracting(TargetIndex.A)); Toil toil = new Toil(); toil.initAction = delegate { if (job.def.makeTargetPrisoner) { Pawn pawn = (Pawn)job.targetA.Thing; pawn.GetLord()?.Notify_PawnAttemptArrested(pawn); GenClamor.DoClamor(pawn, 10f, ClamorDefOf.Harm); if (job.def == JobDefOf.Arrest && !pawn.CheckAcceptArrest(base.pawn)) { base.pawn.jobs.EndCurrentJob(JobCondition.Incompletable); } if (!pawn.IsPrisoner) { QuestUtility.SendQuestTargetSignals(pawn.questTags, "Arrested", pawn.Named("SUBJECT")); } } }; yield return(toil); Toil toil2 = Toils_Haul.StartCarryThing(TargetIndex.A).FailOnNonMedicalBedNotOwned(TargetIndex.B, TargetIndex.A); toil2.AddPreInitAction(CheckMakeTakeeGuest); yield return(toil2); yield return(Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.Touch)); Toil toil3 = new Toil(); toil3.initAction = delegate { CheckMakeTakeePrisoner(); if (Takee.playerSettings == null) { Takee.playerSettings = new Pawn_PlayerSettings(Takee); } }; yield return(toil3); yield return(Toils_Reserve.Release(TargetIndex.B)); Toil toil4 = new Toil(); toil4.initAction = delegate { IntVec3 position = DropBed.Position; pawn.carryTracker.TryDropCarriedThing(position, ThingPlaceMode.Direct, out Thing _); if (!DropBed.Destroyed && (DropBed.OwnersForReading.Contains(Takee) || (DropBed.Medical && DropBed.AnyUnoccupiedSleepingSlot) || Takee.ownership == null)) { Takee.jobs.Notify_TuckedIntoBed(DropBed); if (Takee.RaceProps.Humanlike && job.def != JobDefOf.Arrest && !Takee.IsPrisonerOfColony) { Takee.relations.Notify_RescuedBy(pawn); } Takee.mindState.Notify_TuckedIntoBed(); } if (Takee.IsPrisonerOfColony) { LessonAutoActivator.TeachOpportunity(ConceptDefOf.PrisonerTab, Takee, OpportunityType.GoodToKnow); } }; toil4.defaultCompleteMode = ToilCompleteMode.Instant; yield return(toil4); }
protected override IEnumerable <Toil> MakeNewToils() { var checkIncaseJobWasCancelledPreviously = new Toil { initAction = () => { var curMap = this.GetActor().MapHeld; var lastCorpse = curMap.listerThings.AllThings.FirstOrDefault(x => x is Corpse c && c.InnerPawn.health.hediffSet.HasHediff(UvhashDefOf.Uvhash_TattooParalysis)); if (lastCorpse != null) { this.job.SetTarget(TargetIndex.A, lastCorpse); } } }; var prepareToTransformCorpse = new Toil(); prepareToTransformCorpse.initAction = delegate { Pawn actor = prepareToTransformCorpse.actor; Corpse corpse = this.Corpse; if (corpse == null) { Pawn prey = this.Prey; if (prey == null) { actor.jobs.EndCurrentJob(JobCondition.Incompletable, true); return; } corpse = prey.Corpse; if (corpse == null || !corpse.Spawned) { actor.jobs.EndCurrentJob(JobCondition.Incompletable, true); return; } } corpse.SetForbidden(actor.Faction != Faction.OfPlayer, false); actor.CurJob.SetTarget(TargetIndex.A, corpse); }; var goToCorpse = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch); var goToPreyPos = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch); var gotoCastPos = Toils_Combat.GotoCastPosition(TargetIndex.A, true).JumpIfDespawnedOrNull(TargetIndex.A, prepareToTransformCorpse).FailOn(() => Find.TickManager.TicksGame > this.jobStartTick + 5000); var moveIfCannotHit = Toils_Jump.JumpIfTargetNotHittable(TargetIndex.A, goToPreyPos); var castSpell = new Toil { defaultCompleteMode = ToilCompleteMode.Delay }; castSpell.WithProgressBarToilDelay(TargetIndex.A); castSpell.defaultDuration = 1200; castSpell.AddPreInitAction(() => { curReport = "BloodMage_CastingOn".Translate(TargetA.Thing.Label); moteThrown = UvhashUtility.ThrowMagicMote(1f, this.GetActor()); moteThrown.LifeSpanOffset += 99999f; moteTarget.LifeSpanOffset += 99999f; moteTarget = UvhashUtility.ThrowMagicMote(TargetA.Thing.def.race.baseBodySize, TargetA.Thing); }); castSpell.tickAction = () => { if (moteThrown != null) { moteThrown.exactPosition = this.GetActor().DrawPos; } if (moteTarget != null) { moteTarget.exactPosition = TargetA.Thing.DrawPos; } if (Find.TickManager.TicksGame % 15 == 0) { MoteMaker.ThrowText(this.GetActor().DrawPos + new Vector3(new FloatRange(-1, 1).RandomInRange, 0, new FloatRange(-1, 1).RandomInRange), this.GetActor().MapHeld, cultMadText.RandomElement(), Color.red); //MoteMaker.ThrowText(this.TargetA.Thing.DrawPos + new Vector3(new FloatRange(-1, 1).RandomInRange, 0, new FloatRange(-1, 1).RandomInRange), this.GetActor().MapHeld, cultMadText.RandomElement(), Color.red); } }; castSpell.PlaySustainerOrSound(UvhashDefOf.Uvhash_BloodMagicCastingSustainer); castSpell.AddFinishAction(() => { if (!Prey.Downed) { HealthUtility.AdjustSeverity(Prey, UvhashDefOf.Uvhash_TattooParalysis, 1.0f); } curReport = ""; if (moteThrown != null) { moteThrown.LifeSpanOffset -= 999999f; } if (moteTarget != null) { moteTarget.LifeSpanOffset -= 999999f; } }); var executeTarget = new Toil { defaultCompleteMode = ToilCompleteMode.Delay }; executeTarget.WithProgressBarToilDelay(TargetIndex.B); executeTarget.defaultDuration = 200; executeTarget.AddFinishAction(() => { ExecutionUtility.DoExecutionByCut(this.GetActor(), Prey); }); Toil transformCorpse = new Toil(); transformCorpse.defaultCompleteMode = ToilCompleteMode.Delay; transformCorpse.WithEffect(() => EffecterDef.Named("ButcherFlesh"), TargetIndex.A); transformCorpse.WithProgressBarToilDelay(TargetIndex.A); transformCorpse.defaultDuration = 800; transformCorpse.AddPreInitAction(() => { Messages.Message("BloodBookCreation_Message".Translate(new object[] { this.pawn.LabelCap, this.Prey.Label }), MessageTypeDefOf.NeutralEvent); }); var destroyCorpseAndSpawnBook = new Toil(); destroyCorpseAndSpawnBook.initAction = () => { var corpsePos = Corpse.PositionHeld; var corpseMap = Corpse.MapHeld; Corpse.Destroy(); FilthMaker.MakeFilth(corpsePos, corpseMap, ThingDefOf.FilthBlood, Rand.Range(1, 2)); for (int i = 0; i < 10; i++) { FilthMaker.MakeFilth(corpsePos.RandomAdjacentCell8Way(), corpseMap, ThingDefOf.FilthBlood, Rand.Range(1, 2)); this.GetActor().filth.GainFilth(ThingDefOf.FilthBlood); } var book = (ThingWithComps_LiberCruoris)ThingMaker.MakeThing(UvhashDefOf.Uvhash_LiberCruoris); GenPlace.TryPlaceThing(book, corpsePos, corpseMap, ThingPlaceMode.Near); Find.World.GetComponent <WorldComponent_Uvhash>().CurrentCrystalStage = CrystalStage.BookCreated; this.GetActor().MentalState.RecoverFromState(); this.GetActor().TryGetComp <CompBloodMage>().BloodMageLevel = 1; UvhashUtility.ShowMessageBox("BloodBookCreatedDesc".Translate(this.GetActor()).AdjustedFor(this.GetActor()), "BloodBookCreated".Translate()); }; yield return(new Toil { initAction = delegate { this.jobStartTick = Find.TickManager.TicksGame; } }); yield return(checkIncaseJobWasCancelledPreviously); yield return(Toils_Jump.JumpIf(goToCorpse, () => Prey.Dead)); yield return(Toils_Jump.JumpIf(goToPreyPos, () => Prey.Downed)); yield return(Toils_Combat.TrySetJobToUseAttackVerb()); yield return(gotoCastPos.FailOn(() => this.GetActor().IsFighting())); yield return(castSpell); yield return(goToPreyPos); yield return(executeTarget); yield return(prepareToTransformCorpse); yield return(goToCorpse); yield return(transformCorpse); yield return(destroyCorpseAndSpawnBook); this.AddFinishAction(() => { if (moteThrown != null) { moteThrown.LifeSpanOffset -= 999999f; } if (moteTarget != null) { moteTarget.LifeSpanOffset -= 999999f; } }); yield break; }