mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-28 23:00:21 -04:00
41935aa2a2
Second batch of the Gen 3 review work: the review lanes closed their queues and the test gate grew with them. Review census: 139 routed findings -- 118 fixed, 14 invalid (the report had Gen 4+ semantics in more than one place), 6 struck as stale after re-verification, 1 re-routed. Every fix carries its own pret citation in docs/game3/review-v3-triage.md; the E10 opcode closure is itemised in docs/game3/e10-opcode-spec.md (18 ops wired, 2 reclassified to the seam class). Representative ROM-grounded changes: - The POKéMON start-menu entry is now gated on FLAG_SYS_POKEMON_GET the way retail does it (pokefirered/src/start_menu.c:217-218, flag 0x828). - Money ops read their amount raw and gate the change on the disable byte (pokefirered/src/scrcmd.c:1798-1830, pokefirered/asm/macros/event.inc:1166-1186); random and the warp family VarGet theirs (pokefirered/src/scrcmd.c:455-461, :719-731). - The HM table matches FRLG: there is no Whirlpool HM (pokefirered/include/constants/items.h:411-418). - The day-care party-full guard follows src/daycare.c:525, :1081. - Knock Off keeps its battle-scoped send-out mask (pokefirered/src/battle_script_commands.c:2730-2752, :4489), carried from the first batch. Structural work: the I6/I9/J1 architecture items landed as seams (profile selector, capability flags, font provider, virtual-object layer), the adopted footprint register keeps a KEEP verdict, the quantizer target is met, and the 30 drain items plus carves 1-4 are folded in. Tests: T6 now runs 282 top-level suites (273 + 9 new), the re-sweep ends at 267 pass / 0 fail, the engine tier is 634 suites, modkit 37, and the full gate ran green twice with T3 active on an imported Red cache. Documented skips are the lua5.4 oversize-save oracle where lua5.4 is absent and the config-partials listed in docs/game3/game3-artifact-conversions-v3.md. Docs shipped: review-v3-triage.md, e10-opcode-spec.md, rse-seams.md, game3-suite-sweep-v113.md, game3-artifact-conversions-v3.md, test-baseline-v3.md (plus the first-batch docs already on the branch).
145 lines
6.2 KiB
Lua
145 lines
6.2 KiB
Lua
-- tests/game3_object_subpriority_draworder_test.lua
|
|
-- Seam 7 consumer-half contract (docs/game3/e10-opcode-spec.md §5.8):
|
|
-- 1. set -> Objects.setSubpriority stores {fixedPriority, subpriority}; the
|
|
-- script op applies the bias (prett scrcmd.c:1130 `priority + 83`).
|
|
-- 2. draw -> field_view.applyDrawOrder captures the dynamic class once
|
|
-- (fixedClass), keeps it across elevation changes, and sorts the frozen
|
|
-- actor by subpriority instead of pixel-Y.
|
|
-- 3. reset-> the record clears, no stale fixedClass survives, and the
|
|
-- elevation-driven dynamic path resumes exactly as before.
|
|
-- 4. an unfrozen neighbour still follows ELEVATION_TO_PRIORITY.
|
|
--
|
|
-- pret anchors (clone /Users/shanemcgovern/dev/pokefirered, HEAD c75f35230):
|
|
-- src/event_object_movement.c:8379-8387 UpdateObjectEventElevationAndPriority
|
|
-- -> `if (objEvent->fixedPriority) return;`
|
|
-- src/event_object_movement.c:8424-8429 ObjectEventUpdateSubpriority
|
|
-- -> same early return (gates SetObjectSubpriorityByElevation :8414-8422)
|
|
-- src/event_object_movement.c:2089-2101 SetObjectSubpriority
|
|
-- -> `fixedPriority = TRUE; sprite->subpriority = subpriority`
|
|
-- src/event_object_movement.c:2104-2116 ResetObjectSubpriority
|
|
-- -> `fixedPriority = FALSE` (re-enables the dynamic path; does not restore)
|
|
-- src/scrcmd.c:1122-1140 set/resetobjectsubpriority (`priority + 83`).
|
|
|
|
local Objects = require("src.core.game3.objects")
|
|
local FieldView = require("src.core.game3.field_view")
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local function done()
|
|
if failed > 0 then
|
|
print("[test] FAILED " .. failed)
|
|
os.exit(1)
|
|
end
|
|
print("[test] all passed")
|
|
os.exit(0)
|
|
end
|
|
|
|
-- Current-map live EventObject in the store the producer resolves from.
|
|
local eo = {
|
|
localId = 3,
|
|
def = { x = 4, y = 4, elevation = 0 },
|
|
cellX = 4, cellY = 4, px = 4 * 16, py = 4 * 16,
|
|
elevation = 0, -- class 2 (ground) per ELEVATION_TO_PRIORITY[0]
|
|
}
|
|
Objects._byId[3] = eo
|
|
|
|
local function makeActor(e)
|
|
return {
|
|
kind = "npc",
|
|
i = e.localId,
|
|
obj = e.def,
|
|
eventObject = e,
|
|
elevation = e.elevation,
|
|
x = e.px or 0, y = e.py or 0,
|
|
sortY = e.py or 0,
|
|
}
|
|
end
|
|
|
|
print("[test] 1. baseline: no freeze -> dynamic class, no capture")
|
|
do
|
|
local under, over = FieldView.applyDrawOrder({ makeActor(eo) })
|
|
check(#over == 0 and #under == 1, "elevation 0 lands in the under list")
|
|
check(under[1].priority == 2, "dynamic class 2 from ELEVATION_TO_PRIORITY[0]")
|
|
check(under[1].subpriority == nil, "no subpriority on an unfrozen actor")
|
|
check(eo.fixedClass == nil, "no capture before any freeze is set")
|
|
end
|
|
|
|
print("[test] 2. set stores the record with the +83 script bias")
|
|
do
|
|
local scriptPriority = 0 -- script byte; pret adds 83 in scrcmd.c:1130
|
|
local ok = Objects.setSubpriority(3, nil, nil, scriptPriority + 83)
|
|
check(ok == true, "setSubpriority resolves the current-map object")
|
|
check(eo.fixedPriority == true, "fixedPriority flag set")
|
|
check(eo.subpriority == 83, "subpriority carries the +83 bias (0 + 83)")
|
|
end
|
|
|
|
print("[test] 3. set -> draw freezes the class at first observation")
|
|
do
|
|
local under = FieldView.applyDrawOrder({ makeActor(eo) })
|
|
check(eo.fixedClass == 2, "fixedClass captured on first observation (class 2)")
|
|
check(under[1].priority == 2, "frozen priority = fixedClass")
|
|
check(under[1].subpriority == 83, "+83 bias survives the round trip as the sort key")
|
|
end
|
|
|
|
print("[test] 4. freeze holds across an elevation change (pret early-return)")
|
|
do
|
|
eo.elevation = 13 -- would be class 0 if the dynamic writer ran
|
|
local under, over = FieldView.applyDrawOrder({ makeActor(eo) })
|
|
check(under[1].priority == 2, "priority stays at fixedClass (2), not ELEVATION_TO_PRIORITY[13]=0")
|
|
check(eo.fixedClass == 2, "fixedClass captured once, not re-derived")
|
|
check(#over == 0, "frozen actor does not move to the over list")
|
|
end
|
|
|
|
print("[test] 5. frozen actor sorts by subpriority; neighbour keeps pixel-Y")
|
|
do
|
|
local neighbour = {
|
|
kind = "npc", i = 9, obj = { elevation = 3 }, elevation = 3,
|
|
x = 16, y = 100, sortY = 100, -- pixel-Y 100 > subpriority 83
|
|
}
|
|
local under = FieldView.applyDrawOrder({ neighbour, makeActor(eo) })
|
|
check(#under == 2, "both actors share the under list")
|
|
check(under[1].eventObject == eo, "frozen actor (83) sorts before the neighbour (sortY 100)")
|
|
check(under[2].priority == 2, "unfrozen neighbour still follows ELEVATION_TO_PRIORITY[3]=2")
|
|
check(under[2].subpriority == nil, "unfrozen neighbour keeps the pixel-Y key")
|
|
|
|
local near = {
|
|
kind = "npc", i = 8, obj = { elevation = 3 }, elevation = 3,
|
|
x = 32, y = 10, sortY = 10, -- pixel-Y 10 < subpriority 83
|
|
}
|
|
local under2 = FieldView.applyDrawOrder({ near, makeActor(eo) })
|
|
check(under2[1] == near, "pixel-Y 10 still sorts before subpriority 83")
|
|
check(under2[2].eventObject == eo, "frozen actor falls behind the nearer neighbour")
|
|
end
|
|
|
|
print("[test] 6. reset resumes the dynamic path with no stale capture")
|
|
do
|
|
local ok = Objects.resetSubpriority(3, nil, nil)
|
|
check(ok == true, "resetSubpriority resolves the current-map object")
|
|
check(eo.fixedPriority == nil and eo.subpriority == nil,
|
|
"reset clears the record (pret ResetObjectSubpriority does not restore)")
|
|
eo.elevation = 13
|
|
local under, over = FieldView.applyDrawOrder({ makeActor(eo) })
|
|
check(#over == 1 and #under == 0, "dynamic path resumed: class 0 -> over list")
|
|
check(over[1].priority == 0, "priority follows ELEVATION_TO_PRIORITY[13] = 0 again")
|
|
check(over[1].subpriority == nil, "sort key back to pixel-Y")
|
|
check(eo.fixedClass == nil, "no stale fixedClass survives the reset")
|
|
|
|
-- a later re-freeze must re-capture from the current elevation, not the old one
|
|
Objects.setSubpriority(3, nil, nil, 5 + 83)
|
|
local under2, over2 = FieldView.applyDrawOrder({ makeActor(eo) })
|
|
check(#under2 == 0, "fresh capture at class 0 keeps the actor out of the under list")
|
|
check(eo.fixedClass == 0, "re-freeze re-captures at the current class (0 at elevation 13)")
|
|
check(over2[1] ~= nil and over2[1].priority == 0, "re-frozen priority uses the fresh capture")
|
|
check(over2[1].subpriority == 88, "new bias (5 + 83) replaces the old sort key")
|
|
end
|
|
|
|
done()
|