story2.lua pushed the demo battle straight onto the stack, skipping
the flash + wipe that every other wild battle gets.
InitWildBattle calls DoBattleTransitionAndInitBattleVariables
unconditionally (core.asm:6699) -- there is no BATTLE_TYPE_OLD_MAN or
BATTLE_TYPE_PIKACHU special case -- so the old-man tutorial and Oak's
Pikachu catch get the wipe like any other wild battle, same as every
scripted trainer. Commands.old_man_demo already routed the Viridian
old man's tutorial catch through OverworldState:pushBattle for
exactly this reason; the fallback it used for a pushBattle-less
overworld (ctx.overworld and ctx.overworld.pushBattle then ... else
game.stack:push(battle)) was duplicated verbatim in Commands
.start_battle and would have been a third copy in story2.lua, so it's
pulled into one Commands.pushBattle(ctx, battle) helper instead, used
by all three call sites; the fallback branch now logs a warning
rather than silently dropping the transition and battle-theme start.
oak.facing was set and the battle pushed in the same synchronous
callback, so the overworld never rendered a frame of Oak already
turned toward the grass before the screen cut to battle.
Traced home/overworld.asm: PalletTownOakGreetsPlayerScript (the turn)
and PalletTownPikachuBattleScript (arming wCurOpponent) are separate
script ticks, one main-loop iteration apart. OverworldLoopLessDelay
burns two DelayFrame calls per iteration, calls RunMapScript (via
JoypadOverworld) first, and only then checks wCurOpponent to jump
into the battle -- so the turn from iteration A is on screen for the
two DelayFrame calls that open iteration B, before that same
iteration's RunMapScript arms wCurOpponent and falls straight into
the battle check. hold(2, ...) restores exactly that beat.
Yellow's Pallet Town intro (professor catches the wild Pikachu, then
walks the player to the lab) played the map's default Pallet Town
theme the whole time instead of the dedicated escort cue. Per
pokeyellow's actual scripts: PlayDefaultMusicFadeOutCurrent (run on
every battle exit) legitimately restores Pallet Town's theme after
the Pikachu demo battle for the Whew.../Come with me lines; the
escort cue (MUSIC_MUSEUM_GUY, the same "led by an NPC" theme Pewter's
museum guide uses) only starts in PalletMovementScript_OakMoveLeft,
the first function of the escort script -- but only in pokeyellow's
copy. pokered's copy of that same shared Red/Yellow function only
sets BIT_NO_MAP_MUSIC and leaves whatever was already playing
(MUSIC_MEET_PROF_OAK) running uninterrupted into the lab.
Start Music_MuseumGuy at the top of escortToLab, gated on Yellow so
Red/Blue keeps its unchanged behavior, and fix the Oak-escort warp's
keepMusic comment to say which song rides the warp in each version.
The originals run GiveItem before printing the received texts, and when
the bag can't hold the TM they print a make-room line instead and leave
EVENT_GOT_TM* unset, so talking to the leader again retries the give.
The victory reward path added the TM straight into the inventory, so a
full bag went to 21/20.
Route the gym TM give through Bag.add, split the TM lines out of the
victory dialogue table into tmPre/tmDialogue/noRoom, and port the
beaten-leader middle branch that re-runs the ReceiveTM script. Saves
that already hold the TM without the flag count as received so they
don't collect a second copy.
Refs #797
The Elite Four champion script showed the rival's intro text and then
jumped straight into the battle; the wipe-time playBattle('final')
started Music_FinalBattle only when the battle began. The original
(ChampionsRoomRivalReadyToBattleScript) plays MUSIC_FINAL_BATTLE right
after the dialogue ends, before the battle.
Add a play_music Music_FinalBattle row between the intro text and the
battle, and bump the two past-the-end jump targets 25 -> 26 for the new
row count. pushBattle's wipe-time playBattle('final') no-ops on the
already-playing song, so the theme stays continuous into the fight.
Fixes#706
Issue #695: Pressing B in PC submenus (BoxMenu, PlayerPC) was exiting
the entire PC session instead of returning to the main PC menu. The
three main-menu items (Bill's PC, player's PC, Prof. Oak's PC) were
missing keepOpen=true, so selecting one popped the main menu off the
stack. Added keepOpen to all three, matching the pattern already used
by BoxMenu and PlayerPC's own rows.
Issue #694: Falling through boulder holes in Seafoam Islands, Victory
Road, and Pokemon Mansion played no sound effect. Added Faint_Fall sfx
before every hole warp -- the scripted onStep holes in seafoam.lua,
story.lua, and story6.lua, plus the warp-tile-based hole detection in
OverworldController takeWarp. Faint_Fall is the companion to Faint_Thud
(already played when boulders fall into holes).
Fixes#695Fixes#694
The parcel scene in Oak's Lab plays Music_MeetRival on both the rival's
arrival and departure (lines 144-146 in oaks_lab.lua), but the post-battle
onStep exit sequence only played the fanfare when the rival approached
(fixed in #596). It was missing when the rival walks out after the battle.
Add stop_music + play_music Music_MeetRival before the rival's exit
walk-out in both oaks_lab.lua and oaks_lab_yellow.lua, matching the
parcel scene's double-fanfare pattern from the original ROM.
Fixes#683
The starter balls' scripts showed the received-mon text but never played
the sound_get_key_item fanfare that the text carries in the original
(scripts/OaksLab.asm OaksLabReceivedMonText / OaksLabRivalReceivedMonText).
Add play_sound Get_Key_Item before each received text, mirroring the
Yellow starter port.
WardensHouseWardenText prints Gibberish1, calls YesNoChoice, and answers
with Gibberish2 on yes / Gibberish3 on no (scripts/WardensHouse.asm). The
port printed the question and ended the script. Both reply strings were
already extracted and unused, so this is script wiring only.
The branch targets become labels: they were hand-numbered absolute rows,
already mis-pointed once (#535), and any insert meant renumbering jumps
that had no way to announce they were stale.
Also fixes the parity suite's show_text instrumentation, which stopped
forwarding arguments at `subs` and so dropped the extraOpts carrying
Commands.ask's choice callback -- silently turning every ask under test
back into a plain show_text.
The Yellow port (oaks_lab_yellow.lua) already swaps in Music_MeetRival
for the "Hey wait! Let's check out our Pokemon!" challenge and restores
Music_OaksLab once the rival walks out, but the Red/Blue script never
did, leaving the lab battle silent before and after the fight.
After the player picks a starter and the rival takes his, every ball on
the lab table fell through to 'Those are POKé BALLs' instead of the
leftover-mon line. Port the pokered OaksLabSelectedPokeBallScript ->
OaksLabLastMonScript beat: with EVENT_GOT_STARTER set, Oak turns to face
the player and reads 'That's PROF.OAK's last Pokémon!'. The ROM's
'#MON' ligature is spelled out as Pokémon.
The renumbering also drops the table's nine out-of-range 'jump 21'
rows (run-time 'end' idioms) for explicit "end" targets, so the
script now validates cleanly.
Tests: T2 suite drives the ball talk table through a ScriptRunner-
compatible executor (leftover text, pre-escort text, pre-pick offer)
plus a T3 driver that talks to the leftover ball in a real game.
The selected badge list stayed on the stack while its description opened. Cancelling the next list only closed that newer menu, leaving the NPC conversation open.