Fix ADV transition and nested input lifecycles
This commit is contained in:
@@ -111,7 +111,8 @@ public class ForegroundTransitionTests
|
||||
gfx.QueueMovieMaskTransition(new MovieMaskTransitionRequest(
|
||||
11, 45, 10, 1, -184, 0, 800, 600, 0, 0x325e, 0, 1000));
|
||||
|
||||
Assert.Equal(3, gfx.CompleteClickSkippableTimedPresentation(200));
|
||||
Assert.True(gfx.TryCompleteClickSkippableTimedPresentation(200, out int completed));
|
||||
Assert.Equal(3, completed);
|
||||
|
||||
Assert.Equal(1.0, gfx.SnapshotForegroundTransitions(200).Single().Progress);
|
||||
Assert.False(gfx.TryGet(100)!.OneShotColorEnabled);
|
||||
@@ -123,9 +124,8 @@ public class ForegroundTransitionTests
|
||||
|
||||
[Theory]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
[InlineData(3)]
|
||||
public void AnimationServiceFlagsSuppressClickCompletion(long flags)
|
||||
public void AnimationServiceFlagBit0RejectsClickCompletion(long flags)
|
||||
{
|
||||
var gfx = new GfxState();
|
||||
gfx.SetSurface(4, 0x25, -1);
|
||||
@@ -133,7 +133,35 @@ public class ForegroundTransitionTests
|
||||
gfx.SetAnimatedObjectColorResolved(100, 0, 1000, 0, 0xffffff);
|
||||
gfx.SetAnimationServiceFlags(flags);
|
||||
|
||||
Assert.Equal(0, gfx.CompleteClickSkippableTimedPresentation(100));
|
||||
Assert.False(gfx.TryCompleteClickSkippableTimedPresentation(100, out int completed));
|
||||
Assert.Equal(0, completed);
|
||||
Assert.True(gfx.TryGet(100)!.OneShotColorEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AnimationServiceFlagBit1AcceptsWaitBypassWithoutForcingEndpoint()
|
||||
{
|
||||
var gfx = new GfxState();
|
||||
gfx.SetSurface(4, 0x25, -1);
|
||||
gfx.BindDraw(100, 4, 0, 0, 800, 600, 0, 0);
|
||||
gfx.SetAnimatedObjectColorResolved(100, 0, 1000, 0, 0xffffff);
|
||||
gfx.SetAnimationServiceFlags(2);
|
||||
|
||||
Assert.True(gfx.TryCompleteClickSkippableTimedPresentation(100, out int completed));
|
||||
Assert.Equal(0, completed);
|
||||
Assert.True(gfx.TryGet(100)!.OneShotColorEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MovieMaskAcceptsWaitBypassAndContinuesAsynchronously()
|
||||
{
|
||||
var gfx = new GfxState();
|
||||
gfx.QueueMovieMaskTransition(new MovieMaskTransitionRequest(
|
||||
11, 45, 10, 1, -184, 0, 800, 600, 0, 0x325e, 0, 1000));
|
||||
|
||||
Assert.True(gfx.TryCompleteClickSkippableTimedPresentation(100, out int completed));
|
||||
Assert.Equal(0, completed);
|
||||
Assert.True(gfx.HasActiveTimedPresentation(100));
|
||||
Assert.False(gfx.SnapshotMovieMaskTransitions().Single().Completed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ public class InputBindingTests
|
||||
Sys4ScriptProvider.Load(Table).RequireByName("SYSTEM4.BIN"), vm.InputBindings);
|
||||
|
||||
vm.UpdateKeyboardVirtualKeyState(virtualKey, true);
|
||||
Assert.False(host.PhysicalMessageSkip); // ADV lifecycle is not active yet.
|
||||
Assert.True(host.PhysicalMessageSkip);
|
||||
|
||||
vm.Run();
|
||||
|
||||
@@ -98,6 +98,29 @@ public class InputBindingTests
|
||||
Assert.False(host.MessageSkip);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HeldLogicalActionSixSurvivesPersistentSkipLifecycleSuspension()
|
||||
{
|
||||
var script = ScriptAssembler.Assemble(Table, "HELD_SKIP_LIFECYCLE", new List<(int, Operand[])>
|
||||
{
|
||||
(0x19c, Array.Empty<Operand>()),
|
||||
(0x19b, Array.Empty<Operand>()),
|
||||
(0x1c7, new[] { G(0x140) }),
|
||||
(0x2, Array.Empty<Operand>()),
|
||||
}, Array.Empty<string>());
|
||||
var host = new RecordingHost();
|
||||
var vm = new VirtualMachine(script, Table, host);
|
||||
InputBindingBootstrap.Apply(
|
||||
Sys4ScriptProvider.Load(Table).RequireByName("SYSTEM4.BIN"), vm.InputBindings);
|
||||
|
||||
vm.UpdateKeyboardVirtualKeyState(0x11, true);
|
||||
vm.Run();
|
||||
|
||||
Assert.True(host.PhysicalMessageSkip);
|
||||
Assert.True(host.MessageSkip);
|
||||
Assert.Equal(1, vm.Globals.GetValueOrDefault(0x140));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReleasingPhysicalFastForwardDoesNotClearPersistentSkip()
|
||||
{
|
||||
|
||||
@@ -6,6 +6,28 @@ using Xunit;
|
||||
|
||||
public class WaitForInputTests
|
||||
{
|
||||
private sealed class NestedWaitHost : RecordingHost
|
||||
{
|
||||
public VirtualMachine Vm = null!;
|
||||
public bool SawDormantParentCallback;
|
||||
public bool SawParentCallbackRestored;
|
||||
|
||||
public override void WaitForInput(int layoutSlot, System.Func<bool> serviceInputCallback)
|
||||
{
|
||||
Waits++;
|
||||
SawDormantParentCallback =
|
||||
Vm.RawInputCallbackScriptName == "PARENT"
|
||||
&& !Vm.IsRawInputCallbackActive;
|
||||
}
|
||||
|
||||
public override void Sleep(long duration)
|
||||
{
|
||||
SawParentCallbackRestored =
|
||||
Vm.RawInputCallbackScriptName == "PARENT"
|
||||
&& Vm.IsRawInputCallbackActive;
|
||||
}
|
||||
}
|
||||
|
||||
// wait-for-input (0x72) fires per page. Synthesize a two-page scene and assert it fires exactly
|
||||
// twice — full handling, no dependency on a real scene's (stubbed) line count.
|
||||
[Fact]
|
||||
@@ -28,4 +50,35 @@ public class WaitForInputTests
|
||||
Assert.Equal(new[] { "page one", "page two" }, vm.Emitted.Select(e => e.Text).ToArray());
|
||||
Assert.Equal("exit", vm.HaltReason);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DormantParentRawInputCallbackDoesNotOwnNestedDialogueWait()
|
||||
{
|
||||
var t = OpcodeTableJson.Load(Paths.OpcodesJson);
|
||||
var child = ScriptAssembler.Assemble(t, "CHILD", new List<(int, Operand[])>
|
||||
{
|
||||
(0x6e, new[] { new Operand(2, 0), new Operand(0, 0) }),
|
||||
(0x72, new[] { new Operand(0, 0) }),
|
||||
(0x2, System.Array.Empty<Operand>()),
|
||||
}, new[] { "nested dialogue" });
|
||||
var parent = ScriptAssembler.Assemble(t, "PARENT", new List<(int, Operand[])>
|
||||
{
|
||||
// FIELD-style timed mouse callback remains registered while call-script enters an ADV scene.
|
||||
(0xcc, new[] { new Operand(0, 50), new Operand(0, 0xffff_ffff) }),
|
||||
(0x3, new[] { new Operand(0, 5) }),
|
||||
(0xc8, new[] { new Operand(0, 0) }),
|
||||
(0x2, System.Array.Empty<Operand>()),
|
||||
}, System.Array.Empty<string>());
|
||||
var host = new NestedWaitHost();
|
||||
var vm = new VirtualMachine(parent, t, host, provider: new MapProvider(new() { [5] = child }));
|
||||
host.Vm = vm;
|
||||
|
||||
vm.Run();
|
||||
|
||||
Assert.True(host.SawDormantParentCallback);
|
||||
Assert.True(host.SawParentCallbackRestored);
|
||||
Assert.Equal(1, host.Waits);
|
||||
Assert.False(vm.IsRawInputCallbackActive);
|
||||
Assert.Equal("exit", vm.HaltReason);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user