init mod
This commit is contained in:
commit
5de3fd7ad8
121 files changed
+6632
No files matched your search
@@ -0,0 +1,120 @@
|
||||
using System.Collections.Generic;
|
||||
using Cthangover.Mods.Effects.Animation;
|
||||
using Cthangover.Mods.Dialog.Action;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Mods.Interface.View;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Frame-animates the scene foreground by swapping ViewBox textures at a
|
||||
/// configurable speed. Loads frames from SpriteIDs on construction
|
||||
/// (OnStartQueue). Unlike AnimationController which crossfades, this does
|
||||
/// hard cuts — simpler but acceptable for foreground effects. The speed
|
||||
/// switches to NextFrameSpeed after the first frame so first-frame delay
|
||||
/// can differ from subsequent frames. Registers as IOnUpdateEvent for
|
||||
/// per-frame advancement. Non-looping mode auto-stops at last frame.
|
||||
/// </summary>
|
||||
public class ActionAnimatedForeground : ActionCommand, IOnUpdateEvent
|
||||
{
|
||||
/// <summary>Update priority. Runs after higher-priority listeners. Value 0.</summary>
|
||||
public int Priority => 0;
|
||||
|
||||
/// <summary>List of sprite resource paths to display as animation frames. Loaded in <see cref="DoConstruct"/>.</summary>
|
||||
public List<string> SpriteIDs { get; set; }
|
||||
/// <summary>Initial frame rate multiplier for the first frame.</summary>
|
||||
public float Speed { get; set; } = 1f;
|
||||
/// <summary>Frame rate multiplier for subsequent frames after the first. Allows different pacing for the initial frame.</summary>
|
||||
public float NextFrameSpeed { get; set; } = 1f;
|
||||
/// <summary>Whether the animation wraps after the last frame. When false, playback stops at the final frame.</summary>
|
||||
public bool IsLoop { get; set; } = true;
|
||||
|
||||
private int currentFrame;
|
||||
private float elapsed;
|
||||
private bool isAnimating;
|
||||
private List<Texture2D> frames;
|
||||
|
||||
/// <summary>Preloads frames when the dialog queue is first loaded, so textures are ready before playback.</summary>
|
||||
public override ConstructType ConstructType { get; set; } = ConstructType.OnStartQueue;
|
||||
/// <summary>Animation runs in the background — the dialog queue continues immediately.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Preloads every sprite in <see cref="SpriteIDs"/> into memory so playback never stalls on I/O.</summary>
|
||||
public override void DoConstruct()
|
||||
{
|
||||
base.DoConstruct();
|
||||
LoadFrames();
|
||||
}
|
||||
|
||||
/// <summary>Stops the animation loop; the last shown frame stays on screen.</summary>
|
||||
public override void DoDestruct()
|
||||
{
|
||||
base.DoDestruct();
|
||||
isAnimating = false;
|
||||
}
|
||||
|
||||
private void LoadFrames()
|
||||
{
|
||||
frames = new List<Texture2D>();
|
||||
if (SpriteIDs == null)
|
||||
return;
|
||||
foreach (var id in SpriteIDs)
|
||||
{
|
||||
var tex = GD.Load<Texture2D>(id);
|
||||
if (tex != null)
|
||||
frames.Add(tex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Resets playback to the first frame and shows it on the ViewBox; per-frame stepping happens through <see cref="IOnUpdateEvent.OnUpdate"/>.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
currentFrame = 0;
|
||||
elapsed = 0f;
|
||||
isAnimating = frames != null && frames.Count > 0;
|
||||
|
||||
if (isAnimating)
|
||||
{
|
||||
var viewBox = Scene.Find<ViewBox>("ViewBox");
|
||||
viewBox?.SetForegroundTexture(frames[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void IOnUpdateEvent.OnUpdate()
|
||||
{
|
||||
if (!isAnimating || frames == null || frames.Count == 0)
|
||||
return;
|
||||
|
||||
var viewBox = Scene.Find<ViewBox>("ViewBox");
|
||||
if (viewBox == null)
|
||||
return;
|
||||
|
||||
elapsed += 1f / 60f;
|
||||
var frameDuration = 1f / Mathf.Max(Speed, 0.01f);
|
||||
if (elapsed >= frameDuration)
|
||||
{
|
||||
elapsed -= frameDuration;
|
||||
currentFrame++;
|
||||
if (currentFrame >= frames.Count)
|
||||
{
|
||||
if (IsLoop)
|
||||
currentFrame = 0;
|
||||
else
|
||||
{
|
||||
isAnimating = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
viewBox.SetForegroundTexture(frames[currentFrame]);
|
||||
Speed = NextFrameSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using Cthangover.Core.Factories.Impls;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Mods.Dialog.Action;
|
||||
using Cthangover.Mods.Time;
|
||||
using Cthangover.Mods.Interface.View;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the scene background on the ViewBox, including depth and albedo maps
|
||||
/// for the lighting system. Resolves textures through BackgroundFactory on
|
||||
/// construction (OnStartQueue) — depth and albedo are loaded from the same
|
||||
/// sprite ID with "_depth" / "_albedo" suffixes. Kills any in-progress
|
||||
/// background transition before setting the new texture. Textures are nulled
|
||||
/// after application to prevent stale reuse across dialog restarts.
|
||||
/// Sets SceneContextNode.LastBackgroundID so the scene manager can restore
|
||||
/// the correct background on scene revisit.
|
||||
/// </summary>
|
||||
public class ActionBackground : ActionCommand
|
||||
{
|
||||
/// <summary>Sprite resource ID resolved through <see cref="BackgroundFactory"/> on construction. Also loads depth (_depth) and albedo (_albedo) variants.</summary>
|
||||
public string SpriteID { get; set; }
|
||||
/// <summary>Direct texture override. When non-null, bypasses factory resolution. Set to null after application to prevent stale reuse.</summary>
|
||||
public Texture2D Texture { get; set; }
|
||||
/// <summary>Depth map for the lighting system, loaded from <see cref="SpriteID"/> + "_depth".</summary>
|
||||
public Texture2D DepthTexture { get; set; }
|
||||
/// <summary>Albedo color map for the lighting system, loaded from <see cref="SpriteID"/> + "_albedo".</summary>
|
||||
public Texture2D AlbedoTexture { get; set; }
|
||||
|
||||
/// <summary>Preloads textures when the dialog queue is first created, resolving SpriteID through the factory.</summary>
|
||||
public override ConstructType ConstructType { get; set; } = ConstructType.OnStartQueue;
|
||||
/// <summary>Background is set imperatively — the dialog continues immediately.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Resolves <see cref="SpriteID"/> plus its <c>_depth</c>/<c>_albedo</c> variants through the background factory.</summary>
|
||||
public override void DoConstruct()
|
||||
{
|
||||
base.DoConstruct();
|
||||
if (Texture == null && !string.IsNullOrEmpty(SpriteID))
|
||||
Texture = BackgroundFactory.Instance.Get(SpriteID);
|
||||
if (!string.IsNullOrEmpty(SpriteID))
|
||||
{
|
||||
DepthTexture = BackgroundFactory.Instance.Get(SpriteID + "_depth");
|
||||
AlbedoTexture = BackgroundFactory.Instance.Get(SpriteID + "_albedo");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the background to the ViewBox, kills any in-flight background
|
||||
/// transition and feeds the depth/albedo maps to the light controller.
|
||||
/// Consumed textures are nulled so a reused action cannot re-apply stale data.
|
||||
/// </summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
if (Texture == null)
|
||||
return;
|
||||
|
||||
SceneContextNode.LastBackgroundID = SpriteID;
|
||||
|
||||
var viewBox = Scene.Find<ViewBox>("ViewBox");
|
||||
viewBox?.KillTransitionTween();
|
||||
viewBox?.SetBackgroundTexture(Texture);
|
||||
|
||||
var controller = UiLightController.Instance;
|
||||
controller?.SetupDepthMap(DepthTexture);
|
||||
controller?.SetupAlbedoMap(AlbedoTexture);
|
||||
|
||||
Texture = null;
|
||||
DepthTexture = null;
|
||||
AlbedoTexture = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Cthangover.Mods.Dialog.Action;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the background tint color. DoRun is currently a no-op — the Color
|
||||
/// property is stored for external systems to read. Likely intended as a
|
||||
/// declarative instruction consumed by a background-rendering node rather
|
||||
/// than applied imperatively.
|
||||
/// </summary>
|
||||
public class ActionBackgroundColor : ActionCommand
|
||||
{
|
||||
/// <summary>Target tint color. Stored declaratively — consumed by background-rendering nodes rather than applied imperatively here.</summary>
|
||||
public Color Color { get; set; } = Colors.Black;
|
||||
|
||||
/// <summary>Imperative — the dialog continues immediately after this action is processed.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Deliberate no-op: the tint is declarative data for background-rendering nodes, not applied here.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using Cthangover.Mods.Dialog.Action;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Tween-driven background fade in/out. Animates the modulate alpha of the
|
||||
/// dialog box's parent Control over Duration seconds. Creates and manages
|
||||
/// its own Tween internally, killing any previous tween before starting a
|
||||
/// new one to prevent overlap. Can optionally set WaitType to WaitTime with
|
||||
/// a matching duration so the dialog pauses during the transition.
|
||||
/// </summary>
|
||||
public class ActionBackgroundShowHide : ActionCommand
|
||||
{
|
||||
/// <summary>Whether to fade the background in (Show) or out (Hide).</summary>
|
||||
public BackgroundActionType ActionType { get; set; } = BackgroundActionType.Show;
|
||||
/// <summary>Duration of the fade tween in seconds.</summary>
|
||||
public float Duration { get; set; } = 1f;
|
||||
|
||||
private Tween activeTween;
|
||||
|
||||
/// <summary>Default NoWait — overridden by the DialogQueue builder if the wait flag is set, changing to WaitTime to pause during transition.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Starts an alpha tween of the dialog box parent's <c>modulate:a</c> towards fully visible (Show) or fully transparent (Hide).</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var dialogBox = runtime.DialogBox;
|
||||
if (dialogBox == null)
|
||||
return;
|
||||
|
||||
var targetAlpha = ActionType == BackgroundActionType.Show ? 1f : 0f;
|
||||
|
||||
if (dialogBox.GetParent() is Control backgroundNode)
|
||||
{
|
||||
StopTween();
|
||||
activeTween = backgroundNode.CreateTween();
|
||||
activeTween.TweenProperty(backgroundNode, "modulate:a", targetAlpha, Duration);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Kills the fade tween so a destructed action cannot keep animating.</summary>
|
||||
public override void DoDestruct()
|
||||
{
|
||||
base.DoDestruct();
|
||||
StopTween();
|
||||
}
|
||||
|
||||
private void StopTween()
|
||||
{
|
||||
if (activeTween != null)
|
||||
{
|
||||
activeTween.Kill();
|
||||
activeTween = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using Cthangover.Mods.Dialog.Action;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Waits for a fixed duration. When HiddenMode is true, hides the dialog
|
||||
/// body for the duration (for dramatic pauses or cutscene beats). ShowText,
|
||||
/// if set, displays a temporary message during the wait. DoDestruct is a
|
||||
/// no-op because body visibility is implicitly restored on next Show.
|
||||
/// </summary>
|
||||
public class ActionDelay : ActionCommand
|
||||
{
|
||||
/// <summary>When true, hides the dialog body for the duration of the wait (dramatic pauses, cutscene beats).</summary>
|
||||
public bool HiddenMode { get; set; }
|
||||
/// <summary>Optional temporary text displayed while waiting. Set to null to keep the current dialog text.</summary>
|
||||
public string ShowText { get; set; }
|
||||
|
||||
/// <summary>Pauses the dialog until <see cref="WaitTime"/> elapses.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.WaitTime;
|
||||
/// <summary>Duration of the pause in seconds. Default 1.0.</summary>
|
||||
public override float WaitTime { get; set; } = 1f;
|
||||
|
||||
/// <summary>Shows the optional <see cref="ShowText"/> and, in <see cref="HiddenMode"/>, hides the dialog body for the pause duration.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var dialogBox = runtime.DialogBox;
|
||||
if (dialogBox == null)
|
||||
return;
|
||||
|
||||
if (ShowText != null)
|
||||
dialogBox.SetText(ShowText);
|
||||
|
||||
if (HiddenMode)
|
||||
dialogBox.Body.SetDeferred("visible", false);
|
||||
}
|
||||
|
||||
/// <summary>No-op: the dialog body hidden by <see cref="HiddenMode"/> is restored implicitly by the next show.</summary>
|
||||
public override void DoDestruct()
|
||||
{
|
||||
base.DoDestruct();
|
||||
if (HiddenMode)
|
||||
{
|
||||
// Body restored on next Show
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using Cthangover.Mods.Effects;
|
||||
using Cthangover.Core.Utils;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Spawns a visual effect from the EffectFactory by ID. The spawned node
|
||||
/// persists until the action is destructed. Uses DestructType.OnDelayed
|
||||
/// because the effect must outlive the action's run — the effect node's own
|
||||
/// animation or lifetime controls when it disappears. DoRun is a no-op
|
||||
/// because construction handles spawning.
|
||||
/// </summary>
|
||||
public class ActionEffect : ActionCommand
|
||||
{
|
||||
/// <summary>Identifier resolved through <see cref="EffectFactory"/> to a PackedScene. The spawned node persists until destructed.</summary>
|
||||
public string EffectID { get; set; }
|
||||
|
||||
private Node spawnedEffect;
|
||||
|
||||
/// <summary>The dialog continues immediately — the spawned effect plays independently.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
/// <summary>OnDelayed ensures the effect node outlives the action's run phase. Destruct is called manually when the effect finishes.</summary>
|
||||
public override DestructType DestructType { get; set; } = DestructType.OnDelayed;
|
||||
|
||||
/// <summary>Resolves <see cref="EffectID"/> through <see cref="EffectFactory"/> and instantiates the effect scene.</summary>
|
||||
public override void DoConstruct()
|
||||
{
|
||||
base.DoConstruct();
|
||||
if (string.IsNullOrEmpty(EffectID))
|
||||
return;
|
||||
|
||||
var packedScene = EffectFactory.Instance.Get(EffectID);
|
||||
if (packedScene == null)
|
||||
{
|
||||
GameLogger.Log("DIALOG", $"ActionEffect: effect '{EffectID}' not found", LogLevel.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
spawnedEffect = packedScene.Instantiate();
|
||||
}
|
||||
|
||||
/// <summary>No-op: spawning happens during construction so the effect is ready before the queue reaches this point.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Frees the spawned effect node; paired with the OnDelayed destruct so effects outlive the action's run.</summary>
|
||||
public override void DoDestruct()
|
||||
{
|
||||
base.DoDestruct();
|
||||
if (spawnedEffect != null)
|
||||
{
|
||||
spawnedEffect.QueueFree();
|
||||
spawnedEffect = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Cthangover.Mods.Dialog.Action;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// No-op placeholder action. Used as a labeled jump target (Point) for GoTo
|
||||
/// commands — provides an addressable marker in the dialog sequence without
|
||||
/// any visible effect. NoWait so the dialog skips through labels instantly.
|
||||
/// </summary>
|
||||
public class ActionEmpty : ActionCommand
|
||||
{
|
||||
/// <summary>Label actions skip immediately so the dialog doesn't pause on markers.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>No-op: the action exists only to carry the jump-target ID.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Cthangover.Mods.Dialog.Action;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Terminates the dialog queue immediately. Calls Runtime.End() which
|
||||
/// destructs all remaining actions, processes the cleanup queue, hides
|
||||
/// the dialog box, and fires the dialog-end event.
|
||||
/// </summary>
|
||||
public class ActionEnd : ActionCommand
|
||||
{
|
||||
/// <summary>Ends the dialog queue immediately — no pause, no return.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Terminates the queue via <see cref="DialogRuntime.End"/> — destructs remainders, runs cleanup, hides the box, fires the end event.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
runtime.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Cthangover.Core.Factories.Impls;
|
||||
using Cthangover.Mods.Interface.View;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the scene foreground texture on the ViewBox. Resolves SpriteID through
|
||||
/// BackgroundFactory on construction (OnStartQueue) so the texture is loaded
|
||||
/// before the dialog starts. Sets the texture to null after applying it —
|
||||
/// ActionCommand instances may be reused by the runtime, and nulling prevents
|
||||
/// double-applying stale references.
|
||||
/// </summary>
|
||||
public class ActionForeground : ActionCommand
|
||||
{
|
||||
/// <summary>Sprite resource ID resolved through <see cref="BackgroundFactory"/> on construction.</summary>
|
||||
public string SpriteID { get; set; }
|
||||
/// <summary>Direct texture override. Bypasses factory resolution. Nulled after application to prevent stale reuse across dialog cycles.</summary>
|
||||
public Texture2D Texture { get; set; }
|
||||
|
||||
/// <summary>Preloads the texture when the dialog queue is first created.</summary>
|
||||
public override ConstructType ConstructType { get; set; } = ConstructType.OnStartQueue;
|
||||
/// <summary>Foreground is set imperatively — the dialog continues immediately.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Resolves <see cref="SpriteID"/> through the background factory unless a direct texture override is set.</summary>
|
||||
public override void DoConstruct()
|
||||
{
|
||||
base.DoConstruct();
|
||||
if (Texture == null && !string.IsNullOrEmpty(SpriteID))
|
||||
Texture = BackgroundFactory.Instance.Get(SpriteID);
|
||||
}
|
||||
|
||||
/// <summary>Applies the preloaded texture to the ViewBox foreground, then nulls it so a reused action cannot re-apply stale data.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var viewBox = Scene.Find<ViewBox>("ViewBox");
|
||||
viewBox?.SetForegroundTexture(Texture);
|
||||
Texture = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Cthangover.Mods.Dialog.Action;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Unconditional jump to a labeled action in the dialog queue. NoWait so
|
||||
/// the jump happens transparently. The target is resolved by action ID
|
||||
/// (set via ActionCommand.SetID or the Point()/Empty() fluent methods).
|
||||
/// </summary>
|
||||
public class ActionGoTo : ActionCommand
|
||||
{
|
||||
/// <summary>Target action ID to jump to. Resolved by linear search through the dialog queue.</summary>
|
||||
public string GoTo { get; set; }
|
||||
|
||||
/// <summary>Jump happens transparently — the dialog continues from the target without pausing.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Jumps the queue index to the action whose ID matches <see cref="GoTo"/>.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
runtime.TryGoTo(GoTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Hides the dialog box. Used in cutscenes where UI chrome should be
|
||||
/// temporarily hidden while animations or background transitions play.
|
||||
/// Paired with ActionShowDialog to restore visibility.
|
||||
/// </summary>
|
||||
public class ActionHideDialog : ActionCommand
|
||||
{
|
||||
/// <summary>Hides the dialog immediately — the queue continues without pause.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Hides the dialog box chrome while keeping the queue running.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var dialogBox = runtime.DialogBox;
|
||||
if (dialogBox == null)
|
||||
return;
|
||||
|
||||
dialogBox.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using Cthangover.Core.Utils;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Conditional branch: evaluates a Func<bool> and jumps to TrueGoTo or
|
||||
/// FalseGoTo based on the result. If the chosen target is null/empty, falls
|
||||
/// through to Next(). NoWait so branching is transparent to the player.
|
||||
/// </summary>
|
||||
public class ActionIf : ActionCommand
|
||||
{
|
||||
/// <summary>Delegate evaluated at runtime. Must return true/false to select the branch target.</summary>
|
||||
public Func<bool> Condition { get; set; }
|
||||
/// <summary>Target action ID if <see cref="Condition"/> returns true. Empty or null causes fall-through.</summary>
|
||||
public string TrueGoTo { get; set; }
|
||||
/// <summary>Target action ID if <see cref="Condition"/> returns false. Empty or null causes fall-through.</summary>
|
||||
public string FalseGoTo { get; set; }
|
||||
|
||||
/// <summary>Branch evaluation is transparent — the dialog jumps to the target without user input.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Evaluates <see cref="Condition"/> and jumps to <see cref="TrueGoTo"/> or <see cref="FalseGoTo"/>; an empty target falls through to the next action.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
if (Condition == null)
|
||||
{
|
||||
GameLogger.Log("DIALOG", "ActionIf: Condition delegate is null", LogLevel.Error);
|
||||
runtime.Next();
|
||||
return;
|
||||
}
|
||||
|
||||
var result = Condition();
|
||||
var goTo = result ? TrueGoTo : FalseGoTo;
|
||||
|
||||
if (!string.IsNullOrEmpty(goTo))
|
||||
runtime.TryGoTo(goTo);
|
||||
else
|
||||
runtime.Next();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Cthangover.Core.Interactive;
|
||||
using Cthangover.Core.Utils;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialog action that instantiates an interactive object from its definition
|
||||
/// and places it on the scene. Executes immediately (NoWait).
|
||||
/// </summary>
|
||||
public class ActionInteractiveAdd : ActionCommand
|
||||
{
|
||||
/// <summary>The interactive definition ID to load and instantiate.</summary>
|
||||
public string DefinitionId { get; set; }
|
||||
|
||||
/// <summary>Placement happens immediately — the dialog does not pause.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Instantiates the interactive object named by <see cref="DefinitionId"/> through <see cref="InteractiveManager"/>.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
if (string.IsNullOrEmpty(DefinitionId))
|
||||
{
|
||||
GameLogger.Log("INTERACTIVE", "ActionInteractiveAdd: DefinitionId is empty", LogLevel.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var mgr = InteractiveManager.Instance;
|
||||
if (mgr == null)
|
||||
{
|
||||
GameLogger.Log("INTERACTIVE", "ActionInteractiveAdd: InteractiveManager not initialized yet", LogLevel.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
mgr.Add(DefinitionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Cthangover.Core.Interactive;
|
||||
using Cthangover.Core.Utils;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialog action that removes and destroys all active interactive objects.
|
||||
/// Typically used on scene exit to ensure clean state.
|
||||
/// </summary>
|
||||
public class ActionInteractiveClear : ActionCommand
|
||||
{
|
||||
/// <summary>Clearing happens immediately — the dialog does not pause.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Destroys every active interactive object via <see cref="InteractiveManager"/>.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
GameLogger.Log("INTERACTIVE", "ActionInteractiveClear: clearing all interactives");
|
||||
InteractiveManager.Instance?.ClearAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Cthangover.Core.Interactive;
|
||||
using Cthangover.Core.Utils;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialog action that removes and destroys an interactive object by its definition ID.
|
||||
/// </summary>
|
||||
public class ActionInteractiveRemove : ActionCommand
|
||||
{
|
||||
/// <summary>The definition ID of the interactive object to remove.</summary>
|
||||
public string DefinitionId { get; set; }
|
||||
|
||||
/// <summary>Removal happens immediately — the dialog does not pause.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Destroys the interactive object named by <see cref="DefinitionId"/>.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
if (string.IsNullOrEmpty(DefinitionId))
|
||||
{
|
||||
GameLogger.Log("INTERACTIVE", "ActionInteractiveRemove: DefinitionId is empty", LogLevel.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
InteractiveManager.Instance?.Remove(DefinitionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using Cthangover.Core.Interactive;
|
||||
using Cthangover.Core.Utils;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialog action that modifies a property of an active interactive object.
|
||||
/// Supported properties: <c>enabled</c> (bool), <c>visible</c> (bool).
|
||||
/// </summary>
|
||||
public class ActionInteractiveSet : ActionCommand
|
||||
{
|
||||
/// <summary>The definition ID of the interactive object to modify.</summary>
|
||||
public string DefinitionId { get; set; }
|
||||
|
||||
/// <summary>Property name: "enabled" or "visible".</summary>
|
||||
public string Property { get; set; }
|
||||
|
||||
/// <summary>String value to parse: "true" or "false".</summary>
|
||||
public string Value { get; set; }
|
||||
|
||||
/// <summary>Property changes happen immediately — the dialog does not pause.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Parses <see cref="Value"/> as a bool and applies it to the <c>enabled</c> or <c>visible</c> property of the object named by <see cref="DefinitionId"/>.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
if (string.IsNullOrEmpty(DefinitionId) || string.IsNullOrEmpty(Property) || string.IsNullOrEmpty(Value))
|
||||
{
|
||||
GameLogger.Log("INTERACTIVE", "ActionInteractiveSet: missing parameters", LogLevel.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var mgr = InteractiveManager.Instance;
|
||||
if (mgr == null)
|
||||
return;
|
||||
|
||||
if (!bool.TryParse(Value, out var boolVal))
|
||||
{
|
||||
GameLogger.Log("INTERACTIVE", $"ActionInteractiveSet: invalid bool value '{Value}'", LogLevel.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (Property.ToLowerInvariant())
|
||||
{
|
||||
case "enabled":
|
||||
mgr.SetEnabled(DefinitionId, boolVal);
|
||||
break;
|
||||
case "visible":
|
||||
mgr.SetVisible(DefinitionId, boolVal);
|
||||
break;
|
||||
default:
|
||||
GameLogger.Log("INTERACTIVE", $"ActionInteractiveSet: unknown property '{Property}'", LogLevel.Error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Cthangover.Mods.Time;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies static lights from a JSON string to the UiLightController.
|
||||
/// An empty or null string clears all static lights. The JSON is deserialized
|
||||
/// into LightDef objects with viewport-relative coordinates, which are then
|
||||
/// converted to pixel positions. Supports up to 10 static lights plus the
|
||||
/// player's dynamic lamp.
|
||||
/// </summary>
|
||||
public class ActionLightSet : ActionCommand
|
||||
{
|
||||
/// <summary>JSON string defining static light positions and properties. Empty or null clears all static lights.</summary>
|
||||
public string LightsJson { get; set; }
|
||||
|
||||
/// <summary>Lights are set imperatively — the dialog continues immediately.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Clears static lights when <see cref="LightsJson"/> is empty, otherwise parses and applies the light definitions to the scene's <see cref="UiLightController"/>.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var controller = Scene.Find<UiLightController>("Lights");
|
||||
if (controller == null)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrEmpty(LightsJson))
|
||||
controller.ClearStaticLights();
|
||||
else
|
||||
controller.SetStaticLights(LightsJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Cthangover.Mods.Dialog.Action;
|
||||
using Cthangover.Mods.Time;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Toggles the light controller's time-of-day mode. When UseTime is false,
|
||||
/// static lighting is used; when true, lighting responds to the in-game clock.
|
||||
/// </summary>
|
||||
public class ActionLightUseTime : ActionCommand
|
||||
{
|
||||
/// <summary>True = lights respond to in-game time of day; false = static lighting mode.</summary>
|
||||
public bool UseTime { get; set; } = true;
|
||||
|
||||
/// <summary>Time mode toggle is instant — the dialog continues without pause.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Switches the scene's <see cref="UiLightController"/> between time-of-day lighting and static lights.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var controller = Scene.Find<UiLightController>("Lights");
|
||||
if (controller != null)
|
||||
controller.IsUseLight = UseTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Cthangover.Core.Audio;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts background music playback via IAudioService. Uses MusicType.Ambient
|
||||
/// so the music layer is treated as atmospheric background rather than UI
|
||||
/// feedback. If the same music track is already playing, the audio service handles
|
||||
/// deduplication.
|
||||
/// </summary>
|
||||
public class ActionMusic : ActionCommand
|
||||
{
|
||||
/// <summary>Music track identifier resolved through the audio system. Empty strings are silently ignored.</summary>
|
||||
public string Music { get; set; }
|
||||
|
||||
/// <summary>Music starts playing in the background — the dialog continues immediately.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Starts the named track as ambient background music through <see cref="IAudioService"/>; empty names are ignored.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Music))
|
||||
return;
|
||||
|
||||
var audioService = Scene.Find<Node>("AudioService") as IAudioService;
|
||||
audioService?.PlayMusic(Music, MusicType.Ambient);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Cthangover.Core.Audio;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Pauses background music playback via IAudioService without stopping the
|
||||
/// track. Can be resumed with ActionMusicPlay.
|
||||
/// </summary>
|
||||
public class ActionMusicPause : ActionCommand
|
||||
{
|
||||
/// <summary>Pause is instant — the dialog continues without waiting for audio acknowledgment.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Pauses the current music track without stopping it, so <see cref="ActionMusicPlay"/> can resume it.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var audioService = Scene.Find<Node>("AudioService") as IAudioService;
|
||||
audioService?.PauseMusic(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Cthangover.Core.Audio;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Resumes paused background music. Paired with ActionMusicPause.
|
||||
/// </summary>
|
||||
public class ActionMusicPlay : ActionCommand
|
||||
{
|
||||
/// <summary>Resume is instant — the dialog continues without waiting for audio.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Resumes music paused by <see cref="ActionMusicPause"/>.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var audioService = Scene.Find<Node>("AudioService") as IAudioService;
|
||||
audioService?.PauseMusic(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Cthangover.Core.Utils;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes an arbitrary Action delegate inside the dialog queue.
|
||||
/// Allows imperative code injection (e.g. quest state changes, UI toggles)
|
||||
/// without creating a dedicated action class. NoWait so the queue advances
|
||||
/// immediately after the delegate returns.
|
||||
/// </summary>
|
||||
public class ActionRun : ActionCommand
|
||||
{
|
||||
/// <summary>Arbitrary delegate executed during dialog sequencing. Null delegates are logged and skipped.</summary>
|
||||
public System.Action Executable { get; set; }
|
||||
|
||||
/// <summary>The delegate runs and the dialog advances — no pausing.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Invokes <see cref="Executable"/>; a null delegate is logged and skipped so the queue keeps flowing.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
if (Executable == null)
|
||||
{
|
||||
GameLogger.Log("DIALOG", "ActionRun: Executable delegate is null", LogLevel.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
Executable();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using Cthangover.Core.Actions;
|
||||
using Cthangover.Core.Factories.Impls;
|
||||
using Cthangover.Core.Utils;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Bridges the dialog system to the broader scenario action system
|
||||
/// (ScenarioActionFactory). Resolves an action by name and runs it with a
|
||||
/// ScenarioActionContext wrapping the dialog runtime. Wraps execution in
|
||||
/// try/catch so a faulty scenario action doesn't crash the dialog queue.
|
||||
/// Every error log carries the owning scenario identity (see
|
||||
/// <see cref="DescribeScenario"/>): the runtime cannot report the source
|
||||
/// file and line — the parser drops them — but it can name the scenario
|
||||
/// definition, which together with the validator's file:line report
|
||||
/// pinpoints the broken command.
|
||||
/// </summary>
|
||||
public class ActionScenario : ActionCommand
|
||||
{
|
||||
/// <summary>Scenario action name resolved through <see cref="ScenarioActionFactory"/>. Empty names are logged and skipped.</summary>
|
||||
public string ActionName { get; set; }
|
||||
|
||||
/// <summary>The scenario action runs and the dialog advances — no synchronization.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Resolves <see cref="ActionName"/> through <see cref="ScenarioActionFactory"/> and runs it with a dialog-backed context; exceptions are logged, never propagated.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ActionName))
|
||||
{
|
||||
GameLogger.Log("DIALOG", "ActionScenario: ActionName is null or empty" + DescribeScenario(runtime), LogLevel.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var action = ScenarioActionFactory.Instance.Get(ActionName);
|
||||
if (action == null)
|
||||
{
|
||||
GameLogger.Log("DIALOG", $"ActionScenario: scenario action '{ActionName}' is not registered — the action is skipped, check the spelling and that the defining mod is loaded" + DescribeScenario(runtime), LogLevel.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var ctx = new ScenarioActionContext(runtime);
|
||||
try
|
||||
{
|
||||
action.Run(ctx);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
GameLogger.Log("DIALOG", $"ActionScenario: {ex.Message}\n{ex.StackTrace}" + DescribeScenario(runtime), LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats the scenario suffix for error logs. The locker that started
|
||||
/// the dialog is the event owning the scenario; its ID is the scenario
|
||||
/// definition name (ScenarioId) or, for code-driven lockers, the event
|
||||
/// type name. Returns a human-readable suffix either way, so a missing
|
||||
/// action in a shipped game can be traced to its scenario from
|
||||
/// user://logs/cthangover.log alone.
|
||||
/// </summary>
|
||||
private static string DescribeScenario(DialogRuntime runtime)
|
||||
{
|
||||
var id = runtime?.DialogBox?.Locker?.ID;
|
||||
return string.IsNullOrEmpty(id)
|
||||
? " (scenario unknown)"
|
||||
: $" (scenario '{id}')";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using Cthangover.Mods.Dialog.Action;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Presents player choices by spawning answer variants in the DialogBox.
|
||||
/// WaitType is WaitSelect so the dialog pauses until the player picks an
|
||||
/// option (which triggers DialogBox.SelectVariant → Runtime.TryGoTo).
|
||||
/// Each variant's text is processed through variable substitution before
|
||||
/// display. Also sets an accompanying text message to contextualize the
|
||||
/// choice (e.g. "What will you do?").
|
||||
/// </summary>
|
||||
public class ActionSelect : ActionCommand
|
||||
{
|
||||
/// <summary>The list of selectable choice variants. Each carries display text and a GoTo target.</summary>
|
||||
public List<SelectVariant> Variants { get; set; }
|
||||
/// <summary>Context text shown alongside the choices (e.g. "What will you do?"). Supports variable substitution.</summary>
|
||||
public string Text { get; set; }
|
||||
/// <summary>Left avatar sprite ID shown during the choice. Null hides the slot.</summary>
|
||||
public string FirstAvatar { get; set; }
|
||||
/// <summary>Right avatar sprite ID shown during the choice. Null hides the slot.</summary>
|
||||
public string SecondAvatar { get; set; }
|
||||
|
||||
/// <summary>Dialog pauses until the player selects a variant — then the runtime jumps to the chosen GoTo target.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.WaitSelect;
|
||||
|
||||
/// <summary>Substitutes variables in the variants and context text, then shows the answer box; the runtime stays paused until a variant is picked.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var dialogBox = runtime.DialogBox;
|
||||
if (dialogBox == null)
|
||||
return;
|
||||
|
||||
foreach (var variant in Variants)
|
||||
variant.Text = runtime.ProcessText(variant.Text);
|
||||
|
||||
dialogBox.SetVariants(Variants);
|
||||
dialogBox.SetText(runtime.ProcessText(Text));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets a dialog runtime variable (Name=Value) for use by subsequent actions
|
||||
/// via the ${var} substitution syntax. The optional Callback Func<string>
|
||||
/// allows lazy evaluation — if set, Value is ignored and Callback is invoked
|
||||
/// at runtime. This enables dynamic values (e.g. quest state, character names)
|
||||
/// that can't be known when the dialog script is authored.
|
||||
/// </summary>
|
||||
public class ActionSet : ActionCommand
|
||||
{
|
||||
/// <summary>Variable name. Referenced by subsequent actions via ${name} syntax.</summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>Literal value to store. Ignored if <see cref="Callback"/> is set.</summary>
|
||||
public string Value { get; set; }
|
||||
/// <summary>Lazy evaluation delegate. When non-null, invoked at runtime to compute the value dynamically.</summary>
|
||||
public Func<string> Callback { get; set; }
|
||||
|
||||
/// <summary>Variable assignment is instant — the dialog continues without pause.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Stores <see cref="Value"/> — or the result of <see cref="Callback"/> when set — as the runtime variable <see cref="Name"/>.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var val = Callback != null ? Callback() : Value;
|
||||
runtime.SetVariable(Name, val ?? string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Makes the dialog box visible. Typically paired with ActionHideDialog
|
||||
/// for cutscenes that temporarily hide the dialog UI while animations play.
|
||||
/// </summary>
|
||||
public class ActionShowDialog : ActionCommand
|
||||
{
|
||||
/// <summary>Dialog visibility change is instant — the queue continues without pause.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Makes the dialog box chrome visible again after <see cref="ActionHideDialog"/>.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var dialogBox = runtime.DialogBox;
|
||||
if (dialogBox == null)
|
||||
return;
|
||||
|
||||
dialogBox.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Cthangover.Core.Audio;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Plays a sound through the audio service using the UI sound channel (SoundType.UI).
|
||||
/// NoWait so the sound plays and the dialog continues immediately — no
|
||||
/// synchronization with audio completion.
|
||||
/// </summary>
|
||||
public class ActionSound : ActionCommand
|
||||
{
|
||||
/// <summary>Sound effect identifier resolved through <see cref="IAudioService"/>. Played on the UI channel.</summary>
|
||||
public string Sound { get; set; }
|
||||
|
||||
/// <summary>Sound is fire-and-forget — the dialog continues immediately without synchronization.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Plays <see cref="Sound"/> on the UI sound channel through <see cref="IAudioService"/>; empty names are ignored.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Sound))
|
||||
return;
|
||||
|
||||
var audioService = Scene.Find<Node>("AudioService") as IAudioService;
|
||||
audioService?.PlaySound(Sound, SoundType.UI);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Utils;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Deferred scene switch: calls SceneManager.SwitchScene via CallDeferred
|
||||
/// to avoid mid-queue scene tree mutations. NoWait ensures the dialog ends
|
||||
/// immediately — there's no return from a scene switch.
|
||||
/// <para/>
|
||||
/// Does NOT force the owning scenario into OneRun: re-runs are the scenario
|
||||
/// author's decision (is_one_run metadata) plus per-event conditions.
|
||||
/// Navigation menus (select + switch_scene) must survive into the next
|
||||
/// visit, and forcing OneRun recorded them in CompletedScenarioIds — after
|
||||
/// which FilterCompletedScenarios silently dropped the whole location menu
|
||||
/// on re-entry.
|
||||
/// </summary>
|
||||
public class ActionSwitchScene : ActionCommand
|
||||
{
|
||||
/// <summary>Target scene name passed to <see cref="SceneManager.SwitchScene"/>.</summary>
|
||||
public string SceneName { get; set; }
|
||||
/// <summary>Whether to transition with the dialog hidden. Default true.</summary>
|
||||
public bool HiddenMode { get; set; } = true;
|
||||
/// <summary>Transition speed parameter passed to the scene manager. Default 4.0.</summary>
|
||||
public float Speed { get; set; } = 4f;
|
||||
|
||||
/// <summary>Scene switch is deferred — the dialog ends immediately with no return.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Marks the dialog locker as OneRun and defers <c>SceneManager.SwitchScene</c> so the tree is not mutated mid-queue.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
if (string.IsNullOrEmpty(SceneName))
|
||||
{
|
||||
GameLogger.Log("DIALOG", "ActionSwitchScene: SceneName is null or empty", LogLevel.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// No forced IsOneRun here: location navigation scenarios are meant to
|
||||
// re-run on every visit. Forcing it made DialogRuntime record the
|
||||
// scenario as completed, and the next visit to the same scene started
|
||||
// without its menu. One-time story scenes declare is_one_run: true
|
||||
// (or a condition:) in their metadata instead.
|
||||
|
||||
GameLogger.Log("DIALOG", $"ActionSwitchScene: deferring switch to '{SceneName}'");
|
||||
|
||||
var sceneManager = Scene.Find<SceneManager>("SceneManager");
|
||||
if (sceneManager != null)
|
||||
{
|
||||
Callable.From(() => sceneManager.SwitchScene(SceneName)).CallDeferred();
|
||||
}
|
||||
else
|
||||
{
|
||||
GameLogger.Log("DIALOG", $"ActionSwitchScene: SceneManager not found for '{SceneName}'", LogLevel.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Cthangover.Core.Factories;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// The primary dialog text display action. Sets the text and both avatar slots
|
||||
/// (left/right) on the DialogBox. WaitType is WaitClick so the dialog pauses
|
||||
/// for player input before advancing. Avatars are resolved through
|
||||
/// IAvatarProvider by string ID; a null/empty avatar hides that slot. When
|
||||
/// UseProcessText is true, runtime variables (${var}) are substituted before display.
|
||||
/// </summary>
|
||||
public class ActionText : ActionCommand
|
||||
{
|
||||
/// <summary>The dialog text to display. Supports ${var} substitution when <see cref="UseProcessText"/> is true.</summary>
|
||||
public string Text { get; set; }
|
||||
/// <summary>Left avatar sprite ID resolved through <see cref="IAvatarProvider"/>. Null or empty hides the slot.</summary>
|
||||
public string FirstAvatar { get; set; }
|
||||
/// <summary>Right avatar sprite ID resolved through <see cref="IAvatarProvider"/>. Null or empty hides the slot.</summary>
|
||||
public string SecondAvatar { get; set; }
|
||||
/// <summary>When true, the avatar is rendered in shader-based silhouette/hidden-color mode.</summary>
|
||||
public bool HideColor { get; set; }
|
||||
/// <summary>When true, runtime variable substitution (${var}) is applied to <see cref="Text"/> before display.</summary>
|
||||
public bool UseProcessText { get; set; }
|
||||
|
||||
/// <summary>Pauses for player click/key input — the dialog waits for user acknowledgment.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.WaitClick;
|
||||
|
||||
/// <summary>Sets the dialog text (optionally variable-substituted) and both avatar slots, then waits for the player's click.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var dialogBox = runtime.DialogBox;
|
||||
if (dialogBox == null)
|
||||
return;
|
||||
|
||||
var processedText = UseProcessText ? runtime.ProcessText(Text) : Text;
|
||||
dialogBox.SetText(processedText);
|
||||
dialogBox.SetFirstAvatar(AvatarProviderRegistry.Get(FirstAvatar), HideColor);
|
||||
dialogBox.SetSecondAvatar(AvatarProviderRegistry.Get(SecondAvatar), HideColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Godot;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Timeline-based update action: registers itself as an IOnUpdateEvent
|
||||
/// subscriber and fires OnUpdateCallback(float t) each frame with a normalized
|
||||
/// progress value (0→1) over WaitTime seconds. WaitType is WaitEvent so the
|
||||
/// dialog runtime pauses until elapsed >= WaitTime, at which point the action
|
||||
/// advances the runtime directly (event-driven — no DialogBox poll) and
|
||||
/// destructs itself. OnStartCallback/OnFinishCallback bracket the animation
|
||||
/// for setup/teardown. Fixed 60fps step for deterministic progress regardless
|
||||
/// of actual frame rate.
|
||||
/// </summary>
|
||||
public class ActionTimedUpdate : ActionCommand, IOnUpdateEvent
|
||||
{
|
||||
/// <summary>Update priority. Value 0 — runs before most other listeners.</summary>
|
||||
public int Priority => 0;
|
||||
|
||||
/// <summary>Fires once when <see cref="DoRun"/> is called, before the first update frame.</summary>
|
||||
public System.Action OnStartCallback { get; set; }
|
||||
/// <summary>Fires each frame during the active period with a normalized progress value t (0→1) over <see cref="WaitTime"/> seconds.</summary>
|
||||
public System.Action<float> OnUpdateCallback { get; set; }
|
||||
/// <summary>Fires once when the elapsed time exceeds <see cref="WaitTime"/> or when destructed.</summary>
|
||||
public System.Action OnFinishCallback { get; set; }
|
||||
|
||||
/// <summary>Pauses the dialog until the elapsed time meets WaitTime — the action then advances the runtime itself.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.WaitEvent;
|
||||
/// <summary>Total duration in seconds over which <see cref="OnUpdateCallback"/> receives normalized progress.</summary>
|
||||
public override float WaitTime { get; set; } = 1f;
|
||||
|
||||
private float elapsed;
|
||||
private bool isRunning;
|
||||
private DialogRuntime runtime;
|
||||
|
||||
/// <summary>Registers this action as an <see cref="IOnUpdateEvent"/> listener on the scene's event controller.</summary>
|
||||
public override void DoConstruct()
|
||||
{
|
||||
base.DoConstruct();
|
||||
var controller = Scene.Find<SceneEventController>("EventController");
|
||||
controller?.AddUpdateEventListener(this);
|
||||
}
|
||||
|
||||
/// <summary>Starts the timeline: resets elapsed time and fires <see cref="OnStartCallback"/> before the first frame.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
this.runtime = runtime;
|
||||
elapsed = 0f;
|
||||
isRunning = true;
|
||||
OnStartCallback?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>Detaches from the update controller, stops ticking and fires <see cref="OnFinishCallback"/>.</summary>
|
||||
public override void DoDestruct()
|
||||
{
|
||||
base.DoDestruct();
|
||||
isRunning = false;
|
||||
runtime = null;
|
||||
var controller = Scene.Find<SceneEventController>("EventController");
|
||||
controller?.RemoveUpdateEventListener(this);
|
||||
OnFinishCallback?.Invoke();
|
||||
}
|
||||
|
||||
void IOnUpdateEvent.OnUpdate()
|
||||
{
|
||||
if (!isRunning)
|
||||
return;
|
||||
|
||||
elapsed += 1f / 60f;
|
||||
|
||||
var t = WaitTime > 0f ? Mathf.Min(elapsed / WaitTime, 1f) : 1f;
|
||||
OnUpdateCallback?.Invoke(t);
|
||||
|
||||
if (elapsed >= WaitTime)
|
||||
{
|
||||
// Advances the runtime directly instead of relying on a DialogBox poll.
|
||||
// Next() destructs this action (firing OnFinishCallback and detaching the
|
||||
// update listener), then Run() continues the queue past the WaitEvent point.
|
||||
isRunning = false;
|
||||
runtime?.Next();
|
||||
runtime?.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the dialog box title text. A null title hides the title bar.
|
||||
/// NoWait — title updates are instant visual changes.
|
||||
/// </summary>
|
||||
public class ActionTitle : ActionCommand
|
||||
{
|
||||
/// <summary>Text to display in the title bar. Null hides the title bar.</summary>
|
||||
public string TitleText { get; set; }
|
||||
|
||||
/// <summary>Title changes are instant visual updates — the dialog continues immediately.</summary>
|
||||
public override WaitType WaitType { get; set; } = WaitType.NoWait;
|
||||
|
||||
/// <summary>Applies <see cref="TitleText"/> to the dialog title bar; null hides the bar.</summary>
|
||||
public override void DoRun(DialogRuntime runtime)
|
||||
{
|
||||
var dialogBox = runtime.DialogBox;
|
||||
if (dialogBox == null)
|
||||
return;
|
||||
|
||||
dialogBox.SetTitle(TitleText);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Discriminator for background show/hide transitions.
|
||||
/// </summary>
|
||||
public enum BackgroundActionType
|
||||
{
|
||||
/// <summary>Fade the dialog background visible (target alpha = 1.0).</summary>
|
||||
Show,
|
||||
/// <summary>Fade the dialog background transparent (target alpha = 0.0).</summary>
|
||||
Hide
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using Cthangover.Core.UI;
|
||||
using Cthangover.Mods.Interface.Base.Lists;
|
||||
using Cthangover.Core.UI.Dialog;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Cthangover.Core.UI.Executable;
|
||||
using Cthangover.Core.Scenarios;
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Interactive;
|
||||
|
||||
namespace Cthangover.Mods.Dialog.Action.Impls
|
||||
{
|
||||
/// <summary>
|
||||
/// Data model for a dialog choice option: display Text and a GoTo target
|
||||
/// action ID. The static Point property returns a fresh GUID for runtime
|
||||
/// goto targets. The New factory provides concise C# construction without
|
||||
/// object-initializer syntax.
|
||||
/// </summary>
|
||||
public class SelectVariant
|
||||
{
|
||||
/// <summary>The text displayed on the choice button. Supports runtime variable substitution.</summary>
|
||||
public string Text { get; set; }
|
||||
/// <summary>Target action ID to jump to via <see cref="DialogRuntime.TryGoTo"/> when this variant is selected.</summary>
|
||||
public string GoTo { get; set; }
|
||||
|
||||
/// <summary>Generates a new unique action ID for use as a GoTo target (e.g. with <see cref="DialogQueue.Point"/>).</summary>
|
||||
public static string Point => Guid.NewGuid().ToString();
|
||||
|
||||
/// <summary>Factory for concise C# construction without object-initializer syntax.</summary>
|
||||
public static SelectVariant New(string text, string goTo)
|
||||
{
|
||||
return new SelectVariant { Text = text, GoTo = goTo };
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user