diff --git a/SpecialOrdersExtended/DialogueManager.cs b/SpecialOrdersExtended/DialogueManager.cs
index 2e99556..f77cad2 100644
--- a/SpecialOrdersExtended/DialogueManager.cs
+++ b/SpecialOrdersExtended/DialogueManager.cs
@@ -3,11 +3,54 @@
namespace SpecialOrdersExtended;
+///
+/// A dialogue to delay.
+///
+internal struct DelayedDialogue
+{
+ private readonly int time;
+ private readonly Dialogue dialogue;
+ private readonly NPC npc;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// Time to delay to.
+ /// Dialogue to delay.
+ /// Speaking NPC.
+ public DelayedDialogue(int time, Dialogue dialogue, NPC npc)
+ {
+ this.time = time;
+ this.dialogue = dialogue;
+ this.npc = npc;
+ }
+
+ ///
+ /// Pushes the delayed dialogue onto the NPC's stack if it's past time to do so..
+ ///
+ /// The current in-game time.
+ /// True if pushed, false otherwise.
+ public bool PushIfPastTime(int currenttime)
+ {
+ if (currenttime > this.time)
+ {
+ this.npc.CurrentDialogue.Push(this.dialogue);
+ return true;
+ }
+ return false;
+ }
+}
+
///
/// Static. Handles logic, patches, and console commands related to the special order dialogues.
///
internal class DialogueManager
{
+ ///
+ /// A queue of delayed dialogues.
+ ///
+ private static readonly PerScreen> DelayedDialogues = new(createNewState: () => new Queue());
+
///
/// Backing field for PerScreened Dialogue Logs.
///
@@ -302,6 +345,29 @@ public static void PostfixCheckDialogue(ref bool __result, ref NPC __instance, i
}
}
+ ///
+ /// Clears the Delayed Dialogue queue. Call at end of day.
+ ///
+ public static void ClearDelayedDialogue() => DelayedDialogues.Value.Clear();
+
+ ///
+ /// Push any available dialogues to the NPC's dialogue stacks.
+ ///
+ public static void PushPossibleDelayedDialogues()
+ {
+ while (DelayedDialogues.Value.TryPeek(out DelayedDialogue result))
+ {
+ if (result.PushIfPastTime(Game1.timeOfDay))
+ {
+ _ = DelayedDialogues.Value.Dequeue();
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
///
/// Checks to see if a dialoguekey has been said already, and if not said, pushes the dialogue
/// onto the dialogue stack.
@@ -315,6 +381,13 @@ private static bool PushAndSaveDialogue(string dialogueKey, NPC npc)
{// I have already said this dialogue
return false;
}
+ while (npc.CurrentDialogue.TryPop(out Dialogue? result))
+ {
+ DelayedDialogues.Value.Enqueue(new DelayedDialogue(
+ time: Game1.timeOfDay + 100,
+ npc: npc,
+ dialogue: result));
+ }
npc.CurrentDialogue.Push(new Dialogue(npc.Dialogue[dialogueKey], npc) { removeOnNextMove = true });
if (ModEntry.Config.Verbose)
{
diff --git a/SpecialOrdersExtended/ModEntry.cs b/SpecialOrdersExtended/ModEntry.cs
index 6795d79..65e5109 100644
--- a/SpecialOrdersExtended/ModEntry.cs
+++ b/SpecialOrdersExtended/ModEntry.cs
@@ -1,6 +1,7 @@
using System.Reflection;
using HarmonyLib;
using SpecialOrdersExtended.Integrations;
+using StardewModdingAPI.Events;
using StardewValley.GameData;
namespace SpecialOrdersExtended;
@@ -110,15 +111,21 @@ public override void Entry(IModHelper helper)
helper.Events.GameLoop.GameLaunched += this.OnGameLaunched;
helper.Events.GameLoop.SaveLoaded += this.SaveLoaded;
helper.Events.GameLoop.Saving += this.Saving;
+ helper.Events.GameLoop.TimeChanged += this.OnTimeChanged;
helper.Events.GameLoop.OneSecondUpdateTicking += this.OneSecondUpdateTicking;
}
- private void OneSecondUpdateTicking(object? sender, StardewModdingAPI.Events.OneSecondUpdateTickingEventArgs e)
+ private void OnTimeChanged(object? sender, TimeChangedEventArgs e)
+ {
+ DialogueManager.PushPossibleDelayedDialogues();
+ }
+
+ private void OneSecondUpdateTicking(object? sender, OneSecondUpdateTickingEventArgs e)
{
RecentSOManager.GrabNewRecentlyCompletedOrders();
}
- private void OnGameLaunched(object? sender, StardewModdingAPI.Events.GameLaunchedEventArgs e)
+ private void OnGameLaunched(object? sender, GameLaunchedEventArgs e)
{
// Bind Spacecore API
IModInfo spacecore = this.Helper.ModRegistry.Get("spacechase0.SpaceCore");
@@ -141,11 +148,12 @@ private void OnGameLaunched(object? sender, StardewModdingAPI.Events.GameLaunche
api.RegisterToken(this.ModManifest, "RecentCompleted", new Tokens.RecentCompletedSO());
}
- private void Saving(object? sender, StardewModdingAPI.Events.SavingEventArgs e)
+ private void Saving(object? sender, SavingEventArgs e)
{
this.Monitor.DebugLog("Event Saving raised");
DialogueManager.Save(); // Save dialogue
+ DialogueManager.ClearDelayedDialogue();
if (Context.IsSplitScreen && Context.ScreenId != 0)
{// Some properties only make sense for a single player to handle in splitscreen.
@@ -159,7 +167,7 @@ private void Saving(object? sender, StardewModdingAPI.Events.SavingEventArgs e)
RecentSOManager.Save();
}
- private void SaveLoaded(object? sender, StardewModdingAPI.Events.SaveLoadedEventArgs e)
+ private void SaveLoaded(object? sender, SaveLoadedEventArgs e)
{
this.Monitor.DebugLog("Event SaveLoaded raised");
DialogueManager.Load(Game1.player.UniqueMultiplayerID);