public override void MapComponentTick() { // No Rare version of MapComponentTick, so this will do. if (!AncestorUtils.IsIntervalTick()) { return; } if (!this.initialized) { this.Initialize(); } for (int i = this.despawnBuffer.Count - 1; i >= 0; i--) { this.DespawnVisitor(this.despawnBuffer[i]); } if (!this.visitSchedule.IsScheduledForCurrentSeason) { this.visitSchedule = AncestorVisitScheduler.BuildSeasonScheduleForCurrentSeason(); } this.visitSchedule.VisitScheduleTickInterval(); this.approval.ApprovalTrackerTickInterval(this); this.timer.AncestorMemoTimerTickInterval(this.approval); }
public override void Init() { // Set duration to 1 less than "Permenant" because this will end when visitors despawned this.originalDuration = this.duration; this.duration = 999999999; var introDef = DefDatabase <ConceptDef> .GetNamed("MTW_AncestorVisit"); LessonAutoActivator.TeachOpportunity(introDef, OpportunityType.Important); var spawnController = AncestorUtils.GetMapComponent(); for (int i = 0; i < AncestorConstants.ANCESTORS_PER_VISIT; i++) { var spawned = spawnController.TrySpawnRandomVisitor(); if (spawned != null) { this.visitors.Add(spawned); this.visitInfoMap.Add(spawned.thingIDNumber, new PawnVisitInfo(spawned, this.EstDurationDays)); } } var loiterPoint = spawnController.CurrentSpawner.Position; var lordJob = new LordJob_HauntColony(loiterPoint, this.duration); var lord = LordMaker.MakeNewLord(spawnController.AncestorFaction, lordJob, this.visitors); }
public override void MapConditionTick() { if (!AncestorUtils.IsIntervalTick()) { return; } // Remove despawned visitors this.visitors = visitors.Where(p => p.Spawned).ToList(); if (this.visitors.Count == 0) { this.duration = 0; this.SubmitApprovalChanges(); } else { foreach (Pawn p in this.visitors) { this.PawnApprovalTickInterval(p); } if (this.EstRemainingDays < -1f) { this.QueueForcedEnd(); } } }
protected override ThoughtState CurrentStateInternal(Pawn p) { // TODO: There's gotta be a better way of doin' this! if (!AncestorUtils.IsAncestor(p)) { return(ThoughtState.Inactive); } var shrine = AncestorUtils.GetMapComponent().CurrentSpawner; if (shrine == null) { return(ThoughtState.ActiveAtStage(1)); } // HACK ALERT! Change Shrines to have an Interaction cell, and use that instead of a random one! var room = RoomQuery.RoomAtFast(shrine.RandomAdjacentCellCardinal()); if (room == null) { return(ThoughtState.ActiveAtStage(1)); } else if (room.Role != shrineRoomDef) { return(ThoughtState.ActiveAtStage(1)); } else { return(ThoughtState.Inactive); } }
private void DespawnAllPawnsAndTerminate() { var ancestorTicker = AncestorUtils.GetMapComponent(); var pawns = this.lord.ownedPawns.ToList(); for (int i = pawns.Count - 1; i >= 0; i--) { ancestorTicker.Notify_ShouldDespawn(pawns[i], AncestorLeftCondition.AnchorDestroyed); } }
public override string GetInspectString() { int magic = AncestorUtils.GetMapComponent().CurrentMagic; StringBuilder builder = new StringBuilder(); builder.AppendLine("Magic available: " + magic); builder.AppendLine("Magic for next ritual: " + this.MagicForNextRitual); builder.Append(base.GetInspectString()); return(builder.ToString()); }
public void QueueForcedEnd() { if (!this.forcedEnd) { var spawnController = AncestorUtils.GetMapComponent(); foreach (var visitor in this.visitors.Where(p => p.Spawned)) { spawnController.Notify_ShouldDespawn(visitor, AncestorLeftCondition.LeftVoluntarily); } this.forcedEnd = true; } }
public override void CompTick() { base.CompTick(); if (this.parent is Pawn) { if (!this.hasSet) { AncestorUtils.SetAncestorGraphics((Pawn)this.parent); this.hasSet = true; } } else { Log.ErrorOnce("Cannot add SpiritGraphics to non-Pawn Thing " + this.parent.Label, 65447891); } }
public override float GetScore(Room room) { // I don't know if there should be some "If it's full of joy objects/work benches, *don't* classify it as // a Shrine - if you Shrine room wall gets broken down by a bug, this will probably push all the attached // rooms into the "Shrine Room" - is that a desired behaviour? var shrine = AncestorUtils.GetMapComponent().CurrentSpawner; if (shrine != null && room.AllContainedThings.Contains <Thing>(shrine)) { return(9999.0f); } else { return(0.0f); } }
public void TryFireVisit() { if (AncestorUtils.GetMapComponent().CurrentSpawner != null) { this.FireVisit(); } else if (Find.TickManager.TicksGame < AncestorVisitScheduler.BufferGameStartTicks) { this.FireVisitNoAnchorButNewColony(); } else { this.FireVisitImpossibleWithoutAnchor(); } this.HasFired = true; }
public override bool TryExecute(IncidentParms parms) { // Force a transition WeatherDef weatherDef = DefDatabase <WeatherDef> .GetNamed("MTW_HeavyWind"); Find.WeatherManager.TransitionTo(weatherDef); // Set the duration using reflection int weatherDuration = AncestorUtils.DaysToTicks(this.def.durationDays.RandomInRange); var decider = Find.Storyteller.weatherDecider; typeof(WeatherDecider) .GetField("curWeatherDuration", BindingFlags.Instance | BindingFlags.NonPublic) .SetValue(decider, weatherDuration); return(true); }
public override void ExposeData() { base.ExposeData(); Scribe_Values.LookValue <bool>(ref initialized, "initialized", false); Scribe_Values.LookValue <int>(ref numAncestorsToVisit, "numAncestorsToVisit", 3); Scribe_Deep.LookDeep <ApprovalTracker>(ref this.approval, "approval", new object[0]); Scribe_Deep.LookDeep <AncestorMemoTimer>(ref this.timer, "timer", new object[0]); Scribe_Collections.LookList <Pawn>(ref this.unspawnedAncestors, "unspawnedAncestors", LookMode.Deep, new object[0]); Scribe_Collections.LookList <Building>(ref this.spawners, "spawners", LookMode.MapReference); // Probably there's a better way to do this! if (this.visitSchedule == null) { var seasonStart = AncestorUtils.EstStartOfSeasonAt(Find.TickManager.TicksGame); this.visitSchedule = AncestorVisitScheduler.BuildSeasonSchedule(seasonStart); } Scribe_Deep.LookDeep <VisitScheduleForSeason>(ref this.visitSchedule, "visitSchedule", new object[0]); }
protected override IEnumerable <Toil> MakeNewToils() { //Set fail conditions this.FailOnDestroyedNullOrForbidden(ShrineIndex); yield return(Toils_Reserve.Reserve(ShrineIndex)); yield return(Toils_Goto.GotoThing(ShrineIndex, PathEndMode.ClosestTouch)); Toil toilPetition = new Toil(); toilPetition.initAction = () => { this.ticksElapsed = 0; }; toilPetition.AddPreTickAction(() => { if (this.ticksElapsed > this.PetitionJob.PetitionTicks) { ReadyForNextToil(); } }); toilPetition.tickAction = () => { this.ticksElapsed++; }; toilPetition.AddFinishAction(() => { AncestorUtils.GetMapComponent().Notify_PetitionMade(this.PetitionDef, this.pawn); }); toilPetition.defaultCompleteMode = ToilCompleteMode.Never; yield return(toilPetition); }
protected override IEnumerable <Toil> MakeNewToils() { //Set fail conditions this.FailOnDestroyedNullOrForbidden(ShrineIndex); yield return(Toils_Goto.GotoThing(ShrineIndex, PathEndMode.ClosestTouch)); Toil toilReturn = new Toil(); toilReturn.initAction = () => { this.ticksElapsed = 0; }; // We don't do it in the "ending" action because it'll cause a NPE - when you despawn the pawn it finishes // all the toils it has, and by then the pawn already has been despawned, so this.pawn is null. // // There's probably a more elegant way of fixing this. toilReturn.AddPreTickAction(() => { if (this.ticksElapsed > returnDurationTicks) { var ticker = AncestorUtils.GetMapComponent(); ticker.Notify_ShouldDespawn(this.pawn, AncestorLeftCondition.LeftVoluntarily); ReadyForNextToil(); } }); toilReturn.tickAction = () => { this.ticksElapsed++; }; toilReturn.defaultCompleteMode = ToilCompleteMode.Never; yield return(toilReturn); }
protected override Job TryGiveJob(Pawn pawn) { if (pawn.CurJob != null) { return(pawn.CurJob); } var spawner = AncestorUtils.GetMapComponent().CurrentSpawner; if (spawner == null) { return(null); } IntVec3 anchorCell; GenAdj.TryFindRandomWalkableAdjacentCell8Way(spawner, out anchorCell); if (anchorCell == null) { return(null); } var path = PathFinder.FindPath(pawn.Position, anchorCell, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.PassAnything)); IntVec3 cellBeforeBlocker; Thing blocker = path.FirstBlockingBuilding(out cellBeforeBlocker, pawn); if (blocker != null) { var ticker = AncestorUtils.GetMapComponent(); ticker.Notify_ShouldDespawn(pawn, AncestorLeftCondition.AnchorBlocked); } path.Dispose(); Find.PawnDestinationManager.ReserveDestinationFor(pawn, anchorCell); return(new Job(DefDatabase <JobDef> .GetNamed("MTW_ReturnAnchor"), spawner)); }
public override void PostMake() { base.PostMake(); AncestorUtils.GetMapComponent().Notify_SpawnerCreated(this); }
private void SubmitApprovalChanges() { var summary = new AncestralVisitSummary(this.visitors, this.visitInfoMap); AncestorUtils.GetMapComponent().Notify_VisitEnded(summary); }
public override void DeSpawn() { base.DeSpawn(); AncestorUtils.GetMapComponent().Notify_SpawnerDestroyed(this); }
public override StateGraph CreateGraph() { StateGraph graph = new StateGraph(); var hauntPointToil = new LordToil_Relax(); graph.StartingToil = hauntPointToil; // Return to Anchor LordToil returnAnchorToil = new LordToil_ReturnAnchor(); graph.lordToils.Add(returnAnchorToil); Transition t1 = new Transition(hauntPointToil, returnAnchorToil); t1.triggers.Add(new Trigger_TicksPassed(this.duration)); t1.preActions.Add(new TransitionAction_Message("Your Ancestors are leaving!")); graph.transitions.Add(t1); // Link ALL nodes to Exit if Anchor Destroyed LordToil endToil = new LordToil_End(); graph.lordToils.Add(endToil); var ancestorTicker = AncestorUtils.GetMapComponent(); foreach (var toil in graph.lordToils.Where(t => t != endToil)) { Transition endTransition = new Transition(toil, endToil); endTransition.triggers.Add(new Trigger_TickCondition(() => ancestorTicker.CurrentSpawner == null)); endTransition.preActions.Add(new TransitionAction_Message( "The Anchor has been destroyed! Your Ancestors will be torn from the mortal plane! They won't forget this!")); endTransition.preActions.Add(new TransitionAction_Custom(this.DespawnAllPawnsAndTerminate)); graph.transitions.Add(endTransition); } return(graph); /* wowee thar's a doozy * StateGraph graphArrive = new StateGraph(); * var travelGraph = new LordJob_Travel(chillSpot).CreateGraph(); * travelGraph.StartingToil = new LordToil_CustomTravel(chillSpot, 0.49f); // CHANGED: override StartingToil * LordToil toilArrive = graphArrive.AttachSubgraph(travelGraph).StartingToil; * var toilVisit = new LordToil_VisitPoint(chillSpot); // CHANGED * graphArrive.lordToils.Add(toilVisit); * LordToil toilTakeWounded = new LordToil_TakeWoundedGuest(); * graphArrive.lordToils.Add(toilTakeWounded); * StateGraph graphExit = new LordJob_TravelAndExit(IntVec3.Invalid).CreateGraph(); * LordToil toilExit = graphArrive.AttachSubgraph(graphExit).StartingToil; * LordToil toilLeaveMap = graphExit.lordToils[1]; * LordToil toilLost = new LordToil_End(); * graphExit.AddToil(toilLost); * Transition t1 = new Transition(toilArrive, toilVisit); * t1.triggers.Add(new Trigger_Memo("TravelArrived")); * graphArrive.transitions.Add(t1); * LordToil_ExitMapBest toilExitCold = new LordToil_ExitMapBest(); // ADDED TOIL * graphArrive.AddToil(toilExitCold); * Transition t6 = new Transition(toilArrive, toilExitCold); // ADDED TRANSITION * t6.triggers.Add(new Trigger_UrgentlyCold()); * t6.preActions.Add(new TransitionAction_Message("MessageVisitorsLeavingCold".Translate(new object[] { faction.Name }))); * t6.preActions.Add(new TransitionAction_Custom(() => StopPawns(lord.ownedPawns))); * graphArrive.transitions.Add(t6); * Transition t2 = new Transition(toilVisit, toilTakeWounded); * t2.triggers.Add(new Trigger_WoundedGuestPresent()); * t2.preActions.Add(new TransitionAction_Message("MessageVisitorsTakingWounded".Translate(new object[] { faction.def.pawnsPlural.CapitalizeFirst(), faction.Name }))); * graphArrive.transitions.Add(t2); * Transition t3 = new Transition(toilVisit, toilLeaveMap); * t3.triggers.Add(new Trigger_BecameColonyEnemy()); * t3.preActions.Add(new TransitionAction_WakeAll()); * t3.preActions.Add(new TransitionAction_SetDefendLocalGroup()); * graphArrive.transitions.Add(t3); * Transition t4 = new Transition(toilArrive, toilExit); * t4.triggers.Add(new Trigger_BecameColonyEnemy()); * //t4.triggers.Add(new Trigger_VisitorsPleasedMax(MaxPleaseAmount(faction.ColonyGoodwill))); // CHANGED * t4.triggers.Add(new Trigger_VisitorsAngeredMax(IncidentWorker_VisitorGroup.MaxAngerAmount(faction.PlayerGoodwill))); // CHANGED * t4.preActions.Add(new TransitionAction_WakeAll()); * t4.preActions.Add(new TransitionAction_EnsureHaveExitDestination()); * graphArrive.transitions.Add(t4); * Transition t5 = new Transition(toilVisit, toilExit); * t5.triggers.Add(new Trigger_TicksPassed(Rand.Range(16000, 44000))); * t5.preActions.Add(new TransitionAction_Message("VisitorsLeaving".Translate(new object[] { faction.Name }))); * t5.preActions.Add(new TransitionAction_WakeAll()); * t5.preActions.Add(new TransitionAction_EnsureHaveExitDestination()); * graphArrive.transitions.Add(t5); * return graphArrive; */ }
public static VisitScheduleForSeason BuildSeasonScheduleForCurrentSeason() { long seasonStartTicks = AncestorUtils.EstStartOfSeasonAt(Find.TickManager.TicksAbs); return(BuildSeasonSchedule(seasonStartTicks)); }
private void FireVisitImpossibleWithoutAnchor() { Messages.Message("Your Ancestors wanted to visit, but you have no Shrine! They are very displeased.", MessageSound.Negative); AncestorUtils.GetMapComponent().Notify_VisitImpossibleWithoutAnchor(); }