Regression coverage for the four Yellow Pallet Town fixes on this
branch:
- tests/parity_J.lua: the old-man-style demo bag shows x1 in Yellow
(SimulatedInputBattleItemList), not just the pre-existing x50
(pokered's OldManItemList) case.
- tests/engine/push_battle_transition.lua: Commands.pushBattle calls
ctx.overworld:pushBattle when available and falls back with a
logged warning otherwise. Logger.warn is spied (pcall-safe, always
restored) rather than read off the shared Logger.history ring
buffer, so the fallback checks don't leave noise behind for
whatever else runs in the same process.
- tests/parity_yellow_pallet_pikachu.lua: drives the real onStep
closure through the real StateStack/OverworldState, with no mocked
battle -- Red never plays Music_MuseumGuy for this escort (Blue
shares the same code path: onStep only branches on
GameVersion.isYellow(), never isBlue(), so a separate Blue run
would exercise nothing new), and Yellow's hold before the Pikachu
battle is armed for exactly 2 frames before handing off to
BattleTransition rather than a bare stack push. Stops there rather
than also driving the demo battle to completion just to assert
Music_MuseumGuy fires in Yellow (that fix's own coverage): the
extra coupling to unrelated battle menu/bag/throw frame budgets
wasn't worth it for one more assertion. That side stays manually
verified. scenario() restores Game/GameVersion and re-inits
StateStack on the way out.
All three pass standalone (luajit tests/<path>). The Yellow E2E test
hits the same pre-existing "Music.playMap is nil" gap three other
map-warping parity tests already hit inside the aggregated
tests/run_tests.lua run (missing data/generated/audio.lua in this dev
environment) -- confirmed by diffing the identical error text against
parity_warp_after_warp_step.lua, which also passes clean standalone.
GameSpeed is a single fast-forward multiplier applied uniformly to the
whole logic clock -- overworld walking, menu navigation and battle turns
all scale together. A player who wants 4X battles but 1X overworld (so a
cutscene or NPC dialogue doesn't blur past) has no way to get both.
Splits save.options.speed into speedOverworld/speedBattle/speedMenu, each
cycling independently, with an automatic migration so an existing save's
speed choice carries over. Game.speedCategoryInStack resolves which
category is active by walking the state stack (the same idiom
wideBattleInStack/fillScaleInStack already use), so a menu opened mid-
battle inherits battle speed rather than resetting to whatever "menu"
defaults to. Adds a new core.logic_speed hook so a mod can read or
override the resolved multiplier for the current frame regardless of
which category produced it, sitting after the link-play and run-argument
overrides so neither is a seam a mod can defeat.
RFC 0007 status: Proposed.