mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
2c356f28ea
The rest of the Gen 3 review fixes, each with a gated suite in tests/engine/.
ROM semantics were checked against pret/pokefirered.
Scripts
- givemon carried the wrong operand layout, found earlier; four more layout
desyncs came out of pret asm/macros/event.inc: comparestat is {byte,word},
and setptr / loadbytefromptr / setptrbyte each carry a leading byte plus a
word. A wrong size mis-decodes every instruction after the bad one, so
Versions.CACHE_VERSION moves to 113 and existing caches re-import.
- handlers for previously handler-less verbs: comparestat,
bufferitemnameplural, setmonmove, setmonmetlocation, the modern
fateful-encounter pair, the script-locals family (copylocal, setptr,
loadbytefromptr, setptrbyte, copybyte, compare_local_to_* and
compare_ptr_to_*), the RAM-script family (setvaddress, vgoto, vcall,
vgoto_if, vcall_if, vmessage, vbuffermessage, vbufferstring, endram,
returnram) and the same-map forms of the *at verbs.
- setdooropen / setdoorclosed read their coordinates through VarGet.
Battles
- Knock Off and Thief / Trick persist the item change instead of only
touching the in-battle copy.
- knocked-off party slots are tracked in a bitmask, so a slot reused later
does not inherit the flag.
Field and UI
- Player.reset restores facing and clears the surf flags.
- a definition-less Map.load no longer leaves collision unbound.
- an unresolved region-map section no longer reports PALLET TOWN.
- the naming screen splits input from the timer, so update(dt) stops
indexing a number.
- the hall of fame commits through the engine save path and serializes its
fields.
Persistence
- gameStats, the link-battle records and the trainer card are serialized.
- the PC deposit refuses at the 999 cap instead of destroying the overflow.
Robustness
- Data.load runs cached modules sandboxed.
- the file browser quotes shell arguments.
- .meta dimensions are bounds-checked and mids.idx validates its header.
46 lines
2.1 KiB
Lua
46 lines
2.1 KiB
Lua
-- Game stats must survive a save/load round trip.
|
|
--
|
|
-- Regression: `session.gameStats` is written by five subsystems -- slot-machine
|
|
-- jackpots (slot_machine.lua), hatched eggs (step_events.lua), link W/L/D
|
|
-- (link/battle.lua), link trades (link/trade.lua) and the sticker-man brags that
|
|
-- read them (natives_events.lua) -- but Schema.toSaveTable never emitted it and
|
|
-- fromSaveTable never restored it, so every counter reset on Continue.
|
|
--
|
|
-- The change is additive: a save without the key loads as an empty table, so the
|
|
-- rollback is dropping the key (the counters are then lost, as they are today).
|
|
-- luajit tests/engine/game3_gamestats_persistence_test.lua
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local T = require("tests.harness")
|
|
local check, eq = T.check, T.eq
|
|
love = love or require("tests.love_stub")
|
|
|
|
local Schema = require("src.core.game3.save_schema_firered")
|
|
|
|
local session = Schema.newGame({ name = "RED" })
|
|
session.gameStats = { [13] = 4, [7] = 100, linkBattleWins = 3, linkBattleLosses = 2 }
|
|
|
|
local save = Schema.toSaveTable(session)
|
|
check(type(save.gameStats) == "table", "toSaveTable writes gameStats")
|
|
local written = type(save.gameStats) == "table" and save.gameStats or {}
|
|
eq(written[13], 4, "the hatched-egg counter is written")
|
|
eq(written[7], 100, "a numeric game-stat id is written")
|
|
eq(written.linkBattleWins, 3, "the link battle win count is written")
|
|
|
|
local restored = Schema.fromSaveTable(save)
|
|
check(type(restored.gameStats) == "table", "fromSaveTable restores gameStats")
|
|
local back = type(restored.gameStats) == "table" and restored.gameStats or {}
|
|
eq(back[13], 4, "the hatched-egg counter round-trips")
|
|
eq(back[7], 100, "a numeric game-stat id round-trips")
|
|
eq(back.linkBattleWins, 3, "named keys round-trip")
|
|
eq(back.linkBattleLosses, 2, "...for every recorded outcome")
|
|
|
|
-- An older save has no gameStats key: it must load with an empty table, and the
|
|
-- writers' own `if type(session.gameStats) ~= "table"` guards stay satisfied.
|
|
save.gameStats = nil
|
|
local old = Schema.fromSaveTable(save)
|
|
check(type(old.gameStats) == "table", "a save without gameStats loads with an empty table")
|
|
|
|
T.finish("game3_gamestats_persistence_test")
|