From b668c83de445d4e9f51d62d04fa41582af47efd1 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 6 Jul 2026 14:48:46 -0400 Subject: [PATCH] feat(a2a): add IHost.WaitForInput hook (wait-for-input 0x72); trace parity preserved Co-Authored-By: Claude Opus 4.8 (1M context) --- engine/Age.Engine.Tests/WaitForInputTests.cs | 31 ++++++++++++++++++++ engine/Age.Engine/Hosting/CaptureHost.cs | 1 + engine/Age.Engine/Hosting/IHost.cs | 1 + engine/Age.Engine/Vm/VirtualMachine.cs | 3 +- 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 engine/Age.Engine.Tests/WaitForInputTests.cs diff --git a/engine/Age.Engine.Tests/WaitForInputTests.cs b/engine/Age.Engine.Tests/WaitForInputTests.cs new file mode 100644 index 0000000..881e542 --- /dev/null +++ b/engine/Age.Engine.Tests/WaitForInputTests.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using Age.Engine.Hosting; +using Age.Engine.Sys4; +using Age.Engine.Vm; +using Xunit; + +public class WaitForInputTests +{ + private sealed class CountHost : IHost + { + public int Waits; + public List Emitted = new(); + public void ShowText(int offset, string text) => Emitted.Add(offset); + public void CallScript(long id) { } + public void OnStub(int opcode) { } + public void WaitForInput() => Waits++; + } + + [Fact] + public void WaitForInputFiresAndEmittedIsStable() + { + var table = OpcodeTableJson.Load(Paths.OpcodesJson); + var script = Sys4Loader.Load(Paths.Scripts()["SC0000.BIN"], table); + var host = new CountHost(); + var vm = new VirtualMachine(script, table, host); + vm.Run(); + Assert.True(host.Waits > 0, "wait-for-input (0x72) should fire at least once"); + Assert.Equal(186, host.Emitted.Count); // unchanged vs the A1 SC0000 trace + Assert.Equal("exit", vm.HaltReason); + } +} diff --git a/engine/Age.Engine/Hosting/CaptureHost.cs b/engine/Age.Engine/Hosting/CaptureHost.cs index 14dbac3..e01521e 100644 --- a/engine/Age.Engine/Hosting/CaptureHost.cs +++ b/engine/Age.Engine/Hosting/CaptureHost.cs @@ -7,4 +7,5 @@ public sealed class CaptureHost : IHost public void ShowText(int offset, string text) => Emitted.Add((offset, text)); public void CallScript(long id) => CallScriptCount++; public void OnStub(int opcode) { Stubs.TryGetValue(opcode, out var c); Stubs[opcode] = c + 1; } + public void WaitForInput() { } } diff --git a/engine/Age.Engine/Hosting/IHost.cs b/engine/Age.Engine/Hosting/IHost.cs index 030276b..8b4286d 100644 --- a/engine/Age.Engine/Hosting/IHost.cs +++ b/engine/Age.Engine/Hosting/IHost.cs @@ -4,4 +4,5 @@ public interface IHost void ShowText(int offset, string text); void CallScript(long id); void OnStub(int opcode); + void WaitForInput(); } diff --git a/engine/Age.Engine/Vm/VirtualMachine.cs b/engine/Age.Engine/Vm/VirtualMachine.cs index 9594993..f64366d 100644 --- a/engine/Age.Engine/Vm/VirtualMachine.cs +++ b/engine/Age.Engine/Vm/VirtualMachine.cs @@ -164,7 +164,8 @@ public sealed class VirtualMachine _host.ShowText(off, text); } return pc + 1; - case "end-text-line": case "wait-for-input": case "set-font": + case "wait-for-input": _host.WaitForInput(); return pc + 1; + case "end-text-line": case "set-font": case "comment": case "display-furigana": case "dev_ukn": return pc + 1; default: