This commit is contained in:
iisaev committed 2026-10-18 12:41:38 +03:00
commit 5de3fd7ad8
121 files changed
+6632

No files matched your search

@@ -0,0 +1,90 @@
using Cthangover.Core.Scenes;
using Cthangover.Mods.Dialog;
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.Executable
{
/// <summary>
/// Sequential list-based chain: rescans GetNext() only when the condition
/// state changes (bumped <see cref="ConditionStateMonitor.Version"/>), on the
/// end of its own running dialog, or on the first scan — with a debounce.
/// When an event runs, it's removed from the list first, so it's consumed and
/// the chain shrinks until empty (no self-loop is possible, so no skip-guard
/// is needed). Respects IsOneRun (skips already-run events) and
/// CheckConditions (skips events whose conditions fail). Use for ordered
/// event sequences where each event should play once in order.
/// </summary>
public partial class ExecutableEventListChain : ExecutableEventChainBase
{
private float checkDelay = 1f;
private float timestamp;
private long _lastScanVersion = long.MinValue;
private bool _pendingDialog;
private bool _wakeup;
/// <summary>Debounced chain driver: waits out the running dialog, rescans when the condition state changed and starts the next unconsumed event.</summary>
public override void _Process(double delta)
{
if (!isActive || chain.Count == 0)
{
IsActive = false;
return;
}
if (_pendingDialog)
{
if (dialogBox == null || dialogBox.Locker != null)
return;
_pendingDialog = false;
_lastScanVersion = ConditionStateMonitor.Version;
_wakeup = true;
return;
}
double time = Godot.Time.GetTicksUsec() / 1_000_000.0;
if(time - timestamp < checkDelay)
return;
timestamp = (float)time;
var version = ConditionStateMonitor.Version;
if (version == _lastScanVersion && !_wakeup)
return;
_wakeup = false;
_lastScanVersion = version;
var next = GetNext();
if(next == null)
return;
chain.Remove(next);
next.RunDialog();
_pendingDialog = true;
}
protected override ExecutableEvent GetNext()
{
if (Lists.IsEmpty(chain))
return null;
foreach (var additional in chain)
{
if(additional.IsOneRun && !additional.IsFirstRun)
continue;
if (additional.CheckConditions)
return additional;
}
return null;
}
}
}