Implement ROOM fades and character voices
This commit is contained in:
@@ -77,6 +77,9 @@ public interface IHost
|
||||
// read/message-skip branch reaches op 0x20c and presents the completed endpoint immediately.
|
||||
void WaitForForegroundTransition(GfxState gfx) { }
|
||||
void PresentFrame(GfxState gfx) { }
|
||||
// Legacy SYS4 screen-transition family (op 0x25): scripts render two complete frames into
|
||||
// numbered surfaces, then block while the engine alpha-composites target over source.
|
||||
void CrossfadeSurfaces(GfxState gfx, int sourceSurface, int targetSurface, long intervalArgument) { }
|
||||
void CreateTexture(int slot, int width, int height);
|
||||
void SetTexture(long resourceId, int slot);
|
||||
void ReleaseSurface(int slot) { }
|
||||
|
||||
13
engine/Age.Engine/Model/LegacyScreenTransitionTiming.cs
Normal file
13
engine/Age.Engine/Model/LegacyScreenTransitionTiming.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Age.Engine.Model;
|
||||
|
||||
/// <summary>Native timing conversion shared by the legacy op-0x25 screen-transition family.</summary>
|
||||
public static class LegacyScreenTransitionTiming
|
||||
{
|
||||
public static long DurationMilliseconds(long argument)
|
||||
{
|
||||
long interval = argument <= 64 ? argument : argument / 16;
|
||||
long step = argument <= 64 ? 16 : 1;
|
||||
interval = System.Math.Max(1, interval);
|
||||
return System.Math.Clamp(((256 + step - 1) / step) * interval, 1, 60_000);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,14 @@ public sealed class ResourceMap
|
||||
entry.Name.EndsWith(".AGF", StringComparison.OrdinalIgnoreCase) ? entry : null;
|
||||
}
|
||||
|
||||
/// <summary>Resolve voice audio through the active SC section when one exists, then through the
|
||||
/// universal raw catalog used by non-SC frontend scripts such as ROOM.</summary>
|
||||
public AssetEntry? ResolveVoice(string scene, long resId)
|
||||
{
|
||||
var entry = _catalog.ResolveScene(scene, resId) ?? _catalog.ResolveRaw(resId);
|
||||
return entry is { IsPlaceholder: false } && IsAudio(entry) ? entry : null;
|
||||
}
|
||||
|
||||
/// <summary>Resolve an already-normalized raw catalog id without applying a scene section base.</summary>
|
||||
public AssetEntry? ResolveRawTexture(long rawId)
|
||||
{
|
||||
|
||||
@@ -649,7 +649,26 @@ public sealed class VirtualMachine
|
||||
Write(a[0], Read(a[0]) & ~(1L << (int)bit)); return pc + 1;
|
||||
}
|
||||
case "check-bit": Write(a[0], (Read(a[1]) >> (int)(Read(a[2]) & 31)) & 1); return pc + 1;
|
||||
case "copy-to-global": Write(a[0], Read(a[1])); return pc + 1;
|
||||
case "zero-int-range":
|
||||
case "copy-to-global": // pre-reference compatibility for opcode 0x6c
|
||||
{
|
||||
int count = System.Math.Max(0, checked((int)Read(a[1])));
|
||||
for (int i = 0; i < count; i++) WriteConsecutive(a[0], i, 0);
|
||||
return pc + 1;
|
||||
}
|
||||
case "random-modulo": // 0x60: native CRT rand() % bound
|
||||
case "u0041A270":
|
||||
{
|
||||
long bound = Read(a[1]);
|
||||
if (bound == 0)
|
||||
{
|
||||
Write(a[0], 0);
|
||||
HaltReason ??= "random-modulo-zero";
|
||||
return HALT;
|
||||
}
|
||||
Write(a[0], System.Random.Shared.Next(0x8000) % bound);
|
||||
return pc + 1;
|
||||
}
|
||||
case "jmp": return _cur.Script.IndexByOffset.GetValueOrDefault((int)a[0].Value, pc + 1);
|
||||
case "call": _cur.CallStack.Add(pc + 1); return _cur.Script.IndexByOffset.GetValueOrDefault((int)a[0].Value, pc + 1);
|
||||
case "ret":
|
||||
@@ -1301,6 +1320,10 @@ public sealed class VirtualMachine
|
||||
Read(a[4]), (int)Read(a[5]), Read(a[6]), Read(a[7])); return pc + 1;
|
||||
case "present-frame": // 0x20c: read/message-skip path snaps a queued transition to its endpoint
|
||||
_host.PresentFrame(Gfx); return pc + 1;
|
||||
case "crossfade-surfaces": // 0x25: legacy full-frame surface alpha transition
|
||||
case "u00418B40":
|
||||
_host.CrossfadeSurfaces(Gfx, (int)Read(a[0]), (int)Read(a[1]), Read(a[2]));
|
||||
return pc + 1;
|
||||
case "mark-frame-yield": // 0x21c: normal foreground-transition scheduler/resume boundary
|
||||
_host.WaitForForegroundTransition(Gfx); return pc + 1;
|
||||
case "clear-gfx-command-queue": // 0x224: retained compositor does not use this native queue
|
||||
|
||||
Reference in New Issue
Block a user