feat: wire SC0000 anim cluster ops (0x22f/0x229 pos, 0x239/0x231 sheet, 0x232 glow, 0x228/0x23f query)
Coverage 67->74/129; parity held (79/79, sweep 284/13). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,71 @@
|
||||
using System.Collections.Generic;
|
||||
using Age.Engine.Model;
|
||||
using Age.Engine.Sys4;
|
||||
using Age.Engine.Vm;
|
||||
using Xunit;
|
||||
|
||||
public class AnimChannelTests
|
||||
{
|
||||
private static OpcodeTable T() => OpcodeTableJson.Load(Paths.OpcodesJson);
|
||||
private static Operand G(int addr) => new(3, addr);
|
||||
private static (int, Operand[]) Exit() => (0x2, System.Array.Empty<Operand>());
|
||||
|
||||
[Fact]
|
||||
public void Op0x22f_SetsPosition_Op0x228_QueriesItBack()
|
||||
{
|
||||
var t = T();
|
||||
// g1=handle, g3=x=50, g4=y=60, g5=z=0; op 0x22f sets V24; op 0x228 reads it into g11/g12/g13.
|
||||
var scene = ScriptAssembler.Assemble(t, "GFX", new List<(int, Operand[])>
|
||||
{
|
||||
(0x55, new[]{G(1), new Operand(0,0x1000)}), (0x55, new[]{G(2), new Operand(0,0)}),
|
||||
(0x55, new[]{G(3), new Operand(0,50)}), (0x55, new[]{G(4), new Operand(0,60)}), (0x55, new[]{G(5), new Operand(0,0)}),
|
||||
(0x22f, new[]{G(1), G(2), G(3), G(4), G(5)}), // set position
|
||||
(0x228, new[]{G(10), G(1), G(11), G(12), G(13)}), // query position -> g11,g12,g13
|
||||
Exit(),
|
||||
}, System.Array.Empty<string>());
|
||||
var vm = new VirtualMachine(scene, t, new RecordingHost());
|
||||
vm.Run();
|
||||
Assert.Equal(50, vm.Globals[11]);
|
||||
Assert.Equal(60, vm.Globals[12]);
|
||||
Assert.Equal(0, vm.Globals[10]); // success flag
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Op0x232_SetsColorAnim()
|
||||
{
|
||||
var t = T();
|
||||
var scene = ScriptAssembler.Assemble(t, "GFX", new List<(int, Operand[])>
|
||||
{
|
||||
(0x55, new[]{G(1), new Operand(0,0x1000)}), (0x55, new[]{G(2), new Operand(0,1000)}),
|
||||
(0x55, new[]{G(3), new Operand(0,0x80)}), (0x55, new[]{G(4), new Operand(0,0xFF0000)}),
|
||||
(0x232, new[]{G(1), G(2), G(3), G(4)}), Exit(),
|
||||
}, System.Array.Empty<string>());
|
||||
var vm = new VirtualMachine(scene, t, new RecordingHost());
|
||||
vm.Run();
|
||||
var o = vm.Gfx.TryGet(0x1000)!;
|
||||
Assert.True(o.ColorAnim);
|
||||
Assert.Equal(1000, o.ColorPeriod);
|
||||
Assert.Equal(GfxState.PackColor(0x80, 0xFF0000), o.ColorTarget);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Op0x239_SetsSpritesheetGridCell()
|
||||
{
|
||||
var t = T();
|
||||
var scene = ScriptAssembler.Assemble(t, "GFX", new List<(int, Operand[])>
|
||||
{
|
||||
(0x55, new[]{G(1), new Operand(0,0x1000)}), (0x55, new[]{G(2), new Operand(0,0)}), (0x55, new[]{G(3), new Operand(0,0)}),
|
||||
(0x55, new[]{G(4), new Operand(0,4)}), (0x55, new[]{G(5), new Operand(0,1)}), (0x55, new[]{G(6), new Operand(0,2)}),
|
||||
(0x239, new[]{G(1), G(2), G(3), G(4), G(5), G(6)}), Exit(),
|
||||
}, System.Array.Empty<string>());
|
||||
var vm = new VirtualMachine(scene, t, new RecordingHost());
|
||||
vm.Run();
|
||||
var o = vm.Gfx.TryGet(0x1000)!;
|
||||
Assert.True(o.SrcAnim);
|
||||
Assert.Equal(4, o.SrcGridW);
|
||||
Assert.Equal(2, o.SrcCell);
|
||||
}
|
||||
|
||||
private static GfxState VisibleObj(long handle)
|
||||
{
|
||||
var g = new GfxState();
|
||||
|
||||
@@ -255,6 +255,26 @@ public sealed class VirtualMachine
|
||||
Gfx.GetOrCreate(Read(a[0])).V18 = (Read(a[1]), Read(a[2]), Read(a[3])); return pc + 1;
|
||||
case "set-gfx-geom3-b": // 0x219 (handle)(a)(b)(c) -> V24
|
||||
Gfx.GetOrCreate(Read(a[0])).V24 = (Read(a[1]), Read(a[2]), Read(a[3])); return pc + 1;
|
||||
|
||||
// ---- SC0000 anim/transform/spritesheet cluster (docs/engine-re.md §"SC0000 anim ... cluster") ----
|
||||
case "u00421DD0": // 0x22f set-position: (handle)(op2)(x)(y)(z) -> base position (direct set)
|
||||
case "u004219E0": // 0x229 set-position2: same shape, direct position
|
||||
Gfx.GetOrCreate(Read(a[0])).V24 = (Read(a[2]), Read(a[3]), Read(a[4])); return pc + 1;
|
||||
case "u004223C0": // 0x239 spritesheet cell: (handle)(p3)(p4)(gridW)(gridH)(cell) — static cell
|
||||
Gfx.SetSrcRect(Read(a[0]), Read(a[3]), Read(a[4]), Read(a[5]), 0); return pc + 1;
|
||||
case "u00421EA0": // 0x231 anim spritesheet: (handle)(period)(gridW)(gridH) — ping-pong the cell
|
||||
Gfx.SetSrcRect(Read(a[0]), Read(a[2]), Read(a[3]), 0, Read(a[1])); return pc + 1;
|
||||
case "u00421EF0": // 0x232 anim color/glow: (handle)(period)(alpha)(color) — ping-pong the color
|
||||
Gfx.SetColorAnim(Read(a[0]), Read(a[1]), GfxState.PackColor(Read(a[2]), Read(a[3]))); return pc + 1;
|
||||
case "u00421940": // 0x228 query-position: (succ)(handle)(outX)(outY)(outZ) <- current V24
|
||||
{
|
||||
var obj = Gfx.TryGet(Read(a[1]));
|
||||
var v = obj?.V24 ?? default;
|
||||
Write(a[2], v.X); Write(a[3], v.Y); Write(a[4], v.Z);
|
||||
Write(a[0], obj != null ? 0 : 1); return pc + 1;
|
||||
}
|
||||
case "u00422930": // 0x23f query-object: (out)(handle) <- 0 if the object exists, else -1
|
||||
Write(a[0], Gfx.TryGet(Read(a[1])) != null ? 0 : -1); return pc + 1;
|
||||
case "set-gfx-geom3-c": // 0x1ff (handle)(a)(b)(c) -> V16c
|
||||
Gfx.GetOrCreate(Read(a[0])).V16c = (Read(a[1]), Read(a[2]), Read(a[3])); return pc + 1;
|
||||
case "set-gfx-field64": // 0x212 (idx)(val)
|
||||
|
||||
Reference in New Issue
Block a user