45 lines
2.2 KiB
C#
45 lines
2.2 KiB
C#
namespace BardFrontline.Core;
|
|
|
|
// One outstanding native request. Cooldown changes alone are insufficient for a cleanse: wait for acknowledgement.
|
|
public sealed class RequestGate
|
|
{
|
|
public ActionDecision? Pending { get; private set; }
|
|
private double sentAt;
|
|
private ushort beforeSequence;
|
|
private bool sequenceObserved;
|
|
private ushort requestSequence;
|
|
private readonly Dictionary<(Skill, ulong), double> failures = [];
|
|
public string Reason { get; private set; } = "";
|
|
|
|
public void Submitted(ActionDecision decision, double now, ushort before, ushort after)
|
|
{
|
|
Pending = decision; sentAt = now; beforeSequence = before;
|
|
sequenceObserved = after != before; requestSequence = after; Reason = "等待动作确认";
|
|
}
|
|
public bool Update(double now, ushort used, ushort handled, bool guardActive, bool cleansingStateChanged, bool ownedCastInProgress = false)
|
|
{
|
|
if (Pending == null) return false;
|
|
if (!sequenceObserved && used != beforeSequence) { sequenceObserved = true; requestSequence = used; }
|
|
var acknowledged = sequenceObserved && unchecked((short)(handled - requestSequence)) >= 0;
|
|
var elapsed = now - sentAt;
|
|
var release = Pending.Skill switch
|
|
{
|
|
Skill.Guard => guardActive || acknowledged && elapsed >= .5,
|
|
Skill.Purify or Skill.WardensPaean => cleansingStateChanged || acknowledged && elapsed >= .5,
|
|
_ => acknowledged && elapsed >= .1,
|
|
};
|
|
if (release) { Pending = null; Reason = ""; return false; }
|
|
if (ownedCastInProgress) return true;
|
|
if (elapsed < 2) return true;
|
|
Fail(Pending, now, "动作确认超时,短暂退避"); Pending = null;
|
|
return false;
|
|
}
|
|
public bool IsBlocked(Skill s, ulong id, double now) => failures.TryGetValue((s, id), out var until) && until > now;
|
|
public void Fail(ActionDecision d, double now, string reason)
|
|
{
|
|
failures[(d.Skill, d.TargetId)] = now + .5; Reason = reason;
|
|
foreach (var key in failures.Where(x => x.Value <= now).Select(x => x.Key).ToArray()) failures.Remove(key);
|
|
}
|
|
public void Reset() { Pending = null; failures.Clear(); Reason = ""; }
|
|
}
|