Files
gen1recomp/tests/engine/game3_player_reset_test.lua
T
Shane McGovern 2c356f28ea fix(game3): save, item, map, script and importer bugs found in review
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.
2026-09-22 03:28:39 +01:00

52 lines
2.1 KiB
Lua

-- Player.reset must apply the state it is asked to reset to.
--
-- A1 regression: `reset(x, y, facing)` never assigned Player.facing, so every
-- non-seamless Map.load / warp / fly / syncFromSession left the avatar facing
-- whatever direction the previous map ended on -- and `Player.syncSavePosition`
-- then wrote that stale facing back into the save.
--
-- (N-A2, the transient surf flags, is covered by the same suite below.)
-- luajit tests/engine/game3_player_reset_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 Player = require("src.core.game3.player")
-- A1: the facing argument is applied.
Player.facing = "down"
Player.reset(4, 5, "up")
eq(Player.facing, "up", "Player.reset applies its facing argument")
-- An invalid direction must not corrupt the facing.
Player.facing = "left"
Player.reset(4, 5, "sideways")
eq(Player.facing, "left", "an invalid facing argument leaves the facing unchanged")
-- A nil argument keeps the current facing (reset(x, y) callers).
Player.facing = "right"
Player.reset(4, 5)
eq(Player.facing, "right", "a nil facing argument keeps the current facing")
-- N-A2: transient surf state must not survive a reset. A warp or whiteout while
-- surfing otherwise leaves Player.surfing set, and Collision.canEnter then
-- treats water as walkable on land maps and reads every step as a dismount.
Player.surfing, Player.surfHopping, Player.dismounting = true, true, true
Player.reset(4, 5, "down")
check(not Player.surfing, "Player.reset clears surfing")
check(not Player.surfHopping, "Player.reset clears surfHopping")
check(not Player.dismounting, "Player.reset clears dismounting")
-- The ordinary movement state reset is unchanged.
Player.biking, Player.running, Player.jumping, Player.moving = true, true, true, true
Player.reset(6, 7, "left")
check(not Player.biking, "bike state is still cleared")
check(not Player.running, "run state is still cleared")
check(not Player.jumping, "jump state is still cleared")
check(not Player.moving, "movement is still cleared")
T.finish("game3_player_reset_test")