mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-25 23:11:15 +02:00
1905261c5b
CLOSES #1483, CLOSES #1610, CLOSES #1615, CLOSES #1646, CLOSES #1649, CLOSES #1651, CLOSES #1653, CLOSES #1656, CLOSES #1683, CLOSES #1685, CLOSES #1686, CLOSES #1687, CLOSES #1688, CLOSES #1689, CLOSES #1690, CLOSES #1693, CLOSES #1694, CLOSES #1695, CLOSES #1696, CLOSES #1702, CLOSES #1704, CLOSES #1705, CLOSES #1706, CLOSES #1707, CLOSES #1708, CLOSES #1710, CLOSES #1711, CLOSES #1712, CLOSES #1713, CLOSES #1716, CLOSES #1717, CLOSES #1718, CLOSES #1719, CLOSES #1720, CLOSES #1721, CLOSES #1725, CLOSES #1732, CLOSES #1745, CLOSES #1748, CLOSES #1749, CLOSES #1751, CLOSES #1754
158 lines
6.7 KiB
Lua
158 lines
6.7 KiB
Lua
-- Pet-NPC cries: #1687 (S.S. Anne WIGGLYTUFF + MACHOKE) and #1649
|
|
-- (Vermilion PIDGEY, Vermilion City MACHOP, Fan Club PIKACHU + SEEL).
|
|
-- Commands.play_cry only arms the very next show_text, so what is asserted
|
|
-- here is placement: one play_cry row, the right species, the waitForButton
|
|
-- form, sitting immediately before the box it belongs to. The sound itself
|
|
-- is a driver's job (tests/drivers/pet_cries_bug1687_1649_test.lua).
|
|
-- Self-contained: `luajit tests/pet_cries_test.lua`.
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
if not _G.love then _G.love = require("tests.love_stub") end
|
|
|
|
local Data = require("src.core.Data")
|
|
if not (Data.maps and Data.maps.PALLET_TOWN) then Data:load() end
|
|
local init = require("data.scripts.init")
|
|
local GameVersion = require("src.core.GameVersion")
|
|
local S = require("tests.harness").suite("pet cries")
|
|
local check, eq = S.check, S.eq
|
|
|
|
local yellow = GameVersion.isYellow()
|
|
|
|
-- pokered/scripts/*.asm, PlayCry line in brackets:
|
|
-- SSAnne1FRooms.asm:66 [:70], SSAnneB1FRooms.asm:82 [:86],
|
|
-- VermilionPidgeyHouse.asm:15 [:19], VermilionCity.asm:224 [:228],
|
|
-- PokemonFanClub.asm:71 [:76] and :84 [:89].
|
|
local PETS = {
|
|
{ map = "SS_ANNE_1F_ROOMS", const = "TEXT_SSANNE1FROOMS_WIGGLYTUFF",
|
|
object = "SSANNE1FROOMS_WIGGLYTUFF", species = "WIGGLYTUFF",
|
|
label = "_SSAnne1FRoomsWigglytuffText" },
|
|
{ map = "SS_ANNE_B1F_ROOMS", const = "TEXT_SSANNEB1FROOMS_MACHOKE",
|
|
object = "SSANNEB1FROOMS_MACHOKE", species = "MACHOKE",
|
|
label = "_SSAnneB1FRoomsMachokeText" },
|
|
{ map = "VERMILION_PIDGEY_HOUSE", const = "TEXT_VERMILIONPIDGEYHOUSE_PIDGEY",
|
|
object = "VERMILIONPIDGEYHOUSE_PIDGEY", species = "PIDGEY",
|
|
label = "_VermilionPidgeyHousePidgeyText" },
|
|
-- the cry belongs to the first box; the stomping line is a second box
|
|
-- with no cry of its own (VermilionCity.asm:233 .StompingTheLandFlatText)
|
|
{ map = "VERMILION_CITY", const = "TEXT_VERMILIONCITY_MACHOP",
|
|
object = "VERMILIONCITY_MACHOP", species = "MACHOP",
|
|
label = "_VermilionCityMachopText",
|
|
after = "_VermilionCityMachopStompingTheLandFlatText" },
|
|
{ map = "POKEMON_FAN_CLUB", const = "TEXT_POKEMONFANCLUB_SEEL",
|
|
object = "POKEMONFANCLUB_SEEL", species = "SEEL",
|
|
label = "_PokemonFanClubSeelText" },
|
|
}
|
|
|
|
if yellow then
|
|
PETS[#PETS + 1] = {
|
|
map = "POKEMON_FAN_CLUB", const = "TEXT_POKEMONFANCLUB_CLEFAIRY",
|
|
object = "POKEMONFANCLUB_CLEFAIRY", species = "CLEFAIRY",
|
|
label = "_PokemonFanClubClefairyText",
|
|
}
|
|
else
|
|
PETS[#PETS + 1] = {
|
|
map = "POKEMON_FAN_CLUB", const = "TEXT_POKEMONFANCLUB_PIKACHU",
|
|
object = "POKEMONFANCLUB_PIKACHU", species = "PIKACHU",
|
|
label = "_PokemonFanClubPikachuText",
|
|
}
|
|
end
|
|
|
|
local function rowsOf(script)
|
|
local plays, texts = {}, {}
|
|
for i, row in ipairs(script) do
|
|
if type(row) == "table" then
|
|
if row[1] == "play_cry" then plays[#plays + 1] = i end
|
|
if row[1] == "show_text" then texts[#texts + 1] = i end
|
|
end
|
|
end
|
|
return plays, texts
|
|
end
|
|
|
|
for _, pet in ipairs(PETS) do
|
|
local tag = pet.map .. "/" .. pet.const
|
|
local script = init.talkScript(pet.map, pet.const)
|
|
if check(type(script) == "table", tag .. " has a ported talk script") then
|
|
local plays = rowsOf(script)
|
|
if eq(#plays, 1, tag .. " carries exactly one play_cry row") then
|
|
local cry = script[plays[1]]
|
|
eq(cry[2], pet.species, tag .. " cries " .. pet.species)
|
|
-- the waitForButton form: without it the box pops itself when the
|
|
-- cry ends instead of holding for A/B (Commands.play_cry, #247/#251)
|
|
eq(cry[3], true, tag .. " uses the waitForButton play_cry form")
|
|
-- play_cry arms ctx.pendingCry for the NEXT show_text only, so the
|
|
-- box it belongs to has to be the very next row
|
|
local next_ = script[plays[1] + 1]
|
|
check(type(next_) == "table" and next_[1] == "show_text"
|
|
and next_[2] == pet.label,
|
|
tag .. " arms " .. pet.label .. " on the next row")
|
|
end
|
|
if pet.after then
|
|
local _, texts = rowsOf(script)
|
|
eq(#texts, 2, tag .. " still shows both of its boxes")
|
|
local last = texts[#texts]
|
|
eq(script[last][2], pet.after, tag .. " keeps " .. pet.after .. " last")
|
|
end
|
|
end
|
|
|
|
check(Data.pokemon[pet.species] ~= nil, pet.species .. " is a known species")
|
|
check(Data.audio.cries and Data.audio.cries[pet.species] ~= nil,
|
|
pet.species .. " has a cry program in the mounted cache")
|
|
local text = Data.text[pet.label]
|
|
check(type(text) == "string" and text ~= "",
|
|
pet.label .. " resolves to text")
|
|
|
|
-- a script nobody can reach is the same silence as a missing cry
|
|
local objects = (Data.maps[pet.map] or {}).objects or {}
|
|
local found
|
|
for _, o in ipairs(objects) do
|
|
if o.name == pet.object then found = o end
|
|
end
|
|
if check(found ~= nil, pet.map .. " still lists " .. pet.object) then
|
|
eq(found.text, pet.const, pet.object .. " talks through " .. pet.const)
|
|
end
|
|
end
|
|
|
|
-- Yellow swaps the Fan Club pet for a CLEFAIRY on its own text constant
|
|
-- (pokeyellow/data/maps/objects/PokemonFanClub.asm), so the extra row has
|
|
-- to be version-gated in both directions.
|
|
if yellow then
|
|
check(init.talkScript("POKEMON_FAN_CLUB", "TEXT_POKEMONFANCLUB_CLEFAIRY") ~= nil,
|
|
"Yellow registers the CLEFAIRY pet")
|
|
else
|
|
check(init.talkScript("POKEMON_FAN_CLUB", "TEXT_POKEMONFANCLUB_CLEFAIRY") == nil,
|
|
"Red/Blue do not register Yellow's CLEFAIRY pet")
|
|
end
|
|
|
|
-- The Yellow half of that guard, checked from any version: re-read the
|
|
-- module with isYellow forced on, then put package.loaded back exactly as
|
|
-- it was so the registry keeps pointing at the table it merged.
|
|
do
|
|
local key = "data.scripts.flavor.pokemon_fan_club"
|
|
local cached = package.loaded[key]
|
|
local realIsYellow = GameVersion.isYellow
|
|
GameVersion.isYellow = function() return true end
|
|
package.loaded[key] = nil
|
|
local ok, module = pcall(require, key)
|
|
GameVersion.isYellow = realIsYellow
|
|
package.loaded[key] = cached
|
|
if check(ok, "the Fan Club script loads with isYellow forced on") then
|
|
local row = module.POKEMON_FAN_CLUB.talk.TEXT_POKEMONFANCLUB_CLEFAIRY
|
|
if check(type(row) == "table", "the Yellow branch adds the CLEFAIRY pet") then
|
|
eq(row[1][1], "play_cry", "Yellow CLEFAIRY leads with play_cry")
|
|
eq(row[1][2], "CLEFAIRY", "Yellow CLEFAIRY cries CLEFAIRY, not PIKACHU")
|
|
eq(row[1][3], true, "Yellow CLEFAIRY uses the waitForButton form")
|
|
eq(row[2][2], "_PokemonFanClubClefairyText",
|
|
"Yellow CLEFAIRY arms its own text")
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Sound.playCry hands PIKACHU to the PCM clips whenever the cache has
|
|
-- them, which is Yellow's voiced cry. Red/Blue must never reach that
|
|
-- branch: audio.pikaCries is the only thing gating it.
|
|
if not yellow then
|
|
check(Data.audio.pikaCries == nil,
|
|
"a non-Yellow cache has no Pikachu voice clips for playCry to find")
|
|
end
|
|
|
|
S.finish()
|