fix(vm): faithful headless — halt at wait-for-input instead of plowing
The headless divergence that sent us chasing a phantom 'sleep' spin: op 0x72 wait-for-input was a no-op headless, so a run plowed past all 166 of a scene's prompts into code no real playthrough reaches (SC0000 -> the name-entry poll loop, spinning sleep 1 493k x to STEP-LIMIT). That path is a fiction. Fix: VmOptions.HaltAtWaitForInput -> the VM halts (reason 'wait-for-input') at 0x72. run/play default to faithful (SC0000 now halts at ~402 steps, 0 sleeps, matching the real run's path to the first prompt); --plow opts into the old walk-every-page coverage. sweep stays plow by default (dialogue oracle, 284/13 unchanged); --halt-at-wait makes all 297 scenes halt cleanly at their first prompt (0 STEP-LIMIT). Godot unaffected (really blocks on input; flag false). Engine 58/58 (2 new); sweep default 284/13 unchanged; Godot selftest OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
43
engine/Age.Engine.Tests/HaltAtWaitTests.cs
Normal file
43
engine/Age.Engine.Tests/HaltAtWaitTests.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Age.Engine.Model;
|
||||
using Age.Engine.Sys4;
|
||||
using Age.Engine.Vm;
|
||||
using Xunit;
|
||||
|
||||
public class HaltAtWaitTests
|
||||
{
|
||||
private static OpcodeTable Table() => OpcodeTableJson.Load(Paths.OpcodesJson);
|
||||
|
||||
// Two-page scene: show A ; wait-for-input ; show B ; exit.
|
||||
private static Age.Engine.Model.Script TwoPage(OpcodeTable t) => ScriptAssembler.Assemble(t, "TWOPAGE",
|
||||
new List<(int, Operand[])>
|
||||
{
|
||||
(0x6e, new[] { new Operand(2, 0), new Operand(0, 0) }), // show-text A
|
||||
(0x72, new[] { new Operand(0, 0) }), // wait-for-input
|
||||
(0x6e, new[] { new Operand(2, 1), new Operand(0, 0) }), // show-text B
|
||||
(0x2, Array.Empty<Operand>()), // exit
|
||||
}, new[] { "A", "B" });
|
||||
|
||||
[Fact]
|
||||
public void Default_PlowsPastWait_EmitsBothPages()
|
||||
{
|
||||
var t = Table();
|
||||
var host = new RecordingHost();
|
||||
var vm = new VirtualMachine(TwoPage(t), t, host); // default VmOptions => HaltAtWaitForInput=false
|
||||
vm.Run();
|
||||
Assert.Equal(2, host.Lines.Count); // both pages emitted (plow)
|
||||
Assert.Equal("exit", vm.HaltReason);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HaltAtWait_StopsAtFirstWait_EmitsOnlyFirstPage()
|
||||
{
|
||||
var t = Table();
|
||||
var host = new RecordingHost();
|
||||
var vm = new VirtualMachine(TwoPage(t), t, host, new VmOptions(HaltAtWaitForInput: true));
|
||||
vm.Run();
|
||||
Assert.Single(host.Lines); // only page A ran; halted at the wait
|
||||
Assert.Equal("wait-for-input", vm.HaltReason);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user