mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-07 17:31:35 -04:00
2fd5d09228
Several screens looked their cart strings up in the script cache on every draw, every frame or every read. Each now resolves them once: - the Battle Arena's judgment titles, when the window opens; - the Battle Dome's tourney title, when the tree opens, and a match card's win and match-number texts, when the card is built; - the Frontier Pass map's landmark names and descriptions, when the map opens; - the Pokédex search screen's option texts, when the cursor moves instead of on every frame of the option list; - the party menu's action labels, once per action list; - the Battle Pyramid bag's "Return to" place, when the bag opens; - the expanded placeholders, when their table is built for the current script cache.
210 lines
12 KiB
Lua
210 lines
12 KiB
Lua
-- Emerald screens that keep their own copy of a cart string read the script
|
|
-- cache's text for it when the cache holds it, the way script messages do,
|
|
-- so a mod's text overrides reach them; the pack's copy stays the fallback.
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local function ir(s) return { { t = "text", s = s }, { t = "eos" } } end
|
|
|
|
local BUNDLE = { text = {} }
|
|
package.loaded["src.core.game3.scripting.space"] = { ensureBundle = function() return BUNDLE end }
|
|
|
|
local RomText = require("src.core.game3.rom_text")
|
|
local TextIR = require("src.core.game3.scripting.text_ir")
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
local function plain(x) return x and TextIR.toPlain(x, {}) or nil end
|
|
|
|
-- RomText.irOr / RomText.refIr
|
|
BUNDLE.text = { gText_RecordsLv50 = ir("NIVEAU 50"), ["g3:08abcdef"] = ir("PAR ADRESSE") }
|
|
check(plain(RomText.irOr("gText_RecordsLv50", ir("LV. 50"))) == "NIVEAU 50", "irOr reads the cached text")
|
|
check(plain(RomText.irOr("gText_Missing", ir("LV. 50"))) == "LV. 50", "irOr falls back on the copy")
|
|
check(plain(RomText.irOr(nil, ir("LV. 50"))) == "LV. 50", "irOr without a key keeps the copy")
|
|
check(plain(RomText.refIr({ name = "gText_RecordsLv50", key = "g3:08000000", ir = ir("LV. 50") })) == "NIVEAU 50",
|
|
"refIr reads a reference by its symbol")
|
|
check(plain(RomText.refIr({ name = "sUnnamed", key = "g3:08abcdef", ir = ir("BY ADDRESS") })) == "PAR ADRESSE",
|
|
"refIr reads a reference by its address")
|
|
check(plain(RomText.refIr({ name = "sUnnamed", key = "g3:08000000", ir = ir("COPY") })) == "COPY",
|
|
"refIr falls back on the reference's copy")
|
|
check(RomText.refIr(nil) == nil, "refIr of no reference is nil")
|
|
|
|
-- Battle Dome tables, keyed by the table's label (extract_scripts.lua).
|
|
BUNDLE.text = { ["sBattleDomePotentialTexts[1]"] = ir("Fort potentiel") }
|
|
local Dome = require("src.core.game3.rse.frontier.dome")
|
|
local potential = { ir("Best candidate"), ir("Strong potential") }
|
|
check(plain(Dome.tableText(potential, "sBattleDomePotentialTexts", 2)) == "Fort potentiel",
|
|
"a Dome table string reads the cached text by its label")
|
|
check(plain(Dome.tableText(potential, "sBattleDomePotentialTexts", 1)) == "Best candidate",
|
|
"a Dome table string missing from the cache keeps the copy")
|
|
|
|
-- Apprentice messages are pack references.
|
|
local Apprentice = require("src.core.game3.rse.frontier.apprentice")
|
|
BUNDLE.text = { gText_ApprenticeWhichMon = ir("Lequel?") }
|
|
Apprentice.manifest = function()
|
|
return { whichMon = { { { name = "gText_ApprenticeWhichMon", key = "g3:08000001", ir = ir("Which one?") },
|
|
{ name = "gText_ApprenticeThanks", key = "g3:08000002", ir = ir("Thanks!") } } } }
|
|
end
|
|
Apprentice.player = function() return { id = 0 } end
|
|
check(plain(Apprentice.message({}, Apprentice.MSG.WHICH_MON)) == "Lequel?", "an Apprentice line reads the cached text")
|
|
check(plain(Apprentice.message({}, Apprentice.MSG.THANKS_MON)) == "Thanks!",
|
|
"an Apprentice line missing from the cache keeps the copy")
|
|
|
|
-- The Battle Pyramid bag's "Return to ..." line (pokeemerald/src/battle_pyramid_bag.c:687).
|
|
local Pyramid = require("src.core.game3.rse.frontier.pyramid")
|
|
local PyramidBag = require("src.ui.game3.rse.pyramid_bag")
|
|
Pyramid.bagCursor = { scroll = 0, cursor = 0 }
|
|
Pyramid.bagLists = function() return {}, {} end
|
|
Pyramid.manifest = function()
|
|
return { bagReturnTo = { { name = "gText_TheField", key = "g3:08000003", ir = ir("the field") } } }
|
|
end
|
|
PyramidBag._st.count, PyramidBag._st.location = 1, "field"
|
|
BUNDLE.text = { gText_ReturnToVar1 = { { t = "text", s = "Retourner " }, { t = "strvar", n = 1 }, { t = "eos" } },
|
|
gText_TheField = ir("au jeu") }
|
|
PyramidBag._st.returnTo = PyramidBag.returnTo("field")
|
|
check(PyramidBag.description() == "Retourner au jeu", "the bag's return line names the place from the cache")
|
|
BUNDLE.text.gText_TheField = nil
|
|
check(PyramidBag.description() == "Retourner au jeu", "the open bag keeps the place it read")
|
|
PyramidBag._st.returnTo = PyramidBag.returnTo("field")
|
|
check(PyramidBag.description() == "Retourner the field", "a place missing from the cache keeps the copy")
|
|
|
|
-- Ever Grande City's fly destinations (pokeemerald/src/region_map.c:343).
|
|
local RegionMap = require("src.ui.game3.rse.region_map")
|
|
RegionMap.manifest = function()
|
|
return { multiNameFlyDestinations = { { names = { "POKéMON LEAGUE", "POKéMON CENTER" }, mapSecId = 5, flag = 2100 } } }
|
|
end
|
|
local function flySub()
|
|
local s = { mapSecType = RegionMap.TYPE.CITY_CANFLY, mapSecId = 5, posWithinMapSec = 1, mapSecName = "EVER GRANDE",
|
|
session = { flags = { [2100] = true } } }
|
|
RegionMap.updateFlyText(s)
|
|
return s.flyText.sub
|
|
end
|
|
BUNDLE.text = { ["sEverGrandeCityNames[1]"] = ir("CENTRE POKéMON") }
|
|
check(flySub() == "CENTRE POKéMON", "a fly destination reads its name from the cache")
|
|
BUNDLE.text = {}
|
|
check(flySub() == "POKéMON CENTER", "a fly destination missing from the cache keeps the copy")
|
|
|
|
-- The Pokédex search screen (pokeemerald/src/pokedex.c:1017, 1042, 1330).
|
|
local Gfx = require("src.ui.game3.rse.pokedex_gfx")
|
|
Gfx.manifest = function()
|
|
return { search = {
|
|
topBar = { { description = "Search for POKéMON based on selected parameters." } },
|
|
items = { { description = "List by the first letter in the name." }, {}, {}, {}, {}, {},
|
|
{ description = "Execute search/switch." } },
|
|
orders = { { title = "NUMERICAL", description = "Pokédex listing by number." },
|
|
{ title = "A TO Z", description = "Alphabetical order." } },
|
|
types = { { title = "NONE" }, { title = "NORMAL" }, { title = "FIGHT" } },
|
|
} }
|
|
end
|
|
local Pokedex = require("src.ui.game3.rse.pokedex")
|
|
BUNDLE.text = {
|
|
gText_SearchForPkmnBasedOnParameters = ir("Chercher des POKéMON."),
|
|
gText_ListByFirstLetter = ir("Classer par initiale."),
|
|
gText_ExecuteSearchSwitch = ir("Lancer la recherche."),
|
|
gText_DexSortNumericalTitle = ir("NUMERIQUE"),
|
|
gText_DexSortNumericalDescription = ir("Classement par numéro."),
|
|
["gTypeNames[0]"] = ir("NORMAL"), ["gTypeNames[1]"] = ir("COMBAT"),
|
|
}
|
|
local orders = Pokedex.searchOptionTexts(Pokedex.SEARCH.ORDER)
|
|
check(orders[1].title == "NUMERIQUE" and orders[1].description == "Classement par numéro.",
|
|
"a search option reads its title and description from the cart")
|
|
check(orders[2].title == "A TO Z" and orders[2].description == "Alphabetical order.",
|
|
"a search option missing from the cache keeps the copy")
|
|
local types = Pokedex.searchOptionTexts(Pokedex.SEARCH.TYPE_LEFT)
|
|
check(types[1].title == "NONE" and types[3].title == "COMBAT", "type options read gTypeNames by type id")
|
|
check(Pokedex.topBarDescription(0) == "Chercher des POKéMON.", "a top bar description reads the cart's text")
|
|
check(Pokedex.itemDescription(0) == "Classer par initiale.", "a search item description reads the cart's text")
|
|
check(Pokedex.itemDescription(Pokedex.SEARCH.OK) == "Lancer la recherche.", "the OK item's description reads the cart's text")
|
|
|
|
-- The party menu's actions (pokeemerald/src/data/party_menu.h:658).
|
|
require("tests.game3_cache").stubSpeciesNames()
|
|
local Profile = require("src.core.game3.profile")
|
|
local Pokemon = require("src.core.game3.pokemon")
|
|
local Kit = require("src.ui.game3.rse.scene_kit")
|
|
local PartyMenu = require("src.ui.game3.party_menu")
|
|
Profile.forSession = function()
|
|
return { ui = { party = { manifest = "rse/menus", cursorOptionTexts = { "gText_Summary5", "gText_Switch2",
|
|
"gText_Cancel2" } } } }
|
|
end
|
|
Kit.manifest = function()
|
|
return { party = { cursorOptions = { "SUMMARY", "SWITCH", "CANCEL", "CUT" }, fieldMoves = { 15 } } }
|
|
end
|
|
Pokemon.moveName = function(move) return move == 15 and "COUPE" or nil end
|
|
BUNDLE.text = { gText_Summary5 = ir("RESUME"), gText_Switch2 = ir("ORDRE") }
|
|
check(PartyMenu._cursorOptionText("SUMMARY") == "RESUME", "a party action reads the cart's text")
|
|
check(PartyMenu._cursorOptionText("SWITCH") == "ORDRE", "a second party action reads the cart's text")
|
|
check(PartyMenu._cursorOptionText("CANCEL") == "CANCEL", "a party action missing from the cache keeps the label")
|
|
check(PartyMenu._cursorOptionText("CUT") == "COUPE", "a field move prints the move's name")
|
|
|
|
-- Expanded placeholders (pokeemerald/src/strings.c:6): the rival's name and
|
|
-- Japanese くん/ちゃん come from the cache, the extract's copies otherwise.
|
|
local Message = require("src.ui.game3.message")
|
|
local extracted = {
|
|
RIVAL_MALE = "MAY", RIVAL_FEMALE = "BRENDAN", KUN_MALE = "", KUN_FEMALE = "", VERSION = "EMERALD",
|
|
byGender = { RIVAL = { male = "MAY", female = "BRENDAN" }, KUN = { male = "", female = "" } },
|
|
}
|
|
BUNDLE.text = { gText_ExpandedPlaceholder_May = ir("FLORA"), gText_ExpandedPlaceholder_Kun = ir("くん") }
|
|
local placeholders = Message.cartPlaceholders(extracted)
|
|
check(placeholders.byGender.RIVAL.male == "FLORA", "the rival's name reads the cache")
|
|
check(placeholders.byGender.RIVAL.female == "BRENDAN", "a rival name missing from the cache keeps the copy")
|
|
check(placeholders.byGender.KUN.male == "くん", "the honorific reads the cache")
|
|
check(placeholders.VERSION == "EMERALD", "a placeholder missing from the cache keeps the copy")
|
|
BUNDLE.text.gText_ExpandedPlaceholder_May = ir("AURA")
|
|
check(placeholders.byGender.RIVAL.male == "FLORA", "the values are resolved once, not on every read")
|
|
local line = { { t = "player" }, { t = "ph", code = 5, name = "KUN" }, { t = "text", s = " / " },
|
|
{ t = "ph", code = 6, name = "RIVAL" }, { t = "eos" } }
|
|
BUNDLE.text = { gText_ExpandedPlaceholder_May = ir("FLORA"), gText_ExpandedPlaceholder_Kun = ir("くん"),
|
|
gText_ExpandedPlaceholder_Brendan = ir("BRICE"), gText_ExpandedPlaceholder_Chan = ir("ちゃん") }
|
|
placeholders = Message.cartPlaceholders(extracted)
|
|
check(TextIR.toPlain(line, { dialect = "rse", playerName = "RED", playerGender = 0, placeholders = placeholders })
|
|
== "REDくん / FLORA", "a boy's line expands the honorific and May's name from the cache")
|
|
check(TextIR.toPlain(line, { dialect = "rse", playerName = "RED", playerGender = 1, placeholders = placeholders })
|
|
== "REDちゃん / BRICE", "a girl's line expands the honorific and Brendan's name from the cache")
|
|
|
|
-- The context provider builds them once per script cache.
|
|
local Space = package.loaded["src.core.game3.scripting.space"]
|
|
Space.bundle = BUNDLE
|
|
package.loaded["src.import.CacheFs"] = { loadActive = function() return extracted end }
|
|
local first = TextIR.placeholdersFor({ dialect = "rse" })
|
|
check(first ~= nil and TextIR.placeholdersFor({ dialect = "rse" }) == first,
|
|
"the provider builds the placeholders once per script cache")
|
|
check(first.byGender.RIVAL.female == "BRICE", "the provider's placeholders read the cache")
|
|
BUNDLE = { text = { gText_ExpandedPlaceholder_Brendan = ir("BRUNO") } }
|
|
Space.bundle = BUNDLE
|
|
check(TextIR.placeholdersFor({ dialect = "rse" }).byGender.RIVAL.female == "BRUNO",
|
|
"a new script cache rebuilds them")
|
|
Space.bundle = nil
|
|
|
|
-- The Battle Arena's judgment window reads its titles once, when it opens
|
|
-- (pokeemerald/src/battle_arena.c:412).
|
|
local Data = require("src.core.game3.rse.frontier.f2_data")
|
|
Data.arena = function()
|
|
return { text = { playerMon1Name = ir("A"), vs = ir("VS"), opponentMon1Name = ir("B"), mind = ir("MIND"),
|
|
skill = ir("SKILL"), body = ir("BODY"), judgment = ir("JUDGMENT") } }
|
|
end
|
|
local Arena = require("src.core.game3.battle.facility_arena")
|
|
local arena = Arena.new()
|
|
BUNDLE.text = { gText_Mind = ir("ESPRIT") }
|
|
arena:judgeStep({}, { state = "open" })
|
|
local titles = {}
|
|
for _, row in ipairs(arena.window.texts) do titles[row.win] = plain(row.ir) end
|
|
check(titles[Arena.WIN.MIND] == "ESPRIT", "the judgment window reads a title from the cache when it opens")
|
|
check(titles[Arena.WIN.BODY] == "BODY", "a judgment title missing from the cache keeps the copy")
|
|
BUNDLE.text = { gText_Mind = ir("AUTRE") }
|
|
titles = {}
|
|
for _, row in ipairs(arena.window.texts) do titles[row.win] = plain(row.ir) end
|
|
check(titles[Arena.WIN.MIND] == "ESPRIT", "the open window keeps the titles it read")
|
|
|
|
if failed > 0 then
|
|
print(failed .. " check(s) failed")
|
|
os.exit(1)
|
|
end
|
|
print("all checks passed")
|