Implement ADV controls and native Auto timing

This commit is contained in:
gamer147
2026-07-18 17:16:06 -04:00
parent 8c7c7158a7
commit 4bf98cc7af
20 changed files with 1184 additions and 256 deletions

View File

@@ -0,0 +1,50 @@
namespace Age.Engine.Hosting;
/// <summary>
/// Native ADV Auto timing policy. Unvoiced waits use AutoMessageTime1; voiced waits park until voice
/// completion and then use AutoMessageTime0. The host supplies a monotonic clock and live voice state.
/// </summary>
public sealed class AdvAutoAdvanceTimer
{
private bool _armed;
private bool _waitingForVoice;
private long _deadlineMs;
public void Reset()
{
_armed = false;
_waitingForVoice = false;
_deadlineMs = 0;
}
public bool Poll(AdvAutoWaitState state, bool voiceActive, long nowMs)
{
if (!state.Enabled)
{
Reset();
return false;
}
if (!_armed)
{
_armed = true;
_waitingForVoice = state.VoicePending && voiceActive;
if (!_waitingForVoice)
_deadlineMs = nowMs + EffectiveDelay(
state.VoicePending ? state.PostVoiceDelayMs : state.UnvoicedDelayMs);
}
if (_waitingForVoice)
{
if (voiceActive) return false;
_waitingForVoice = false;
_deadlineMs = nowMs + EffectiveDelay(state.PostVoiceDelayMs);
}
return nowMs >= _deadlineMs;
}
// Native callers substitute 100 ms when either configuration getter returns zero.
private static long EffectiveDelay(long configuredMs)
=> configuredMs == 0 ? 100 : System.Math.Max(1, configuredMs);
}

View File

@@ -7,6 +7,9 @@ public readonly record struct AdvWaitIndicatorConfig(
int SourceX, int SourceY, int CellWidth, int CellHeight,
int TerminalFrame, long FramePeriodMs);
public readonly record struct AdvAutoWaitState(
bool Enabled, bool VoicePending, long PostVoiceDelayMs, long UnvoicedDelayMs);
public interface IHost
{
void ShowText(int offset, string text);
@@ -17,6 +20,18 @@ public interface IHost
void ConfigureAdvWaitIndicator(AdvWaitIndicatorConfig config) { }
void WaitForInput();
void WaitForInput(int layoutSlot) => WaitForInput();
// Interactive hosts service script callbacks on the VM thread while the enclosing ADV page remains
// parked. The callback returns true while another queued input callback is ready to run.
void WaitForInput(int layoutSlot, Func<bool> serviceInputCallback)
{
while (serviceInputCallback()) { }
WaitForInput(layoutSlot);
}
void WaitForInput(int layoutSlot, Func<bool> serviceInputCallback,
Func<AdvAutoWaitState> autoWaitState)
=> WaitForInput(layoutSlot, serviceInputCallback);
void WakeInputCallbackService() { }
void InputCallbackCompleted(GfxState gfx) { }
void Sleep(long duration);
void FrameYield();
// Native 0x1c7/0x1cc query two distinct ADV skip channels. Headless and non-interactive