Play the jingle when Oak hands over the starter (#668)

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.
This commit is contained in:
Shane McGovern
2026-08-02 16:14:25 +01:00
parent 0f45bb5792
commit 1dae9622e1
3 changed files with 68 additions and 26 deletions
+23 -18
View File
@@ -22,10 +22,10 @@ local function starterBall(askText, species, choseFlag, ownBall,
rivalBallX, rivalBall)
return {
{ "check_flag", "EVENT_GOT_STARTER" }, -- 1
{ "jump_if_true", 20 }, -- 2
{ "jump_if_true", 22 }, -- 2
-- no picking until Oak has walked you in (OaksLabScript gating)
{ "check_flag", "EVENT_FOLLOWED_OAK_INTO_LAB" }, -- 3
{ "jump_if_false", 23 }, -- 4
{ "jump_if_false", 25 }, -- 4
-- the Pokédex "new species" entry shows before the ask (predef
-- StarterDex ahead of OaksLabYouWant...Text). StarterDex temporarily
-- sets the owned bits so ShowPokedexData prints height/weight/text;
@@ -37,36 +37,41 @@ local function starterBall(askText, species, choseFlag, ownBall,
-- OaksLab.asm prints ReceivedMon then AddPartyMon (AskName lives
-- inside give_pokemon). Show the received text first so the
-- nickname prompt follows "you got X", matching Gen1.
{ "show_text", "_OaksLabReceivedMonText", { RAM = species } }, -- 8
{ "give_pokemon", species, 5 }, -- 9
{ "set_flag", "EVENT_GOT_STARTER" }, -- 10
{ "set_flag", choseFlag }, -- 11
-- The received text carries sound_get_key_item (OaksLab.asm
-- OaksLabReceivedMonText); the jingle plays as the box opens
-- (same beat as the Yellow port's starter, #668).
{ "play_sound", "Get_Key_Item" }, -- 8
{ "show_text", "_OaksLabReceivedMonText", { RAM = species } }, -- 9
{ "give_pokemon", species, 5 }, -- 10
{ "set_flag", "EVENT_GOT_STARTER" }, -- 11
{ "set_flag", choseFlag }, -- 12
-- POKé BALLs are not handed out here in the original -- Oak gives
-- them later, at OaksLabOak1Text's .give_poke_balls beat once the
-- player has beaten the Route 22 rival (see TEXT_OAKSLAB_OAK1 below)
{ "hide_object", "OAKS_LAB", ownBall }, -- 12
{ "hide_object", "OAKS_LAB", ownBall }, -- 13
-- the rival walks to the countering ball (around the furniture)
{ "move_npc_to", 1, rivalBallX, 4 }, -- 13
{ "face_object", 1, "up" }, -- 14
{ "show_text", "_OaksLabRivalIllTakeThisOneText" }, -- 15
{ "hide_object", "OAKS_LAB", rivalBall }, -- 16
{ "move_npc_to", 1, rivalBallX, 4 }, -- 14
{ "face_object", 1, "up" }, -- 15
{ "show_text", "_OaksLabRivalIllTakeThisOneText" }, -- 16
{ "hide_object", "OAKS_LAB", rivalBall }, -- 17
{ "play_sound", "Get_Key_Item" }, -- 18 (sound_get_key_item)
{ "show_text", "_OaksLabRivalReceivedMonText",
{ RAM = rivalBall == "OAKSLAB_CHARMANDER_POKE_BALL" and "CHARMANDER"
or rivalBall == "OAKSLAB_SQUIRTLE_POKE_BALL" and "SQUIRTLE"
or "BULBASAUR" } }, -- 17
{ "jump", "end" }, -- 18
{ "jump", "end" }, -- 19 (spacer)
or "BULBASAUR" } }, -- 19
{ "jump", "end" }, -- 20
{ "jump", "end" }, -- 21 (spacer)
-- a leftover ball after the player's pick: Oak turns to face the
-- player and reads the last-mon line instead of re-offering the
-- starter (scripts/OaksLab.asm OaksLabSelectedPokeBallScript ->
-- OaksLabLastMonScript; #601). The ROM's "#MON" ligature is spelled
-- out as Pokémon here.
{ "face_object", 5, "down" }, -- 20
{ "show_text", "That's PROF.OAK's\nlast Pokémon!" }, -- 21
{ "face_object", 5, "down" }, -- 22
{ "show_text", "That's PROF.OAK's\nlast Pokémon!" }, -- 23
-- OaksLabLastMonScript ends at TextScriptEnd; the port used to fall
-- through into the pre-pick line below (#601 remnant, reported on #600)
{ "jump", "end" }, -- 22
{ "show_text", "_OaksLabThoseArePokeBallsText" }, -- 23
{ "jump", "end" }, -- 24
{ "show_text", "_OaksLabThoseArePokeBallsText" }, -- 25
}
end
+25 -8
View File
@@ -94,11 +94,18 @@ T.check(box:find("Those are", 1, true) == nil,
T.check(box:find("#MON", 1, true) == nil,
"the ROM #MON ligature is spelled out as Pokémon")
-- the pokered beat also turns Oak to face the player
T.check(contribution.talk[BALL][20][1] == "face_object"
and contribution.talk[BALL][20][2] == 5
and contribution.talk[BALL][20][3] == "down",
"row 20 faces Oak down before the line (OaksLabLastMonScript)")
-- the pokered beat also turns Oak to face the player: find the
-- face_object row in the leftover-ball path (content-based, so a jingle
-- row added for #668 doesn't shift the hard-coded index)
local oakFaceRow
for i, row in ipairs(contribution.talk[BALL]) do
if row[1] == "face_object" and row[2] == 5 and row[3] == "down" then
oakFaceRow = i
break
end
end
T.check(oakFaceRow ~= nil,
"a face_object row turns Oak down before the line (OaksLabLastMonScript)")
-- ---- pre-escort: still the vanilla "Those are POKé BALLs" line
local pre = { EVENT_GOT_STARTER = false, EVENT_FOLLOWED_OAK_INTO_LAB = false }
@@ -115,15 +122,25 @@ T.check(concat(t3):find("last Pokémon!", 1, true) == nil,
"no last-mon line before the pick")
-- ---- all three balls share the same table shape (last-mon beat present)
-- content-based again: locate the leftover-ball "Pokémon" line wherever
-- it sits, instead of pinning a row number (#668 added two jingle rows)
for _, key in ipairs({
"TEXT_OAKSLAB_CHARMANDER_POKE_BALL",
"TEXT_OAKSLAB_SQUIRTLE_POKE_BALL",
"TEXT_OAKSLAB_BULBASAUR_POKE_BALL",
}) do
local script = contribution.talk[key]
T.check(script and script[21] and script[21][2] and
script[21][2]:find("Pokémon", 1, true) ~= nil,
key .. " carries the last-mon line")
local lastMon
if script then
for _, row in ipairs(script) do
if row[1] == "show_text" and type(row[2]) == "string"
and row[2]:find("Pokémon", 1, true) then
lastMon = row[2]
break
end
end
end
T.check(lastMon ~= nil, key .. " carries the last-mon line")
end
T.finish("oaks_lab_last_ball_bug601")
+20
View File
@@ -34,6 +34,16 @@ Game.stack = StateStack; StateStack:init()
Game.save = SaveData.newGame()
require("src.render.Font").load(Data)
-- spy on Sound.play so the starter-received jingle beat is observable
-- without real audio (parity_C does the same for its arrival SFX)
local Sound = require("src.core.Sound")
local realSoundPlay = Sound.play
local played = {}
Sound.play = function(data, name)
played[#played + 1] = name
return realSoundPlay(data, name)
end
-- pumps a script coroutine to completion; pressFn returns the Input.pressed
-- table for this frame (default: mash A through text/ask/naming)
local function runScript(script, pressFn)
@@ -64,6 +74,14 @@ check(Flags.get(Game.save, "EVENT_GOT_STARTER"), "starter flag set")
eq(Game.save.inventory.POKE_BALL, nil, "no POKe BALLs yet right after picking a starter")
check(Game.save.party[1] and Game.save.party[1].species == "BULBASAUR",
"starter joined the party")
-- #668: OaksLabReceivedMonText carries sound_get_key_item; the jingle
-- must fire as the starter is handed over (once for the player's mon,
-- once for the rival's counter-pick)
local jingles = 0
for _, name in ipairs(played) do
if name == "Get_Key_Item" then jingles = jingles + 1 end
end
eq(jingles, 2, "starter + rival counter-pick both play the Get_Key_Item jingle (#668)")
-- A-mash accepts the nickname prompt and fills NamingScreen with A's
check(Game.save.party[1].nickname == "AAAAAAAAAA",
"starter nickname prompt accepted (AskName / #137)")
@@ -182,4 +200,6 @@ do
Game.save = realSave
end
Sound.play = realSoundPlay
S.finish()