Fix FIELD minimap camera pan
This commit is contained in:
@@ -20,8 +20,7 @@ public class AnimChannelTests
|
||||
{
|
||||
(0x55, new[]{G(1), I(0xcf3a)}), (0x55, new[]{G(2), I(0)}),
|
||||
(0x55, new[]{G(3), I(360)}), (0x55, new[]{G(4), I(20)}), (0x55, new[]{G(5), I(0)}),
|
||||
(0x1fb, new[]{G(1), I(0), I(0), I(0), I(1), I(1), I(0), I(0)}),
|
||||
(0x22f, new[]{G(1), G(2), G(3), G(4), G(5)}),
|
||||
(0x1fb, new[]{G(1), I(0), I(0), I(0), I(1), I(1), G(3), G(4)}),
|
||||
(0x55, new[]{G(6), I(300)}), (0x55, new[]{G(7), I(40)}),
|
||||
(0x55, new[]{G(8), I(20)}), (0x51, new[]{G(8), I(0), G(8)}),
|
||||
(0x220, new[]{G(1), G(2), G(6), G(7), G(8), G(5)}),
|
||||
@@ -63,8 +62,7 @@ public class AnimChannelTests
|
||||
(0x55, new[]{G(4), I(360)}), (0x55, new[]{G(5), I(20)}), (0x55, new[]{G(6), I(0)}),
|
||||
(0x55, new[]{G(40), I(20)}), (0x51, new[]{G(40), I(0), G(40)}),
|
||||
(0x55, new[]{G(41), I(60)}), (0x51, new[]{G(41), I(0), G(41)}),
|
||||
(0x1fb, new[]{G(1), I(0), I(0), I(0), I(1), I(1), I(0), I(0)}),
|
||||
(0x22f, new[]{G(1), G(2), G(4), G(5), G(6)}),
|
||||
(0x1fb, new[]{G(1), I(0), I(0), I(0), I(1), I(1), G(4), G(5)}),
|
||||
|
||||
(0x228, new[]{G(10), G(1), G(11), G(12), G(13)}),
|
||||
(0x50, new[]{G(11), G(11), I(40)}), (0x50, new[]{G(12), G(12), G(40)}),
|
||||
|
||||
@@ -51,6 +51,41 @@ public class GfxRangeTransformTests
|
||||
Assert.False(gfx.HasActiveTimedPresentation(1300));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Opcode22fPansTheSelectedRangeInSyncWithAnOrdinaryObjectTween()
|
||||
{
|
||||
var table = OpcodeTableJson.Load(Paths.OpcodesJson);
|
||||
var script = ScriptAssembler.Assemble(table, "RANGE_PAN", new List<(int, Operand[])>
|
||||
{
|
||||
(0x229, new[] { I(1), I(1), I(500), I(350), I(0) }),
|
||||
(0x22c, new[] { I(100), I(50), I(0) }),
|
||||
(0x22f, new[] { I(0), I(300), I(300), I(150), I(0) }),
|
||||
(0x220, new[] { I(50001), I(0), I(300), I(100), I(50), I(0) }),
|
||||
(0x2, System.Array.Empty<Operand>()),
|
||||
}, System.Array.Empty<string>());
|
||||
var vm = new VirtualMachine(script, table, new RecordingHost());
|
||||
|
||||
vm.Gfx.SetSurface(1, 1, -1);
|
||||
vm.Gfx.BindDraw(1, 1, 0, 0, 1, 1, 500, 350);
|
||||
vm.Gfx.BindDraw(50001, 1, 0, 0, 1, 1, 0, 0);
|
||||
vm.Run();
|
||||
vm.Gfx.SnapshotVisibleObjects(1000); // seed the shared one-shot start
|
||||
var halfway = vm.Gfx.SnapshotVisibleObjects(1150);
|
||||
var map = halfway.Single(x => x.Handle == 1);
|
||||
var marker = halfway.Single(x => x.Handle == 50001);
|
||||
var mapPoint = Transform2DMath.Build(map.Transform).FromLocalOrigin(map.DstX, map.DstY)
|
||||
.Then(map.RangeTransform!.Value).Apply(0, 0);
|
||||
var markerPoint = Transform2DMath.Build(marker.Transform)
|
||||
.FromLocalOrigin(marker.DstX, marker.DstY).Apply(0, 0);
|
||||
|
||||
Assert.Equal((700.0, 450.0), mapPoint);
|
||||
Assert.Equal((50.0, 25.0), markerPoint);
|
||||
Assert.Null(vm.Gfx.TryGet(0));
|
||||
Assert.True(vm.Gfx.HasActiveTimedPresentation(1150));
|
||||
vm.Gfx.SnapshotVisibleObjects(1300);
|
||||
Assert.False(vm.Gfx.HasActiveTimedPresentation(1300));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Opcode229SelectsRangeWithoutCreatingAnOrdinaryObject()
|
||||
{
|
||||
|
||||
@@ -182,6 +182,23 @@ public sealed partial class GfxState
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Op 0x22f: arm the selected retained-gfx range transform's delayed one-shot
|
||||
/// translation target. FIELD uses this channel to pan the world while its ordinary minimap object
|
||||
/// runs a matching op-0x220 translation.</summary>
|
||||
public void SetRangeTranslationChannel(long delayMs, long durationMs,
|
||||
(long X, long Y, long Z) target)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_rangeTransform.TranslationDelayMs = delayMs;
|
||||
_rangeTransform.TranslationDurationMs = durationMs;
|
||||
_rangeTransform.TranslationTarget = target;
|
||||
_rangeTransform.TranslationEnabled = durationMs > 0;
|
||||
_rangeTransform.OneShotStartMs = -1;
|
||||
MarkRetainedMutation();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Op 0x21d: clone the native 0x2d4-byte retained-object record from source to destination.</summary>
|
||||
public bool CloneObject(long sourceHandle, long destinationHandle)
|
||||
{
|
||||
|
||||
@@ -39,8 +39,10 @@ public sealed partial class VirtualMachine
|
||||
Gfx.SetDefaultObjectSlot((int)Read(a[0])); 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)
|
||||
Gfx.SetObjectPosition(Read(a[0]), (Read(a[2]), Read(a[3]), Read(a[4]))); return pc + 1;
|
||||
case "u00421DD0": // pre-reference compatibility
|
||||
case "set-gfx-range-translation-target": // 0x22f (delay)(duration)(x)(y)(z)
|
||||
Gfx.SetRangeTranslationChannel(Read(a[0]), Read(a[1]),
|
||||
(Read(a[2]), Read(a[3]), Read(a[4]))); return pc + 1;
|
||||
case "u004219E0": // pre-reference compatibility
|
||||
case "set-gfx-range-transform": // 0x229 (first)(count)(anchor x/y/z)
|
||||
Gfx.SetRangeTransform(Read(a[0]), Read(a[1]), (Read(a[2]), Read(a[3]), Read(a[4])));
|
||||
|
||||
@@ -1528,7 +1528,8 @@ public sealed partial class VirtualMachine
|
||||
return StepRetainedObject(label, a, pc);
|
||||
|
||||
// ---- 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 "u00421DD0": // pre-reference compatibility
|
||||
case "set-gfx-range-translation-target": // 0x22f (delay)(duration)(x)(y)(z)
|
||||
case "u004219E0": // pre-reference compatibility
|
||||
case "set-gfx-range-transform": // 0x229 (first)(count)(anchor x/y/z)
|
||||
case "u00421A90": // pre-reference compatibility
|
||||
|
||||
Reference in New Issue
Block a user