Implement ADV History voice replay

This commit is contained in:
gamer147
2026-07-19 14:11:49 -04:00
parent 538e87d368
commit 8f94ef86ac
10 changed files with 134 additions and 21 deletions

View File

@@ -1,3 +1,4 @@
using Age.Engine.Hosting;
using Age.Engine.Model;
using Age.Engine.Sys4;
using Age.Engine.Vm;
@@ -10,6 +11,18 @@ public class HistoryDataOpsTests
private static Operand G(int address) => new(T_GINT, address);
private static Operand L(int address) => new(T_LINT, address);
private sealed class HistoryVoiceHost : RecordingHost
{
public AdvAutoWaitState AutoState;
public override void WaitForInput(int layoutSlot, Func<bool> serviceInputCallback,
Func<AdvAutoWaitState> autoWaitState)
{
AutoState = autoWaitState();
Waits++;
}
}
[Fact]
public void CopyInlineIntArrayWritesConsecutiveSignedDwords()
{
@@ -161,4 +174,49 @@ public class HistoryDataOpsTests
Assert.False(history.TryFindVoicePair(0, out long voiceId, out long voiceArgument));
Assert.Equal((-1L, -1L), (voiceId, voiceArgument));
}
[Fact]
public void PlayHistoryVoiceUsesNativeVariantAndAutoServices()
{
var history = new AdvTextHistory();
var script = ScriptAssembler.Assemble(Table, "HISTORY_VOICE_REPLAY",
new List<(int, Operand[])>
{
(0x1bd, new[] { I(77) }),
(0x72, new[] { I(1) }),
(0x2, Array.Empty<Operand>()),
}, Array.Empty<string>());
var host = new HistoryVoiceHost();
var vm = new VirtualMachine(script, Table, host, textHistory: history);
vm.Run();
Assert.Equal("exit", vm.HaltReason);
Assert.Equal(new long[] { 77 }, host.Voices);
Assert.Equal(new[] { (77L, 1) }, host.VoiceRequests);
Assert.True(host.AutoState.VoicePending);
var voice = Assert.Single(history.Records);
Assert.Equal(AdvTextHistoryRecordKind.Voice, voice.Kind);
Assert.Equal((77L, 1L), (voice.Value, voice.AuxValue));
}
[Fact]
public void SuppressedHistoryReplayDoesNotRecordItself()
{
var history = new AdvTextHistory();
history.SetRecordingEnabled(false);
var script = ScriptAssembler.Assemble(Table, "HISTORY_VOICE_REPLAY_SUPPRESSED",
new List<(int, Operand[])>
{
(0x1bd, new[] { I(88) }),
(0x2, Array.Empty<Operand>()),
}, Array.Empty<string>());
var host = new RecordingHost();
var vm = new VirtualMachine(script, Table, host, textHistory: history);
vm.Run();
Assert.Equal(new[] { (88L, 1) }, host.VoiceRequests);
Assert.Empty(history.Records);
}
}

View File

@@ -26,6 +26,8 @@ internal class RecordingHost : IHost
public readonly List<AdvWaitIndicatorConfig> WaitIndicators = new();
public readonly List<long> SleptDurations = new();
public readonly List<(long Resource, int Channel)> SfxLoads = new();
public readonly List<long> Voices = new();
public readonly List<(long Id, int PlaybackVariant)> VoiceRequests = new();
public readonly List<int> SfxStarts = new();
public readonly List<int> SfxReleases = new();
public readonly List<(int Target, long Duration)> BgmFades = new();
@@ -101,7 +103,12 @@ internal class RecordingHost : IHost
public void DrawTexture(int slot, int sx, int sy, int w, int h, int dx, int dy) { }
public (int Width, int Height) GetTextureSize(int slot) => (0, 0);
public void PlayBgm(long id) { }
public void PlayVoice(long id) { }
public void PlayVoice(long id) => Voices.Add(id);
public void PlayVoice(long id, int playbackVariant)
{
Voices.Add(id);
VoiceRequests.Add((id, playbackVariant));
}
public void LoadSoundEffect(long resourceId, int channel) => SfxLoads.Add((resourceId, channel));
public void StartSoundEffect(int channel) => SfxStarts.Add(channel);
public void ReleaseSoundEffect(int channel) => SfxReleases.Add(channel);