protected override IEnumerable <Toil> MakeNewToils() { List <Toil> toilsList = new List <Toil>(); Building_Pyre pyre = this.TargetThingA as Building_Pyre; bool beerIsAvailable = false; if (this.pawn.Position.InHorDistOf(pyre.Position, Building_Pyre.partyAreaRadius) == false) { // Go around pyre. toilsList.Add(base.ToilGetWanderCell(pyre.Position)); Find.PawnDestinationManager.ReserveDestinationFor(this.pawn, this.CurJob.targetB.Cell); toilsList.Add(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.OnCell)); // Release cell (the pawn will either go grab a beer or move on the next job). toilsList.Add(base.ToilReleaseCell()); } // Look for an available beer. List <Thing> list = Find.ListerThings.ThingsOfDef(ThingDefOf.Beer); if (list.Count > 0) { Predicate <Thing> validator = (Thing t) => pawn.CanReserve(t, 1) && !t.IsForbidden(pawn); Thing beer = GenClosest.ClosestThing_Global_Reachable(pyre.Position, list, PathEndMode.OnCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), Building_Pyre.beerSearchAreaRadius, validator, null); if (beer != null) { beerIsAvailable = true; this.CurJob.SetTarget(TargetIndex.A, beer); //this.CurJob.targetA = beer; this.CurJob.maxNumToCarry = 1; toilsList.Add(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch).FailOnDespawnedNullOrForbidden(TargetIndex.A)); toilsList.Add(Toils_Ingest.PickupIngestible(TargetIndex.A, this.pawn)); // TargetIndex.A becomes the carried beer. toilsList.Add(Toils_Ingest.CarryIngestibleToChewSpot(this.pawn)); toilsList.Add(Toils_Ingest.FindAdjacentEatSurface(TargetIndex.B, TargetIndex.A)); // float durationMultiplier = 1f / this.pawn.GetStatValue(StatDefOf.EatingSpeed, true); // Don't use it so the job duration is nearly the same for all pawns. float durationMultiplier = 1f; toilsList.Add(Toils_Ingest.ChewIngestible(this.pawn, durationMultiplier, TargetIndex.A, TargetIndex.B).FailOn((Toil x) => !this.Food.Spawned && (this.pawn.carrier == null || this.pawn.carrier.CarriedThing != this.Food))); toilsList.Add(Toils_Ingest.FinalizeIngest(this.pawn, TargetIndex.A)); } } // Draw a mote. ThingDef moteDef = null; if (beerIsAvailable) { moteDef = Util_CampfireParty.Mote_BeerAvailable; } else { moteDef = Util_CampfireParty.Mote_BeerUnavailable; } MoteAttached moteAttached = (MoteAttached)ThingMaker.MakeThing(moteDef); moteAttached.AttachTo(this.pawn); GenSpawn.Spawn(moteAttached, this.pawn.Position); return(toilsList); }
protected override IEnumerable <Toil> MakeNewToils() { List <Toil> toilsList = new List <Toil>(); Building_Pyre pyre = this.TargetThingA as Building_Pyre; IntVec3 memorizedFacingCell = Find.Map.Center; // Go around pyre. toilsList.Add(base.ToilGetWanderCell(pyre.Position)); Find.PawnDestinationManager.ReserveDestinationFor(this.pawn, this.CurJob.targetB.Cell); toilsList.Add(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.OnCell)); // Add toils to drops all worn apparels. if (this.pawn.apparel != null && this.pawn.apparel.WornApparelCount > 0) { for (int apparelIndex = 0; apparelIndex < this.pawn.apparel.WornApparelCount; apparelIndex++) { Toil dropApparel = new Toil() { initAction = () => { if (this.pawn.apparel != null && this.pawn.apparel.WornApparelCount > 0) { Apparel apparel; this.pawn.apparel.TryDrop(this.pawn.apparel.WornApparel.RandomElement <Apparel>(), out apparel); } }, defaultCompleteMode = ToilCompleteMode.Instant }; toilsList.Add(dropApparel); Toil waitFacingRandomCell = new Toil() { initAction = () => { memorizedFacingCell = this.pawn.Position + new IntVec3(0, 0, 1).RotatedBy(new Rot4(Rand.Range(0, 4))); }, tickAction = () => { this.pawn.Drawer.rotator.FaceCell(memorizedFacingCell); }, defaultDuration = 150, defaultCompleteMode = ToilCompleteMode.Delay }; toilsList.Add(waitFacingRandomCell); } } // Release cell. toilsList.Add(base.ToilReleaseCell()); return(toilsList); }
protected override IEnumerable <Toil> MakeNewToils() { List <Toil> toilsList = new List <Toil>(); Building_Pyre pyre = this.TargetThingA as Building_Pyre; // Get a valid cell to wander on. toilsList.Add(base.ToilGetWanderCell(pyre.Position)); Find.PawnDestinationManager.ReserveDestinationFor(this.pawn, this.CurJob.targetB.Cell); toilsList.Add(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.OnCell)); // Talk with nearby pawn. toilsList.Add(GetToilTalkWithNearbyPawn()); // Release cell. toilsList.Add(base.ToilReleaseCell()); return(toilsList); }
protected Toil ToilGetWanderCell(Building_Pyre pyre) { Toil toil = new Toil() { initAction = () => { IntVec3 cell; bool validCellIsFound = CellFinder.TryFindRandomReachableCellNear(pyre.Position, pyre.Map, Building_Pyre.partyAreaRadius, TraverseParms.For(TraverseMode.NoPassClosedDoors, Danger.None), new Predicate <IntVec3>(this.IsValidCellToWander), null, out cell); if (validCellIsFound) { this.CurJob.targetB = cell; } else { this.CurJob.targetB = this.pawn.Position; } }, defaultCompleteMode = ToilCompleteMode.Instant }; return(toil); }
protected override IEnumerable <Toil> MakeNewToils() { const int partyParts = 4; const int jobsPerPart = 3; const int maxTries = 3; List <PartyJobType> partyJobsType = new List <PartyJobType>(); List <Toil> partyToils = new List <Toil>(); Building_Pyre pyre = this.TargetThingA as Building_Pyre; bool revelerIsPsychopath = this.pawn.story.traits.HasTrait(TraitDef.Named("Psychopath")); bool revelerIsNudist = this.pawn.story.traits.HasTrait(TraitDefOf.Nudist); bool revelerHasTriggerHappyTrait = this.pawn.story.traits.DegreeOfTrait(TraitDef.Named("ShootingAccuracy")) == -1; int revelerAlcoholAddictionLevel = this.pawn.story.traits.DegreeOfTrait(TraitDefOf.DrugDesire); // Psychopaths don't like having parties with others... 3:p if (revelerIsPsychopath) { partyToils.Add(Toils_Goto.GotoCell(pyreIndex, PathEndMode.ClosestTouch)); Toil toil = new Toil() { tickAction = () => { this.pawn.Drawer.rotator.FaceCell(pyre.Position); }, defaultDuration = 300, defaultCompleteMode = ToilCompleteMode.Delay }; partyToils.Add(toil); pawn.needs.mood.thoughts.memories.TryGainMemoryThought(Util_CampfireParty.Thought_HadCampfirePartyPsychopaths); return(partyToils); } // Initialize party jobs type. for (int jobTypeIndex = 0; jobTypeIndex < partyParts * jobsPerPart; jobTypeIndex++) { partyJobsType.Add(PartyJobType.Undefined); } // If the colonist is a nudist, add a drop clothes job in 1st, 2nd or 3rd part. if (revelerIsNudist) { for (int tries = 0; tries < maxTries; tries++) { int jobIndex = Rand.Range(jobsPerPart, 3 * jobsPerPart) + tries; if (jobIndex >= partyParts * jobsPerPart) { jobIndex -= jobsPerPart; } if (partyJobsType[jobIndex] == PartyJobType.Undefined) { partyJobsType[jobIndex] = PartyJobType.DropClothes; break; } } } // If the colonist has the trigger-happy trait, add a shoot in the air job in 3nd or 4th part. if (revelerHasTriggerHappyTrait) { for (int tries = 0; tries < maxTries; tries++) { int jobIndex = Rand.Range(2 * jobsPerPart, 4 * jobsPerPart) + tries; if (jobIndex >= partyParts * jobsPerPart) { jobIndex -= jobsPerPart; } if (partyJobsType[jobIndex] == PartyJobType.Undefined) { partyJobsType[jobIndex] = PartyJobType.ShootUpInTheAir; break; } } } // Add a drink beer job for each level of addiction. if (revelerAlcoholAddictionLevel >= 0) { for (int beerIndex = 0; beerIndex < 2 * (revelerAlcoholAddictionLevel + 1); beerIndex++) { for (int tries = 0; tries < maxTries; tries++) { int jobIndex = Rand.Range(0, partyParts * jobsPerPart) + tries; if (jobIndex >= partyParts * jobsPerPart) { jobIndex -= jobsPerPart; } if (partyJobsType[jobIndex] == PartyJobType.Undefined) { partyJobsType[jobIndex] = PartyJobType.DrinkBeer; break; } } } } // Convert all remaining undefined jobs into wander/play the guitar/dance jobs. for (int jobIndex = 0; jobIndex < partyParts * jobsPerPart; jobIndex++) { if (partyJobsType[jobIndex] == PartyJobType.Undefined) { float jobSelector = Rand.Value; if (jobSelector < 0.2f) { partyJobsType[jobIndex] = PartyJobType.PlayTheGuitar; } else if (jobSelector < 0.5f) { partyJobsType[jobIndex] = PartyJobType.Dance; } else { partyJobsType[jobIndex] = PartyJobType.WanderAroundPyre; } } } // Debug: display generated jobs sequence. /*for (int jobIndex = 0; jobIndex < partyParts * jobsPerPart; jobIndex++) * { * Log.Message("partyJobsType[" + jobIndex + "] = " + partyJobsType[jobIndex]); * }*/ // Generate actual toils. if (this.pawn.jobs.jobQueue == null) { // This case will only happen for a pawn who has never queued jobs before. this.pawn.jobs.jobQueue = new JobQueue(); } for (int jobIndex = 0; jobIndex < partyParts * jobsPerPart; jobIndex++) { switch (partyJobsType[jobIndex]) { case PartyJobType.WanderAroundPyre: this.pawn.jobs.jobQueue.EnqueueLast(new Job(Util_CampfireParty.Job_WanderAroundPyre, pyre)); break; case PartyJobType.PlayTheGuitar: this.pawn.jobs.jobQueue.EnqueueLast(new Job(Util_CampfireParty.Job_PlayTheGuitar, pyre)); break; case PartyJobType.Dance: this.pawn.jobs.jobQueue.EnqueueLast(new Job(Util_CampfireParty.Job_Dance, pyre)); break; case PartyJobType.DrinkBeer: this.pawn.jobs.jobQueue.EnqueueLast(new Job(Util_CampfireParty.Job_IngestBeer, pyre)); break; case PartyJobType.DropClothes: this.pawn.jobs.jobQueue.EnqueueLast(new Job(Util_CampfireParty.Job_DropClothes, pyre)); break; case PartyJobType.ShootUpInTheAir: this.pawn.jobs.jobQueue.EnqueueLast(new Job(Util_CampfireParty.Job_ShootUpinTheAir, pyre)); break; } if ((jobIndex % jobsPerPart) == (jobsPerPart - 1)) { this.pawn.jobs.jobQueue.EnqueueLast(new Job(Util_CampfireParty.Job_UpdateThought)); } } return(partyToils); }
protected override IEnumerable <Toil> MakeNewToils() { List <Toil> toilsList = new List <Toil>(); Building_Pyre pyre = this.TargetThingA as Building_Pyre; if (this.pawn.equipment == null) { // Release cell. toilsList.Add(base.ToilReleaseCell()); return(toilsList); } toilsList.Add(base.ToilGetWanderCell(pyre.Position)); Find.VisibleMap.pawnDestinationManager.ReserveDestinationFor(this.pawn, this.CurJob.targetB.Cell); toilsList.Add(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.OnCell)); // Add toils to shoot up in the air. int numberOfShots = Rand.Range(5, 9); bool isSlowFiringGun = false; if (this.pawn.equipment.Primary != null) { ThingDef weaponDef = this.pawn.equipment.Primary.def; if ((weaponDef == ThingDef.Named("Gun_PumpShotgun")) || (weaponDef == ThingDefOf.Gun_SurvivalRifle)) { isSlowFiringGun = true; } } for (int shotIndex = 0; shotIndex < numberOfShots; shotIndex++) { int durationInTicks = Rand.Range(5, 50); if (isSlowFiringGun) { durationInTicks = Rand.Range(30, 70); } ; Toil shootUpInTheAir = new Toil() { initAction = () => { // Check gun has not been dropped since job start. if (this.pawn.equipment.Primary != null) { ThingDef weaponDef = this.pawn.equipment.Primary.def; if ((weaponDef == ThingDefOf.Gun_Pistol) || (weaponDef == ThingDef.Named("Gun_PumpShotgun")) || (weaponDef == ThingDef.Named("Gun_AssaultRifle")) || (weaponDef == ThingDef.Named("Gun_PDW")) || (weaponDef == ThingDef.Named("Gun_HeavySMG")) || (weaponDef == ThingDef.Named("Gun_LMG")) || (weaponDef == ThingDef.Named("Gun_ChargeRifle")) || (weaponDef == ThingDef.Named("Gun_Minigun")) || (weaponDef == ThingDefOf.Gun_SurvivalRifle)) { this.pawn.equipment.Primary.def.Verbs.First().soundCast.PlayOneShot(this.pawn.Position); } } else { durationInTicks = 1; } }, defaultDuration = durationInTicks, defaultCompleteMode = ToilCompleteMode.Delay }; toilsList.Add(shootUpInTheAir); } // Release cell. toilsList.Add(base.ToilReleaseCell()); return(toilsList); }