mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
f11b9c762f
Badge lines are end-battle texts (SaveEndBattleTextPointers), so they are
printed while the battle sound engine is still loaded. A text sound command
names an id rather than a sound, and that engine's SFX_Headers_2 gives those
ids different sounds: the id behind sound_get_item_1 / sound_level_up is
SFX_Level_Up there, and the id behind sound_get_key_item is SFX_Ball_Poof.
The port resolved the jingle by name, so it always played the overworld
reading (Get_Item1 / Get_Key_Item) -- the wrong jingle for receiving the
BOULDERBADGE, and the same collision for Cerulean, Saffron, Cinnabar and
Viridian in Red, Blue and Yellow alike.
Add victories.badgeSoundFor(), which answers with the jingle that is actually
audible for the badge hand-over:
Red/Blue Brock Level_Up, Misty Ball_Poof, Sabrina Ball_Poof,
Blaine Ball_Poof, Giovanni Level_Up
Yellow the same, except Misty: CeruleanGym.asm drops the command from
that line, so Yellow's Cascade Badge has no jingle
Vermilion, Celadon and Fuchsia carry no sound on their badge lines in any
version. The raw `badgeSound` field keeps the overworld-engine name, which is
what the TM texts (printed in the overworld) genuinely need.
Tests: pin the literal per-version jingle and its page for all five badge
leaders in tests/engine/gym_badge_jingle_page_bug1982.lua (53 checks), and
have the #1606 and driver suites assert through badgeSoundFor.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
136 lines
5.3 KiB
Lua
136 lines
5.3 KiB
Lua
-- Driver: gym-leader post-battle dialogue chain (#164).
|
|
-- Invokes checkVictoryRewards for Brock then Misty (same path as a win)
|
|
-- and screenshots pages that must include badge-effect + TM explanation
|
|
-- text -- not just a synthetic "received badge/TM" stub.
|
|
--
|
|
-- SHOT_DIR=/tmp/gym164 POKEPORT_DRIVER=tests/drivers/gym_leader_victory_test.lua love .
|
|
return function(game)
|
|
local U = dofile("tests/drivers/util.lua")
|
|
local DIR = os.getenv("SHOT_DIR") or "/tmp/shots"
|
|
local TextBox = require("src.render.TextBox")
|
|
local OW = require("src.world.OverworldController")
|
|
|
|
local function currentPageText()
|
|
local top = game.stack:top()
|
|
if getmetatable(top) ~= TextBox then return "" end
|
|
local page = top.pages and top.pages[top.pageIndex]
|
|
if not page then return "" end
|
|
return table.concat(page, "\n")
|
|
end
|
|
|
|
local function mashUntil(cond)
|
|
for _ = 1, 1200 do
|
|
if cond() then return true end
|
|
U.tap(game, "a")
|
|
U.wait(2)
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function advancePages(want, shotName)
|
|
U.log(shotName, "waiting for:", want)
|
|
local ok = mashUntil(function()
|
|
local top = game.stack:top()
|
|
if getmetatable(top) ~= TextBox then return false end
|
|
-- only match once the current page has finished typing
|
|
if not (top.waiting or top.done) then return false end
|
|
return currentPageText():find(want, 1, true) ~= nil
|
|
end)
|
|
U.log(shotName, "found:", ok, "page:", currentPageText():gsub("\n", "\\n"))
|
|
U.shot(game, DIR .. "/" .. shotName .. ".png")
|
|
assert(ok, shotName .. " missing dialogue containing: " .. want)
|
|
end
|
|
|
|
local function runLeader(mapId, x, y, class, party, shots)
|
|
while game.stack:top() do game.stack:pop() end
|
|
game.save.flags = game.save.flags or {}
|
|
game.save.inventory = game.save.inventory or {}
|
|
game.save.defeatedTrainers = game.save.defeatedTrainers or {}
|
|
game.stack:push(OW, mapId, x, y, "up")
|
|
U.wait(5)
|
|
local ow = game.stack:top()
|
|
U.shot(game, DIR .. "/" .. shots.prefix .. "_0_gym.png")
|
|
-- true: the badge line rode the battle screen on the real path (#1606)
|
|
ow:checkVictoryRewards(class, party, true)
|
|
U.wait(10)
|
|
for _, s in ipairs(shots.pages) do
|
|
advancePages(s.want, shots.prefix .. "_" .. s.name)
|
|
end
|
|
U.log(shots.prefix, "closing box:", mashUntil(function()
|
|
return game.stack:top() == ow
|
|
end))
|
|
U.shot(game, DIR .. "/" .. shots.prefix .. "_done.png")
|
|
end
|
|
|
|
game.save.player.name = game.save.player.name or "RED"
|
|
|
|
-- The REAL gym path (#1606): the badge line and jingle must ride the
|
|
-- battle it pushes (scripts/PewterGym.asm:117-119).
|
|
while game.stack:top() do game.stack:pop() end
|
|
local Pokemon = require("src.pokemon.Pokemon")
|
|
game.save.party = { Pokemon.new(game.data, "CHARIZARD", 50) }
|
|
game.save.flags = game.save.flags or {}
|
|
game.save.inventory = game.save.inventory or {}
|
|
game.save.defeatedTrainers = game.save.defeatedTrainers or {}
|
|
game.stack:push(OW, "PEWTER_GYM", 4, 3, "up")
|
|
U.wait(5)
|
|
local realOw = game.stack:top()
|
|
local brock
|
|
for _, npc in ipairs(realOw.npcs or {}) do
|
|
if npc.def and npc.def.trainerClass == "OPP_BROCK" then brock = npc end
|
|
end
|
|
assert(brock, "Brock stands in PEWTER_GYM")
|
|
require("data.scripts.gyms").PEWTER_GYM.talk.TEXT_PEWTERGYM_BROCK(
|
|
game, realOw, brock, function() end)
|
|
local battle
|
|
for _ = 1, 600 do
|
|
local top = game.stack:top()
|
|
if top and top.oppClass == "OPP_BROCK" and top.onFinish then
|
|
battle = top
|
|
break
|
|
end
|
|
U.tap(game, "a")
|
|
U.wait(2)
|
|
end
|
|
assert(battle, "the real gym path reaches Brock's BattleState")
|
|
assert(type(battle.endBattleText) == "string" and #battle.endBattleText > 0,
|
|
"the battle carries the armed badge line (#1606)")
|
|
assert(battle.endBattleSound == "Level_Up",
|
|
"and the badge jingle beside it (sound_level_up, PewterGym.asm; the " ..
|
|
"battle sound engine is loaded, so it plays SFX_Level_Up, #2339)")
|
|
assert(battle.endBattleSoundPage == 3,
|
|
"the jingle is armed for the BOULDERBADGE page (PewterGym.asm:156)")
|
|
U.shot(game, DIR .. "/brock_real_battle.png")
|
|
U.log("force-finishing Brock's battle to run the reward chain")
|
|
battle.onFinish("win")
|
|
if game.stack:top() == battle then game.stack:pop() end
|
|
U.wait(10)
|
|
-- rewardDialogueShown: the badge line rode the battle screen, so the map
|
|
-- chain opens on the TM prelude, not on a reprint of the badge line
|
|
for _, s in ipairs({
|
|
{ want = "Wait!", name = "1_wait" },
|
|
{ want = "TM34", name = "2_tm34" },
|
|
{ want = "BIDE", name = "3_bide" },
|
|
}) do
|
|
advancePages(s.want, "brock_" .. s.name)
|
|
end
|
|
assert(game.save.flags.EVENT_BEAT_BROCK, "EVENT_BEAT_BROCK")
|
|
assert(game.save.inventory.BOULDERBADGE, "BOULDERBADGE")
|
|
assert((game.save.inventory.TM_BIDE or 0) >= 1, "TM_BIDE")
|
|
|
|
-- checkVictoryRewards direct drive, as after a battle whose badge line
|
|
-- rode the battle screen (shownOnBattleScreen = true)
|
|
runLeader("CERULEAN_GYM", 5, 5, "OPP_MISTY", 1, {
|
|
prefix = "misty",
|
|
pages = {
|
|
{ want = "CUT", name = "1_cut" },
|
|
{ want = "TM11", name = "2_tm11" },
|
|
},
|
|
})
|
|
assert(game.save.flags.EVENT_BEAT_MISTY, "EVENT_BEAT_MISTY")
|
|
assert(game.save.inventory.CASCADEBADGE, "CASCADEBADGE")
|
|
assert((game.save.inventory.TM_BUBBLEBEAM or 0) >= 1, "TM_BUBBLEBEAM")
|
|
|
|
U.log("gym_leader_victory_test: ok")
|
|
end
|