mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-08 17:51:37 -04:00
Merge pull request #2678 from thibautbus/feat/emerald-translation-runtime
Make Emerald's screens reachable by translation mods
This commit is contained in:
@@ -494,8 +494,8 @@ function Adapter.new(battleState, sayFn)
|
||||
if id and id > 0 then
|
||||
if ABILITY_BY_ID[id] then return ABILITY_BY_ID[id] end
|
||||
local ok, Pokemon = pcall(require, "src.core.game3.pokemon")
|
||||
if ok and Pokemon and Pokemon.abilityName then
|
||||
local n = Pokemon.abilityName(id)
|
||||
if ok and Pokemon and Pokemon.romAbilityName then
|
||||
local n = Pokemon.romAbilityName(id)
|
||||
if n and n ~= "" and not n:match("^ABILITY") then
|
||||
return (tostring(n):upper():gsub("%s+", "_"))
|
||||
end
|
||||
|
||||
@@ -228,7 +228,8 @@ local function fill(st, extra)
|
||||
end
|
||||
|
||||
function Fac:refText(st, which, extra)
|
||||
local ir = Data.arena().refereeStrings[which + 1]
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
local ir = RomText.irOr(RomText.key("gRefereeStringsTable", which), Data.arena().refereeStrings[which + 1])
|
||||
return Data.battleText(ir, fill(st, extra))
|
||||
end
|
||||
|
||||
@@ -373,11 +374,32 @@ function Fac:runStep(st, step)
|
||||
return true
|
||||
end
|
||||
|
||||
-- pokeemerald/src/battle_arena.c:412
|
||||
local JUDGMENT_TEXTS = {
|
||||
{ Fac.WIN.PLAYER_NAME, "gText_PlayerMon1Name", "playerMon1Name" },
|
||||
{ Fac.WIN.VS, "gText_Vs", "vs" },
|
||||
{ Fac.WIN.OPPONENT_NAME, "gText_OpponentMon1Name", "opponentMon1Name" },
|
||||
{ Fac.WIN.MIND, "gText_Mind", "mind" },
|
||||
{ Fac.WIN.SKILL, "gText_Skill", "skill" },
|
||||
{ Fac.WIN.BODY, "gText_Body", "body" },
|
||||
{ Fac.WIN.JUDGMENT_TITLE, "gText_Judgment", "judgment" },
|
||||
}
|
||||
|
||||
local function judgmentTexts()
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
local text, out = Data.arena().text, {}
|
||||
for i, row in ipairs(JUDGMENT_TEXTS) do
|
||||
out[i] = { win = row[1], ir = RomText.irOr(row[2], text[row[3]]) }
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
-- pokeemerald/src/battle_arena.c:395
|
||||
function Fac:judgeStep(st, step)
|
||||
local j = self.window
|
||||
if step.state == "open" then
|
||||
self.window = { fade = 0, target = 8, icons = {}, line = true, buffs = { buff1 = "0", buff2 = "0" } }
|
||||
self.window = { fade = 0, target = 8, icons = {}, line = true, buffs = { buff1 = "0", buff2 = "0" },
|
||||
texts = judgmentTexts() }
|
||||
self.fadeWait = true
|
||||
return false
|
||||
elseif step.state == "row" then
|
||||
@@ -519,16 +541,9 @@ function Fac:draw(st)
|
||||
Chrome.userFrame(Chrome._frameType or 0, 6, 1, 18, 12)
|
||||
local W, I = A.windows, A.textInfo
|
||||
local fl = fill(st, j.buffs)
|
||||
local function put(win, ir)
|
||||
windowText(W[win + 1], I[win + 1], fontText(ir, fl))
|
||||
for _, t in ipairs(j.texts) do
|
||||
windowText(W[t.win + 1], I[t.win + 1], fontText(t.ir, fl))
|
||||
end
|
||||
put(Fac.WIN.PLAYER_NAME, A.text.playerMon1Name)
|
||||
put(Fac.WIN.VS, A.text.vs)
|
||||
put(Fac.WIN.OPPONENT_NAME, A.text.opponentMon1Name)
|
||||
put(Fac.WIN.MIND, A.text.mind)
|
||||
put(Fac.WIN.SKILL, A.text.skill)
|
||||
put(Fac.WIN.BODY, A.text.body)
|
||||
put(Fac.WIN.JUDGMENT_TITLE, A.text.judgment)
|
||||
if j.line then
|
||||
local img = self:iconImage(Fac.ANIM.LINE)
|
||||
for i = 0, 7 do love.graphics.draw(img, 64 + i * 16 - 8, 84 - 8) end
|
||||
|
||||
@@ -4,6 +4,7 @@ local PokemonExtract = require("src.import.gba.pokemon_extract")
|
||||
local Versions = require("src.import.gba.versions")
|
||||
local ModRuntime = require("src.mods.Runtime")
|
||||
local CacheBlob = require("src.import.CacheBlob")
|
||||
local Strings = require("src.core.Strings")
|
||||
|
||||
local Pokemon = {}
|
||||
|
||||
@@ -331,7 +332,7 @@ function Pokemon.abilityName(abilityId)
|
||||
if not abilityId or abilityId < 1 then return "-------" end
|
||||
if not Pokemon._abilityNames then Pokemon.install(Pokemon._cache) end
|
||||
local n = Pokemon._abilityNames and Pokemon._abilityNames[abilityId]
|
||||
if n and n ~= "" then return n end
|
||||
if n and n ~= "" then return Strings(n) end
|
||||
error("no ROM ability name for ability " .. abilityId, 2)
|
||||
end
|
||||
|
||||
|
||||
@@ -52,6 +52,13 @@ return {
|
||||
-- pokeemerald/src/menu_specialized.c:1503
|
||||
levelUpStats = { "gText_MaxHP", "gText_Attack", "gText_Defense", "gText_SpAtk", "gText_SpDef", "gText_Speed" },
|
||||
},
|
||||
-- pokeemerald/src/data/party_menu.h:658
|
||||
cursorOptionTexts = {
|
||||
"gText_Summary5", "gText_Switch2", "gText_Cancel2", "gText_Item", "gMenuText_Give", "gText_Take",
|
||||
"gText_Mail", "gText_Take2", "gText_Read2", "gText_Cancel2", "gText_Shift", "gText_SendOut",
|
||||
"gText_Enter", "gText_NoEntry", "gText_Store", "gText_Register", "gText_Trade4", "gText_Trade4",
|
||||
"gMenuText_Toss",
|
||||
},
|
||||
-- pokeemerald/src/party_menu.c:2101
|
||||
buttons = { cancel = "gText_Cancel", confirm = "gMenuText_Confirm" },
|
||||
-- pokeemerald/src/party_menu.c:2557
|
||||
|
||||
@@ -56,6 +56,16 @@ function RomText.has(key)
|
||||
return cachedText(b, key) ~= nil
|
||||
end
|
||||
|
||||
function RomText.irOr(key, fallback)
|
||||
if key ~= nil and RomText.has(key) then return RomText.ir(key) end
|
||||
return fallback
|
||||
end
|
||||
|
||||
function RomText.refIr(ref)
|
||||
if type(ref) ~= "table" then return nil end
|
||||
return RomText.irOr(ref.name, RomText.irOr(ref.key, ref.ir))
|
||||
end
|
||||
|
||||
local SOURCE_FORMS = {}
|
||||
for _, named in ipairs({ false, true }) do
|
||||
for _, nl in ipairs({ "\n", "\\n" }) do
|
||||
|
||||
@@ -593,7 +593,7 @@ function Apprentice.message(sess, which)
|
||||
local e = map[which]
|
||||
if not e then return nil end
|
||||
local ref = e[1][id] and e[1][id][e[2]]
|
||||
return ref and ref.ir
|
||||
return ref and require("src.core.game3.rom_text").refIr(ref)
|
||||
end
|
||||
|
||||
-- pokeemerald/src/apprentice.c:564
|
||||
|
||||
@@ -617,10 +617,16 @@ local function setStr(ctx, adapters, n, v)
|
||||
Util.setStringVar(ctx, adapters, n, v)
|
||||
end
|
||||
|
||||
local function tableText(list, name, i)
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
return RomText.irOr(RomText.key(name, i - 1), list[i])
|
||||
end
|
||||
Dome.tableText = tableText
|
||||
|
||||
-- pokeemerald/src/battle_dome.c:2564
|
||||
function Dome.roundText(sess)
|
||||
local f = Util.frontier(sess)
|
||||
return Data.dome().text.rounds[(tonumber(f.curChallengeBattleNum) or 0) + 1]
|
||||
return tableText(Data.dome().text.rounds, "gRoundsStringTable", (tonumber(f.curChallengeBattleNum) or 0) + 1)
|
||||
end
|
||||
|
||||
-- pokeemerald/src/battle_dome.c:3028
|
||||
@@ -1033,7 +1039,8 @@ function Dome.trainerCard(sess, tid)
|
||||
card.species[i] = facilityMon(sess, f.domeMonIds[tid + 1][i]).species
|
||||
end
|
||||
end
|
||||
card.potential = M.text.potential[(trainerId == D.TRAINER_FRONTIER_BRAIN) and Dome.TRAINERS_COUNT + 1 or tid + 1]
|
||||
card.potential = tableText(M.text.potential, "sBattleDomePotentialTexts",
|
||||
(trainerId == D.TRAINER_FRONTIER_BRAIN) and Dome.TRAINERS_COUNT + 1 or tid + 1)
|
||||
local pts = {}
|
||||
for k = 0, Dome.NUM_MOVE_POINT_TYPES - 1 do pts[k] = 0 end
|
||||
for i = 0, D.PARTY_SIZE - 1 do
|
||||
@@ -1061,8 +1068,8 @@ function Dome.trainerCard(sess, tid)
|
||||
style = style + 1
|
||||
end
|
||||
card.style = style
|
||||
card.styleText = M.text.styles[style + 1]
|
||||
card.statText = M.text.stats[Dome.statTextId(sess, tid) + 1]
|
||||
card.styleText = tableText(M.text.styles, "sBattleDomeOpponentStyleTexts", style + 1)
|
||||
card.statText = tableText(M.text.stats, "sBattleDomeOpponentStatsTexts", Dome.statTextId(sess, tid) + 1)
|
||||
return card
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
local Rse = require("src.core.game3.rse.init")
|
||||
local D = require("src.core.game3.rse.frontier.trainers")
|
||||
local Util = require("src.core.game3.rse.frontier.util")
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
|
||||
local NativesFrontier = {}
|
||||
|
||||
@@ -307,7 +308,7 @@ function NativesFrontier.ssTidalMultichoice(ctx, adapters)
|
||||
local FrlgFont = require("src.ui.game3.frlg_font")
|
||||
for i, id in ipairs(sel) do
|
||||
local ref = D.manifest().ssTidalDestinations[id + 1]
|
||||
labels[i] = TextIR.toPlain(ref.ir, {})
|
||||
labels[i] = TextIR.toPlain(RomText.refIr(ref), {})
|
||||
local w = FrlgFont.measure(labels[i])
|
||||
if w > widest then widest = w end
|
||||
end
|
||||
|
||||
@@ -416,6 +416,16 @@ function SummaryData.abilityDescription(abilityId, abilityName)
|
||||
return Strings(d.ABILITIES["ABILITY_"])
|
||||
end
|
||||
|
||||
-- pokeemerald/src/data/contest_text_tables.h:220
|
||||
function SummaryData.contestEffectDescription(effect)
|
||||
local text = type(effect) == "table" and effect.description or effect
|
||||
return Strings(type(text) == "string" and text or "")
|
||||
end
|
||||
|
||||
function SummaryData.contestCategoryName(name)
|
||||
return Strings(name or "")
|
||||
end
|
||||
|
||||
function SummaryData.moveDescription(moveId, moveName)
|
||||
local d = get_descriptions()
|
||||
moveName = rom_name("romMoveName", moveId, moveName)
|
||||
|
||||
@@ -155,7 +155,7 @@ local function rsePrint()
|
||||
local idx = pyramid.location(sess) == pyramid.LOCATION.TOP and #headers or
|
||||
(tonumber(pyramid.frontier(sess).curChallengeBattleNum) or 0) + 1
|
||||
local ref = headers[idx]
|
||||
if ref then name = require("src.core.game3.scripting.text_ir").toPlain(ref.ir) end
|
||||
if ref then name = require("src.core.game3.scripting.text_ir").toPlain(RomText.refIr(ref)) end
|
||||
elseif sec == rseConstants():id("region_map_sections", "MAPSEC_SECRET_BASE") then
|
||||
-- pokeemerald/src/secret_base.c:735
|
||||
local sb = R.system("secretBase")
|
||||
|
||||
@@ -41,6 +41,27 @@ end
|
||||
|
||||
local placeholderCache = {}
|
||||
|
||||
-- pokeemerald/src/strings.c:6
|
||||
local function cartPlaceholders(extracted)
|
||||
local Extract = require("src.import.gba.text_placeholders_extract")
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
local function value(name)
|
||||
local label = Extract.SYMBOLS[name]
|
||||
if label and RomText.has(label) then return RomText.plain(label) end
|
||||
return extracted[name]
|
||||
end
|
||||
local out, byGender = {}, {}
|
||||
for name, v in pairs(extracted) do out[name] = v end
|
||||
for name in pairs(Extract.SYMBOLS) do out[name] = value(name) end
|
||||
for name, pair in pairs(extracted.byGender or {}) do byGender[name] = pair end
|
||||
for name, pair in pairs(Extract.BY_GENDER) do
|
||||
byGender[name] = { male = out[pair.male], female = out[pair.female] }
|
||||
end
|
||||
out.byGender = byGender
|
||||
return out
|
||||
end
|
||||
Message.cartPlaceholders = cartPlaceholders
|
||||
|
||||
-- pokeemerald/src/string_util.c:456
|
||||
TextIR.setContextProvider(function(kind, dialect, ctx)
|
||||
if kind == "gender" then
|
||||
@@ -66,13 +87,15 @@ TextIR.setContextProvider(function(kind, dialect, ctx)
|
||||
local GameVersion = require("src.core.GameVersion")
|
||||
local s = liveSession()
|
||||
local id = (s and s.version) or GameVersion.get() or ""
|
||||
local Sp = package.loaded["src.core.game3.scripting.space"]
|
||||
local bundle = Sp and Sp.bundle
|
||||
local hit = placeholderCache[id]
|
||||
if hit then return hit end
|
||||
if hit and hit.bundle == bundle then return hit.values end
|
||||
local okC, CacheFs = pcall(require, "src.import.CacheFs")
|
||||
local t = okC and CacheFs.loadActive(dialect.placeholders) or nil
|
||||
if type(t) == "table" then
|
||||
placeholderCache[id] = t
|
||||
return t
|
||||
placeholderCache[id] = { bundle = bundle, values = cartPlaceholders(t) }
|
||||
return placeholderCache[id].values
|
||||
end
|
||||
return nil
|
||||
end)
|
||||
|
||||
@@ -90,7 +90,7 @@ local function gameFieldMoves()
|
||||
index[label] = j - 1
|
||||
byMove[move] = label
|
||||
end
|
||||
return { labels = labels, base = base, index = index, byMove = byMove }
|
||||
return { labels = labels, base = base, index = index, byMove = byMove, moves = moves, texts = p.cursorOptionTexts }
|
||||
end
|
||||
|
||||
local function fieldMoveIndex()
|
||||
@@ -111,14 +111,32 @@ local function cursor_option_text(act)
|
||||
local p = partyUi()
|
||||
if p and p.actionText then return p.actionText(act, g) end
|
||||
if g then
|
||||
-- pokeemerald/src/data/party_menu.h:658
|
||||
local fm = g.index[act]
|
||||
if fm then return g.labels[g.base + fm + 1] end
|
||||
return g.labels[(assert(CURSOR_OPTION[act], act)) + 1]
|
||||
if fm then
|
||||
local move = g.moves[fm + 1]
|
||||
return move and Pokemon.moveName(move) or g.labels[g.base + fm + 1]
|
||||
end
|
||||
local i = assert(CURSOR_OPTION[act], act)
|
||||
local key = g.texts and g.texts[i + 1]
|
||||
if key and RomText.has(key) then return RomText.plain(key) end
|
||||
return g.labels[i + 1]
|
||||
end
|
||||
local fm = FIELD_MOVE_INDEX[act]
|
||||
if fm then return RomText.at("sCursorOptions", CURSOR_OPTION_FIELD_MOVES + fm) end
|
||||
return RomText.at("sCursorOptions", (assert(CURSOR_OPTION[act], act)))
|
||||
end
|
||||
PartyMenu._cursorOptionText = cursor_option_text
|
||||
|
||||
-- pokeemerald/src/party_menu.c:2557
|
||||
local function action_texts(list)
|
||||
local cached = PartyMenu._actionTexts
|
||||
if cached and cached.list == list then return cached.texts end
|
||||
local texts = {}
|
||||
for i, act in ipairs(list) do texts[i] = cursor_option_text(act) end
|
||||
PartyMenu._actionTexts = { list = list, texts = texts }
|
||||
return texts
|
||||
end
|
||||
|
||||
local FR_INSETS = { msgX = 2, msgY = 2, actX = 9, actY = 2, cursorX = 1 }
|
||||
local function textInsets()
|
||||
@@ -2859,12 +2877,13 @@ function PartyMenu.draw()
|
||||
local popX = 22
|
||||
local popY = 19 - popH
|
||||
Window.stdFrame(Window.template(popX, popY, popW, popH))
|
||||
for i, act in ipairs(PartyMenu.ITEM_ACTIONS) do
|
||||
local texts = action_texts(PartyMenu.ITEM_ACTIONS)
|
||||
for i in ipairs(PartyMenu.ITEM_ACTIONS) do
|
||||
local rowY = (popY * 8) + (i - 1) * 16 + ins.actY
|
||||
if i == PartyMenu.itemActionCursor then
|
||||
Window.cursorPx(popX * 8 + ins.cursorX, rowY)
|
||||
end
|
||||
FrlgFont.draw(cursor_option_text(act), popX * 8 + ins.actX, rowY, { colors = FrlgFont.COLOR.NORMAL })
|
||||
FrlgFont.draw(texts[i], popX * 8 + ins.actX, rowY, { colors = FrlgFont.COLOR.NORMAL })
|
||||
end
|
||||
elseif PartyMenu.mode == "action" and p and p.drawActions then
|
||||
p.drawActions(PartyMenu, false)
|
||||
@@ -2878,6 +2897,7 @@ function PartyMenu.draw()
|
||||
local popX = 19
|
||||
local popY = 19 - popH
|
||||
Window.stdFrame(Window.template(popX, popY, popW, popH))
|
||||
local texts = action_texts(PartyMenu.ACTIONS)
|
||||
for i, act in ipairs(PartyMenu.ACTIONS) do
|
||||
local rowY = (popY * 8) + (i - 1) * 16 + ins.actY
|
||||
if i == PartyMenu.actionCursor then
|
||||
@@ -2885,7 +2905,7 @@ function PartyMenu.draw()
|
||||
end
|
||||
local isFm = PartyMenu._fieldMoveNames and PartyMenu._fieldMoveNames[act]
|
||||
local col = isFm and (FrlgFont.COLOR.BLUE or FrlgFont.COLOR.MALE_NPC) or FrlgFont.COLOR.NORMAL
|
||||
FrlgFont.draw(cursor_option_text(act), popX * 8 + ins.actX, rowY, { colors = col })
|
||||
FrlgFont.draw(texts[i], popX * 8 + ins.actX, rowY, { colors = col })
|
||||
end
|
||||
else
|
||||
if p and p.drawPrompt then
|
||||
|
||||
@@ -730,7 +730,10 @@ function UI:printContestMoveDescription(move)
|
||||
self:fillBox(0, TILE_EMPTY_JAM_HEART, 0x15, 0x20, MAX_CONTEST_MOVE_HEARTS, 0x01, 0x11)
|
||||
self:fillBox(0, TILE_FILLED_JAM_HEART, 0x15, 0x20, hearts, 0x01, 0x11)
|
||||
local key = "gContestEffectDescriptionPointers[" .. (cm.effect or 0) .. "]"
|
||||
local desc = UI.has(key) and UI.plain(key) or ""
|
||||
local desc = ""
|
||||
if UI.has(key) then
|
||||
desc = require("src.core.game3.summary_data").contestEffectDescription(UI.plain(key))
|
||||
end
|
||||
self.win[WIN_MOVE_DESCRIPTION] = { text = desc, x = 0, y = 1, fg = 15, shadow = 8 }
|
||||
self.win[WIN_SLASH] = { text = UI.plain("gText_Slash"), x = 0, y = 1, fg = 15, shadow = 8 }
|
||||
end
|
||||
|
||||
@@ -280,7 +280,7 @@ local function drawTree()
|
||||
drawLines()
|
||||
love.graphics.draw(treeImage(), 0, 0)
|
||||
local W = M().treeWindows
|
||||
local title = textOf(M().text.battleTourney)
|
||||
local title = st.treeTitle
|
||||
local tw = W[3]
|
||||
drawSpaced(title, tw.left * 8 + centerX(title, 0x70, "short", 2), tw.top * 8 + 1,
|
||||
colors(COLOR.DYNAMIC_5, COLOR.DYNAMIC_4), "short", 2)
|
||||
@@ -425,12 +425,12 @@ local function drawMatchCard(card, ox, oy)
|
||||
local W = M().cardWindows
|
||||
local c = colors(COLOR.DYNAMIC_5, COLOR.DYNAMIC_4)
|
||||
local d = card.data
|
||||
local wt = textOf(M().text.wins[d.win.id + 1], { d.win.var1, d.win.var2 })
|
||||
local wt = textOf(d.winIr, { d.win.var1, d.win.var2 })
|
||||
winText(W[9], wt, 0, 0, c, "normal", 0, ox, oy)
|
||||
local left, right = d.sides[1], d.sides[2]
|
||||
winText(W[7], left.name, centerX(left.name, 0x40, "short", 2), 2, c, "short", 2, ox, oy)
|
||||
winText(W[8], right.name, centerX(right.name, 0x40, "short", 2), 2, c, "short", 2, ox, oy)
|
||||
local mn = textOf(M().text.matchNumbers[d.matchNo + 1])
|
||||
local mn = textOf(d.matchNoIr)
|
||||
winText(W[6], mn, centerX(mn, 0xA0, "short", 0), 2, c, "short", 0, ox, oy)
|
||||
drawPic(picFor(left.trainerId), ox + 48, oy + 88, left.lost)
|
||||
drawPic(picFor(right.trainerId), ox + 192, oy + 88, right.lost)
|
||||
@@ -443,7 +443,17 @@ end
|
||||
|
||||
local function makeCard(kind, id)
|
||||
if kind == "trainer" then return { kind = kind, id = id, data = trainerCardData(id) } end
|
||||
return { kind = kind, id = id, data = matchCardData(id) }
|
||||
local data = matchCardData(id)
|
||||
local Dome = require("src.core.game3.rse.frontier.dome")
|
||||
-- pokeemerald/src/battle_dome.c:4931, :4977
|
||||
data.winIr = Dome.tableText(M().text.wins, "sBattleDomeWinTexts", data.win.id + 1)
|
||||
data.matchNoIr = Dome.tableText(M().text.matchNumbers, "sBattleDomeMatchNumberTexts", data.matchNo + 1)
|
||||
return { kind = kind, id = id, data = data }
|
||||
end
|
||||
|
||||
-- pokeemerald/src/battle_dome.c:5415
|
||||
local function treeTitle()
|
||||
return textOf(require("src.core.game3.rom_text").irOr("gText_BattleTourney", M().text.battleTourney))
|
||||
end
|
||||
|
||||
local function drawCard(card, ox, oy)
|
||||
@@ -541,6 +551,7 @@ function UI.showTree(opts)
|
||||
st.cursor = opts.cursor or 0
|
||||
st.frame, st.bg2y, st.bg3y = 0, 0, 11
|
||||
buildTree(st.mode)
|
||||
st.treeTitle = treeTitle()
|
||||
st.phase = "fadein"
|
||||
fadeIn()
|
||||
push()
|
||||
@@ -596,6 +607,7 @@ local function backToTree()
|
||||
st.mode = rt.mode
|
||||
st.bg2y, st.bg3y = 0, 11
|
||||
buildTree(st.mode)
|
||||
st.treeTitle = st.treeTitle or treeTitle()
|
||||
st.phase = "fadein"
|
||||
fadeIn()
|
||||
end
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
local Stack = require("src.ui.game3.stack")
|
||||
local FrlgFont = require("src.ui.game3.frlg_font")
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
local Strings = require("src.core.Strings")
|
||||
local Kit = require("src.ui.game3.rse.scene_kit")
|
||||
local Gfx = require("src.ui.game3.rse.pokeblock_gfx")
|
||||
local PalFade = require("src.core.game3.pal_fade")
|
||||
@@ -162,7 +163,7 @@ function Common.categoryText(species)
|
||||
entriesPack = Gfx.loadLua("data/generated/gba/pokemon/pokedex/entries.lua") or {}
|
||||
end
|
||||
local e = entriesPack[tonumber(species) or 0] or {}
|
||||
return (e.category or "") .. " " .. RomText.plain("gText_Pokemon")
|
||||
return Strings(e.category or "") .. " " .. RomText.plain("gText_Pokemon")
|
||||
end
|
||||
|
||||
function Common.speciesName(species)
|
||||
|
||||
@@ -149,12 +149,32 @@ local function updateHighlight(cur, prev)
|
||||
local _ = g
|
||||
end
|
||||
|
||||
-- pokeemerald/src/frontier_pass.c:530
|
||||
local function description(i)
|
||||
return RomText.irOr(RomText.key("sPassAreaDescriptions", i), man().descriptions[i + 1])
|
||||
end
|
||||
|
||||
-- pokeemerald/src/frontier_pass.c:556
|
||||
local LANDMARK_TEXTS = {
|
||||
{ "gText_BattleTower3", "gText_BattleTowerDesc" },
|
||||
{ "gText_BattleDome2", "gText_BattleDomeDesc" },
|
||||
{ "gText_BattlePalace2", "gText_BattlePalaceDesc" },
|
||||
{ "gText_BattleArena2", "gText_BattleArenaDesc" },
|
||||
{ "gText_BattleFactory2", "gText_BattleFactoryDesc" },
|
||||
{ "gText_BattlePike2", "gText_BattlePikeDesc" },
|
||||
{ "gText_BattlePyramid2", "gText_BattlePyramidDesc" },
|
||||
}
|
||||
|
||||
local function landmarkText(i, field)
|
||||
local labels = LANDMARK_TEXTS[i + 1]
|
||||
return RomText.irOr(labels and labels[field == "name" and 1 or 2], man().landmarks[i + 1][field])
|
||||
end
|
||||
|
||||
local function describe(area)
|
||||
local d = man().descriptions
|
||||
if area == A.RECORD and not st.hasRecord then
|
||||
st.desc = textOf(d[A.NOTHING + 1])
|
||||
st.desc = textOf(description(A.NOTHING))
|
||||
elseif area ~= A.NOTHING then
|
||||
st.desc = textOf(d[area + 1])
|
||||
st.desc = textOf(description(area))
|
||||
else
|
||||
st.desc = nil
|
||||
end
|
||||
@@ -456,6 +476,10 @@ function Map.show()
|
||||
Map.pal:beginFade(PalFade.ALL, 0, 16, 0, PalFade.WHITE)
|
||||
Map.image = nil
|
||||
Map.head = Map.headPosition()
|
||||
Map.landmarks = {}
|
||||
for i = 0, NUM_FACILITIES - 1 do
|
||||
Map.landmarks[i] = { name = textOf(landmarkText(i, "name")), description = textOf(landmarkText(i, "description")) }
|
||||
end
|
||||
end
|
||||
|
||||
-- pokeemerald/src/frontier_pass.c:1582
|
||||
@@ -544,9 +568,9 @@ function Map.draw()
|
||||
love.graphics.draw(Map.image, 0, 0)
|
||||
local lm = man().landmarks
|
||||
for i = 0, NUM_FACILITIES - 1 do
|
||||
drawText(textOf(lm[i + 1].name), 160 + 4, 8 + i * 16 + 1, colors(i == Map.pos and 2 or 1), "narrow")
|
||||
drawText(Map.landmarks[i].name, 160 + 4, 8 + i * 16 + 1, colors(i == Map.pos and 2 or 1), "narrow")
|
||||
end
|
||||
drawText(textOf(lm[Map.pos + 1].description), 16 + 4, 128, colors(0))
|
||||
drawText(Map.landmarks[Map.pos].description, 16 + 4, 128, colors(0))
|
||||
local cur = spriteFrame("cursor", 4, 16, 16, p.cursor)
|
||||
love.graphics.draw(cur, 155 + 8, Map.cursorY - 8, 0, -1, 1)
|
||||
local mark = lm[Map.pos + 1]
|
||||
|
||||
@@ -338,12 +338,12 @@ function Records.buildRankingHall(sess, hallId, lvlMode)
|
||||
local win = newWindow(HALL_TPL)
|
||||
local man = D().manifest()
|
||||
local pair = man.recordsChallengeTexts[hallId + 1]
|
||||
local facilityName = plainIr(pair[1].ir)
|
||||
put(win, plainIr(pair[2].ir, { facilityName }), 0, 1)
|
||||
local lvl = plainIr(man.levelModeText[lvlMode + 1].ir)
|
||||
local facilityName = plainIr(RomText.refIr(pair[1]))
|
||||
put(win, plainIr(RomText.refIr(pair[2]), { facilityName }), 0, 1)
|
||||
local lvl = plainIr(RomText.refIr(man.levelModeText[lvlMode + 1]))
|
||||
put(win, lvl, (240 - 32) - width(lvl), 1)
|
||||
local rows = U().rankingHall(sess, hallId, lvlMode)
|
||||
local recordText = man.hallFacilityToRecordsText[hallId + 1].ir
|
||||
local recordText = RomText.refIr(man.hallFacilityToRecordsText[hallId + 1])
|
||||
local link = hallId == U().RANKING_HALL.TOWER_LINK
|
||||
for i, r in ipairs(rows) do
|
||||
local pos = i - 1
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
local MapSections = require("src.import.gba.rse.map_sections_extract")
|
||||
local Strings = require("src.core.Strings")
|
||||
|
||||
local Mapsec = {}
|
||||
|
||||
@@ -45,7 +46,7 @@ end
|
||||
-- pokeemerald/src/region_map.c:1568
|
||||
function Mapsec.name(sec)
|
||||
local e = Mapsec.entry(sec)
|
||||
return e and e.name or ""
|
||||
return e and e.name and Strings(e.name) or ""
|
||||
end
|
||||
|
||||
-- pokeemerald/src/map_name_popup.c:403
|
||||
|
||||
@@ -399,8 +399,11 @@ local function draw_contest(moveId)
|
||||
right(RomText.plain("gText_MoveRelearnerJam"), 92, 41)
|
||||
if not moveId then return end
|
||||
local cm, eff, c = contest_row(moveId)
|
||||
if cm then print_at(c.categories and c.categories[cm.category] or "", 4, 25) end
|
||||
if eff then print_lines(eff.description, 0, 65, NARROW) end
|
||||
if cm then
|
||||
local category = c.categories and c.categories[cm.category]
|
||||
print_at(SummaryData.contestCategoryName(category), 4, 25)
|
||||
end
|
||||
if eff then print_lines(SummaryData.contestEffectDescription(eff), 0, 65, NARROW) end
|
||||
draw_hearts(eff)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
local Kit = require("src.ui.game3.rse.scene_kit")
|
||||
local Strings = require("src.core.Strings")
|
||||
local FrlgFont = require("src.ui.game3.frlg_font")
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
local Pal = require("src.core.game3.pal_fade")
|
||||
@@ -935,7 +936,12 @@ local function monInfo(s, nat, nationalNumber, owned, newEntry)
|
||||
out[#out + 1] = { text = RomText.plain("gText_NumberClear01") .. string.format("%03d", num), x = 0x60, y = 0x19 }
|
||||
local sp = Pokedex.speciesOf(nat)
|
||||
out[#out + 1] = { text = sp ~= 0 and pokemon().name(sp) or Gfx.manifest().tenDashes, x = 0x84, y = 0x19 }
|
||||
local category = owned and ((e.category or "") .. " " .. RomText.plain("gText_Pokemon")) or RomText.plain("gText_5MarksPokemon")
|
||||
local category
|
||||
if owned then
|
||||
category = Strings(e.category or "") .. " " .. RomText.plain("gText_Pokemon")
|
||||
else
|
||||
category = RomText.plain("gText_5MarksPokemon")
|
||||
end
|
||||
out[#out + 1] = { text = category, x = 0x64, y = 0x29 }
|
||||
out[#out + 1] = { text = RomText.plain("gText_HTHeight"), x = 0x60, y = 0x39 }
|
||||
out[#out + 1] = { text = RomText.plain("gText_WTWeight"), x = 0x60, y = 0x49 }
|
||||
@@ -946,7 +952,7 @@ local function monInfo(s, nat, nationalNumber, owned, newEntry)
|
||||
out[#out + 1] = { text = RomText.plain("gText_UnkHeight"), x = 0x81, y = 0x39 }
|
||||
out[#out + 1] = { text = RomText.plain("gText_UnkWeight"), x = 0x81, y = 0x49 }
|
||||
end
|
||||
local desc = owned and (e.description or "") or ""
|
||||
local desc = owned and Strings(e.description or "") or ""
|
||||
local w = 0
|
||||
for line in (desc .. "\n"):gmatch("(.-)\n") do w = math.max(w, FrlgFont.measure(line) or 0) end
|
||||
out[#out + 1] = { text = desc, x = w < 240 and math.floor((240 - w) / 2) or 0, y = 95 }
|
||||
@@ -1587,8 +1593,54 @@ function tasks.switchFromSize(s)
|
||||
end
|
||||
end
|
||||
|
||||
local function cartText(key, fallback)
|
||||
if key and RomText.has(key) then return RomText.plain(key) end
|
||||
return fallback
|
||||
end
|
||||
|
||||
-- pokeemerald/src/pokedex.c:1330
|
||||
local TYPE_OPTION = { "gText_DexSearchTypeNone" }
|
||||
for _, t in ipairs({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17 }) do
|
||||
TYPE_OPTION[#TYPE_OPTION + 1] = RomText.key("gTypeNames", t)
|
||||
end
|
||||
local SEARCH_OPTION_TEXTS = {
|
||||
[SEARCH.NAME] = { titles = { "gText_DexSearchDontSpecify", "gText_DexSearchAlphaABC", "gText_DexSearchAlphaDEF",
|
||||
"gText_DexSearchAlphaGHI", "gText_DexSearchAlphaJKL", "gText_DexSearchAlphaMNO", "gText_DexSearchAlphaPQR",
|
||||
"gText_DexSearchAlphaSTU", "gText_DexSearchAlphaVWX", "gText_DexSearchAlphaYZ" } },
|
||||
[SEARCH.COLOR] = { titles = { "gText_DexSearchDontSpecify", "gText_DexSearchColorRed", "gText_DexSearchColorBlue",
|
||||
"gText_DexSearchColorYellow", "gText_DexSearchColorGreen", "gText_DexSearchColorBlack", "gText_DexSearchColorBrown",
|
||||
"gText_DexSearchColorPurple", "gText_DexSearchColorGray", "gText_DexSearchColorWhite", "gText_DexSearchColorPink" } },
|
||||
[SEARCH.TYPE_LEFT] = { titles = TYPE_OPTION },
|
||||
[SEARCH.TYPE_RIGHT] = { titles = TYPE_OPTION },
|
||||
[SEARCH.ORDER] = {
|
||||
titles = { "gText_DexSortNumericalTitle", "gText_DexSortAtoZTitle", "gText_DexSortHeaviestTitle",
|
||||
"gText_DexSortLightestTitle", "gText_DexSortTallestTitle", "gText_DexSortSmallestTitle" },
|
||||
descriptions = { "gText_DexSortNumericalDescription", "gText_DexSortAtoZDescription",
|
||||
"gText_DexSortHeaviestDescription", "gText_DexSortLightestDescription", "gText_DexSortTallestDescription",
|
||||
"gText_DexSortSmallestDescription" },
|
||||
},
|
||||
[SEARCH.MODE] = {
|
||||
titles = { "gText_DexHoennTitle", "gText_DexNatTitle" },
|
||||
descriptions = { "gText_DexHoennDescription", "gText_DexNatDescription" },
|
||||
},
|
||||
}
|
||||
-- pokeemerald/src/pokedex.c:1017
|
||||
local TOPBAR_DESCRIPTIONS = { "gText_SearchForPkmnBasedOnParameters", "gText_SwitchPokedexListings",
|
||||
"gText_ReturnToPokedex" }
|
||||
-- pokeemerald/src/pokedex.c:1042
|
||||
local ITEM_DESCRIPTIONS = { "gText_ListByFirstLetter", "gText_ListByBodyColor", "gText_ListByType",
|
||||
"gText_ListByType", "gText_SelectPokedexListingMode", "gText_SelectPokedexMode", "gText_ExecuteSearchSwitch" }
|
||||
|
||||
local function topBarDescription(i)
|
||||
return cartText(TOPBAR_DESCRIPTIONS[i + 1], Gfx.manifest().search.topBar[i + 1].description)
|
||||
end
|
||||
|
||||
local function itemDescription(i)
|
||||
return cartText(ITEM_DESCRIPTIONS[i + 1], Gfx.manifest().search.items[i + 1].description)
|
||||
end
|
||||
|
||||
-- pokeemerald/src/pokedex.c:1437
|
||||
local function searchOptionTexts(which)
|
||||
local function searchOptionList(which)
|
||||
local sm = Gfx.manifest().search
|
||||
if which == SEARCH.NAME then return sm.names end
|
||||
if which == SEARCH.COLOR then return sm.colors end
|
||||
@@ -1598,6 +1650,23 @@ local function searchOptionTexts(which)
|
||||
return {}
|
||||
end
|
||||
|
||||
local function searchOptionTexts(which)
|
||||
local list = searchOptionList(which)
|
||||
local keys = SEARCH_OPTION_TEXTS[which]
|
||||
if not keys then return list end
|
||||
local out = {}
|
||||
for i, t in ipairs(list) do
|
||||
out[i] = {
|
||||
title = cartText(keys.titles[i], t.title),
|
||||
description = cartText(keys.descriptions and keys.descriptions[i], t.description),
|
||||
}
|
||||
end
|
||||
return out
|
||||
end
|
||||
Pokedex.searchOptionTexts = searchOptionTexts
|
||||
Pokedex.topBarDescription = topBarDescription
|
||||
Pokedex.itemDescription = itemDescription
|
||||
|
||||
local function searchSel(q, which)
|
||||
local c = q.cursor[which] or 0
|
||||
local o = q.scroll[which] or 0
|
||||
@@ -1766,7 +1835,7 @@ function tasks.loadSearch(s)
|
||||
elseif st == 1 then
|
||||
local q = s.searchState
|
||||
setDefaultSearchModeAndOrder(s, q)
|
||||
setSearchMessage(q, Gfx.manifest().search.topBar[TOPBAR.SEARCH + 1].description)
|
||||
setSearchMessage(q, topBarDescription(TOPBAR.SEARCH))
|
||||
s.searchArrows = {
|
||||
{ x = 184, y = 4, down = false, data2 = 0, invisible = true },
|
||||
{ x = 184, y = 108, down = true, data2 = 0, invisible = true },
|
||||
@@ -1784,7 +1853,7 @@ function tasks.loadSearch(s)
|
||||
s.state = 0
|
||||
s.fn = "searchTopBar"
|
||||
s.searchState.phase = "topbar"
|
||||
setSearchMessage(s.searchState, Gfx.manifest().search.topBar[s.searchState.topBar + 1].description)
|
||||
setSearchMessage(s.searchState, topBarDescription(s.searchState.topBar))
|
||||
refreshSearch(s)
|
||||
end
|
||||
end
|
||||
@@ -1794,7 +1863,6 @@ end
|
||||
function tasks.searchTopBar(s, inp)
|
||||
local new = inp.new or {}
|
||||
local q = s.searchState
|
||||
local sm = Gfx.manifest().search
|
||||
if new.b then
|
||||
se("SE_PC_OFF")
|
||||
s.fn = "exitSearch"
|
||||
@@ -1815,20 +1883,20 @@ function tasks.searchTopBar(s, inp)
|
||||
return
|
||||
end
|
||||
q.phase = "menu"
|
||||
setSearchMessage(q, sm.items[q.menuItem + 1].description)
|
||||
setSearchMessage(q, itemDescription(q.menuItem))
|
||||
refreshSearch(s)
|
||||
return
|
||||
end
|
||||
if new.left and q.topBar > TOPBAR.SEARCH then
|
||||
se("SE_DEX_PAGE")
|
||||
q.topBar = q.topBar - 1
|
||||
setSearchMessage(q, sm.topBar[q.topBar + 1].description)
|
||||
setSearchMessage(q, topBarDescription(q.topBar))
|
||||
refreshSearch(s)
|
||||
end
|
||||
if new.right and q.topBar < TOPBAR.CANCEL then
|
||||
se("SE_DEX_PAGE")
|
||||
q.topBar = q.topBar + 1
|
||||
setSearchMessage(q, sm.topBar[q.topBar + 1].description)
|
||||
setSearchMessage(q, topBarDescription(q.topBar))
|
||||
refreshSearch(s)
|
||||
end
|
||||
end
|
||||
@@ -1850,7 +1918,7 @@ function tasks.searchMenu(s, inp)
|
||||
setDefaultSearchModeAndOrder(s, q)
|
||||
q.phase = "topbar"
|
||||
s.fn = "searchTopBar"
|
||||
setSearchMessage(q, sm.topBar[q.topBar + 1].description)
|
||||
setSearchMessage(q, topBarDescription(q.topBar))
|
||||
refreshSearch(s)
|
||||
return
|
||||
end
|
||||
@@ -1896,7 +1964,7 @@ function tasks.searchMenu(s, inp)
|
||||
if nxt ~= 0xFF then
|
||||
se(sound)
|
||||
q.menuItem = nxt
|
||||
setSearchMessage(q, sm.items[q.menuItem + 1].description)
|
||||
setSearchMessage(q, itemDescription(q.menuItem))
|
||||
refreshSearch(s)
|
||||
end
|
||||
end
|
||||
@@ -1947,7 +2015,7 @@ function tasks.searchDone(s, inp)
|
||||
else
|
||||
s.fn = "searchMenu"
|
||||
q.phase = "menu"
|
||||
setSearchMessage(q, Gfx.manifest().search.items[q.menuItem + 1].description)
|
||||
setSearchMessage(q, itemDescription(q.menuItem))
|
||||
refreshSearch(s)
|
||||
se("SE_BALL")
|
||||
end
|
||||
@@ -1959,8 +2027,7 @@ function tasks.searchParam(s, inp)
|
||||
local new, rep = inp.new or {}, inp.rep or {}
|
||||
local q = s.searchState
|
||||
local mi = q.menuItem
|
||||
local texts = searchOptionTexts(mi)
|
||||
local maxOption = #texts - 1
|
||||
local maxOption = #searchOptionList(mi) - 1
|
||||
if new.a or new.b then
|
||||
se(new.a and "SE_PIN" or "SE_BALL")
|
||||
if new.b then
|
||||
@@ -1969,7 +2036,7 @@ function tasks.searchParam(s, inp)
|
||||
end
|
||||
q.paramBox = false
|
||||
q.phase = "menu"
|
||||
setSearchMessage(q, Gfx.manifest().search.items[mi + 1].description)
|
||||
setSearchMessage(q, itemDescription(mi))
|
||||
refreshSearch(s)
|
||||
s.fn = "searchMenu"
|
||||
return
|
||||
@@ -1994,7 +2061,7 @@ function tasks.searchParam(s, inp)
|
||||
end
|
||||
if moved then
|
||||
se("SE_SELECT")
|
||||
local t = texts[searchSel(q, mi) + 1]
|
||||
local t = searchOptionTexts(mi)[searchSel(q, mi) + 1]
|
||||
setSearchMessage(q, t and t.description or "")
|
||||
refreshSearch(s)
|
||||
end
|
||||
@@ -2138,8 +2205,7 @@ function Pokedex.frame(s, inp)
|
||||
end
|
||||
if s.searchArrows and s.fn == "searchParam" then
|
||||
local q = s.searchState
|
||||
local texts = searchOptionTexts(q.menuItem)
|
||||
local last = #texts - 1
|
||||
local last = #searchOptionList(q.menuItem) - 1
|
||||
for _, a in ipairs(s.searchArrows) do
|
||||
local off = q.scroll[q.menuItem] or 0
|
||||
if a.down then
|
||||
|
||||
@@ -100,11 +100,18 @@ local function itemName(id)
|
||||
end
|
||||
|
||||
-- pokeemerald/src/battle_pyramid_bag.c:379
|
||||
-- pokeemerald/src/battle_pyramid_bag.c:687
|
||||
function PBag.returnTo(location)
|
||||
local ret = Py().manifest().bagReturnTo[(PBag.LOCATION[location] or 0) + 1]
|
||||
return ret and require("src.core.game3.scripting.text_ir").toPlain(RomText.refIr(ret), {}) or ""
|
||||
end
|
||||
|
||||
function PBag.show(opts)
|
||||
opts = opts or {}
|
||||
for k in pairs(st) do st[k] = nil end
|
||||
st.session = opts.session
|
||||
st.location = opts.location or "field"
|
||||
st.returnTo = PBag.returnTo(st.location)
|
||||
st.onClose = opts.onClose
|
||||
st.onUse = opts.onUse
|
||||
st.onGive = opts.onGive
|
||||
@@ -465,9 +472,7 @@ local function description()
|
||||
return RomText.plain("gText_MoveVar1Where", { stringVars = { itemName(items[st.swapFrom + 1]) } })
|
||||
end
|
||||
if item then return ItemsData.description(item) or "" end
|
||||
local ret = Py().manifest().bagReturnTo[(PBag.LOCATION[st.location] or 0) + 1]
|
||||
local TextIR = require("src.core.game3.scripting.text_ir")
|
||||
return RomText.plain("gText_ReturnToVar1", { stringVars = { ret and TextIR.toPlain(ret.ir, {}) or "" } })
|
||||
return RomText.plain("gText_ReturnToVar1", { stringVars = { st.returnTo or "" } })
|
||||
end
|
||||
PBag.description = description
|
||||
|
||||
|
||||
@@ -353,14 +353,20 @@ local function newState(opts)
|
||||
end
|
||||
RegionMap.newState = newState
|
||||
|
||||
-- pokeemerald/src/region_map.c:349
|
||||
local MULTI_NAME_TABLES = { "sEverGrandeCityNames" }
|
||||
|
||||
-- pokeemerald/src/region_map.c:1760
|
||||
function RegionMap.updateFlyText(s)
|
||||
s.flyText = nil
|
||||
if s.mapSecType > TYPE.NONE then
|
||||
for _, m in ipairs(RegionMap.manifest().multiNameFlyDestinations) do
|
||||
for i, m in ipairs(RegionMap.manifest().multiNameFlyDestinations) do
|
||||
if s.mapSecId == m.mapSecId then
|
||||
if flagSet(s, m.flag) then
|
||||
s.flyText = { tall = true, name = s.mapSecName, sub = m.names[s.posWithinMapSec + 1] or "" }
|
||||
local sub = m.names[s.posWithinMapSec + 1] or ""
|
||||
local key = MULTI_NAME_TABLES[i] and RomText.key(MULTI_NAME_TABLES[i], s.posWithinMapSec)
|
||||
if key and RomText.has(key) then sub = RomText.plain(key) end
|
||||
s.flyText = { tall = true, name = s.mapSecName, sub = sub }
|
||||
end
|
||||
break
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
local Kit = require("src.ui.game3.rse.scene_kit")
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
local Strings = require("src.core.Strings")
|
||||
local FrlgFont = require("src.ui.game3.frlg_font")
|
||||
local Pal = require("src.core.game3.pal_fade")
|
||||
local Trig = require("src.core.game3.trig")
|
||||
@@ -126,7 +127,7 @@ local function categoryText(species, policy)
|
||||
local nat = Pokemon.national and Pokemon.national(species) or species
|
||||
local row = dex and dex[nat]
|
||||
-- pokeemerald/src/international_string_util.c:86
|
||||
local category = (row and row.category) or ""
|
||||
local category = Strings((row and row.category) or "")
|
||||
if policy then return policy.categoryText(category, RomText.plain(policy.categoryKey)) end
|
||||
return category .. " " .. RomText.plain("gText_Pokemon")
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ local RomText = require("src.core.game3.rom_text")
|
||||
local Pokemon = require("src.core.game3.pokemon")
|
||||
local ItemsData = require("src.core.game3.items_data")
|
||||
local SummaryData = require("src.core.game3.summary_data")
|
||||
local Strings = require("src.core.Strings")
|
||||
|
||||
local RseSummary = {}
|
||||
|
||||
@@ -416,7 +417,7 @@ local function drawInfo(m, Sm, mon, egg)
|
||||
dynamic = {
|
||||
[0] = RomText.ir("sMemoNatureTextColor"), [1] = RomText.ir("sMemoMiscTextColor"),
|
||||
[2] = RomText.at("gNatureNamePointers", natureId), [3] = tostring(metLevel == 0 and 5 or metLevel),
|
||||
[4] = secName or "", [5] = RomText.ir("gText_EmptyString5"),
|
||||
[4] = secName and Strings(secName) or "", [5] = RomText.ir("gText_EmptyString5"),
|
||||
},
|
||||
})
|
||||
end
|
||||
@@ -545,7 +546,7 @@ local function drawMoves(m, Sm, mon, contest, detail)
|
||||
drawTile(m, "hearts", i < appeal and 1 or 0, tx * 8, ty * 8)
|
||||
drawTile(m, "hearts", i < jam and 3 or 4, tx * 8, (ty + 2) * 8)
|
||||
end
|
||||
put(m, dw, eff.description or "", 6, 1, 0)
|
||||
put(m, dw, SummaryData.contestEffectDescription(eff), 6, 1, 0)
|
||||
end
|
||||
else
|
||||
local pa = win(m, W.POWER_ACC)
|
||||
|
||||
@@ -32,7 +32,7 @@ function Records.lines(sess)
|
||||
local y = 18
|
||||
local modes = Hl.manifest().modeStrings
|
||||
for i = 1, Hl.NUM_MODES do
|
||||
out[#out + 1] = { text = TextIR.toPlain(modes[i].ir, {}), x = 0, y = y }
|
||||
out[#out + 1] = { text = TextIR.toPlain(RomText.refIr(modes[i]), {}), x = 0, y = y }
|
||||
y = y + 15
|
||||
local m, s, f = Hl.timeParts(sess.trainerHillTimes[i])
|
||||
local vars = { string.format("%2d", m), string.format("%2d", s), string.format("%02d", f) }
|
||||
|
||||
@@ -905,23 +905,27 @@ local function draw_page_skills(mon)
|
||||
-- Party stores ability as numeric id (e.g. 65 = OVERGROW); resolve to name.
|
||||
local abilityId = tonumber(mon.abilityId) or tonumber(mon.ability)
|
||||
local ability = mon.abilityName
|
||||
local abilityNameTranslated = false
|
||||
if type(mon.ability) == "string" and mon.ability ~= "" and not tonumber(mon.ability) then
|
||||
ability = mon.ability
|
||||
end
|
||||
if (not ability or ability == "") and abilityId and abilityId > 0 then
|
||||
ability = Pokemon.abilityName(abilityId)
|
||||
abilityNameTranslated = true
|
||||
end
|
||||
if not ability or ability == "" then
|
||||
local aid = Pokemon.abilityId and Pokemon.abilityId(Pokemon.speciesOf(mon), mon.personality or 0)
|
||||
if aid and aid > 0 then
|
||||
abilityId = aid
|
||||
ability = Pokemon.abilityName(aid)
|
||||
abilityNameTranslated = true
|
||||
end
|
||||
end
|
||||
ability = ability or "—"
|
||||
local ax, ay = cxy("abilityName", 74, 129)
|
||||
-- No registry renames abilities; a translation reaches the name through Strings().
|
||||
draw_text(Strings(tostring(ability)), ax, ay, 80, "NORMAL")
|
||||
local abilityText = tostring(ability)
|
||||
if not abilityNameTranslated then abilityText = Strings(abilityText) end
|
||||
draw_text(abilityText, ax, ay, 80, "NORMAL")
|
||||
local desc = SummaryData.abilityDescription(abilityId, tostring(ability))
|
||||
local ad = coords().abilityDesc or { x = 10, y = 143, w = 232 }
|
||||
draw_text(desc, ad.x or 10, ad.y or 143, ad.w or 232, "NORMAL")
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
-- 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")
|
||||
@@ -0,0 +1,201 @@
|
||||
package.path = "./?.lua;./?/init.lua;" .. package.path
|
||||
|
||||
local Strings = require("src.core.Strings")
|
||||
local Mapsec = require("src.ui.game3.rse.mapsec")
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
local FrlgFont = require("src.ui.game3.frlg_font")
|
||||
local Pokemon = require("src.core.game3.pokemon")
|
||||
local BattleText = require("src.core.game3.battle.battle_text")
|
||||
local SummaryData = require("src.core.game3.summary_data")
|
||||
|
||||
Pokemon._abilityNames = { [9] = "STATIC" }
|
||||
Pokemon._romAbilityNames = { [9] = "STATIC" }
|
||||
|
||||
Mapsec.readLua = function(rel)
|
||||
assert(rel == "pokemon/pokedex/entries.lua")
|
||||
return {
|
||||
[252] = {
|
||||
category = "Wood Gecko",
|
||||
description = "A small gecko.",
|
||||
height = 5,
|
||||
weight = 50,
|
||||
},
|
||||
}
|
||||
end
|
||||
RomText.plain = function(key) return key end
|
||||
FrlgFont.measure = function(text) return #text end
|
||||
Pokemon.name = function() return "TREECKO" end
|
||||
|
||||
local Pokedex = require("src.ui.game3.rse.pokedex")
|
||||
Pokedex.speciesOf = function() return 252 end
|
||||
Pokedex.hoennNumber = function() return 1 end
|
||||
|
||||
local function info()
|
||||
return Pokedex.monInfo({}, 252, false, true, false)
|
||||
end
|
||||
|
||||
-- pokeemerald/src/starter_choose.c:579 and battle_factory_screen.c:2007 print
|
||||
-- the same CopyMonCategoryText string as the Pokédex.
|
||||
local Kit = require("src.ui.game3.rse.scene_kit")
|
||||
Kit.loadLua = function(rel)
|
||||
if rel == "data/generated/gba/region_map/map_sections.lua" then
|
||||
return { sections = { [0] = { name = "LITTLEROOT TOWN" } } }
|
||||
end
|
||||
-- the Pokédex reads its layout from the graphics manifest (Emerald's, not
|
||||
-- Ruby/Sapphire's native one)
|
||||
if rel == "data/generated/gba/rse/pokedex/manifest.lua" then return {} end
|
||||
assert(rel == "data/generated/gba/pokemon/dex.lua", rel)
|
||||
return { [252] = { category = "Wood Gecko" } }
|
||||
end
|
||||
Pokemon.national = function(species) return species end
|
||||
Pokemon._names = { [252] = "TREECKO" } -- keeps the starter label from reinstalling the packs
|
||||
local StarterChoose = require("src.ui.game3.rse.starter_choose")
|
||||
StarterChoose.species = function() return 252 end
|
||||
local function starterCategory()
|
||||
local view = setmetatable({ man = {}, selection = 1 }, StarterChoose)
|
||||
view:_createLabel()
|
||||
return view.label.category
|
||||
end
|
||||
|
||||
local PokeblockGfx = require("src.ui.game3.rse.pokeblock_gfx")
|
||||
PokeblockGfx.loadLua = function(rel)
|
||||
assert(rel == "data/generated/gba/pokemon/pokedex/entries.lua", rel)
|
||||
return { [252] = { category = "Wood Gecko" } }
|
||||
end
|
||||
local FactoryCommon = require("src.ui.game3.rse.factory_select").Common
|
||||
|
||||
-- pokeemerald/src/contest.c:3237
|
||||
local ContestUI = require("src.ui.game3.rse.contest")
|
||||
ContestUI.has = function(key) return key == "gContestEffectDescriptionPointers[1]" end
|
||||
ContestUI.plain = function(key)
|
||||
if key == "gContestEffectDescriptionPointers[1]" then return "Startles the audience." end
|
||||
return key
|
||||
end
|
||||
local function contestMoveDescription()
|
||||
local view = setmetatable({
|
||||
c = { data = { moves = { [33] = { category = 0, effect = 1 } }, effects = { [1] = { appeal = 20, jam = 0 } } } },
|
||||
win = {},
|
||||
fillBox = function() end,
|
||||
fillBoxInc = function() end,
|
||||
}, { __index = ContestUI })
|
||||
view:printContestMoveDescription(33)
|
||||
return view.win[10].text
|
||||
end
|
||||
|
||||
-- pokeemerald/src/region_map.c:1568
|
||||
Mapsec.pack = function()
|
||||
return { count = 1, sections = { [0] = { name = "LITTLEROOT TOWN" } } }
|
||||
end
|
||||
|
||||
-- pokeemerald/src/pokemon_summary_screen.c:3116: the trainer memo's met
|
||||
-- location is a map section name.
|
||||
local RseSummary = require("src.ui.game3.rse.summary_menu")
|
||||
local PalText = require("src.ui.game3.rse.pal_text")
|
||||
local drawInfo
|
||||
for i = 1, 60 do
|
||||
local name, value = debug.getupvalue(RseSummary.draw, i)
|
||||
if not name then break end
|
||||
if name == "drawInfo" then drawInfo = value; break end
|
||||
end
|
||||
assert(drawInfo, "RSE summary info page drawer")
|
||||
RomText.ir = function() return {} end
|
||||
RomText.at = function() return {} end
|
||||
PalText.width = function() return 0 end
|
||||
Pokemon.types = function() return {} end
|
||||
Pokemon.speciesOf = function() return 252 end
|
||||
SummaryData.nature = function() return 0 end
|
||||
local function metLocation()
|
||||
local shown
|
||||
local draw = PalText.draw
|
||||
PalText.draw = function(_, _, _, ctx)
|
||||
if ctx and ctx.dynamic then shown = ctx.dynamic[4] end
|
||||
end
|
||||
local w = { left = 0, top = 0, paletteNum = 0 }
|
||||
local m = { palette = {}, textColors = {}, windows = {}, pageWindows = { info = { w, w, w, w } } }
|
||||
local describe = SummaryData.abilityDescription
|
||||
SummaryData.abilityDescription = function() return "" end
|
||||
drawInfo(m, { _playerState = { name = "MAY", trainerId = 1 } },
|
||||
{ species = 252, ability = 9, otName = "MAY", otId = 1, metLevel = 5, metLocation = 0 }, false)
|
||||
PalText.draw, SummaryData.abilityDescription = draw, describe
|
||||
return shown
|
||||
end
|
||||
|
||||
-- A modded ability past the built-in id table resolves to a key from its name.
|
||||
local Adapter = require("src.core.game3.battle.adapter")
|
||||
Pokemon._abilityNames[200] = "NEW SKILL"
|
||||
Pokemon._romAbilityNames[200] = "NEW SKILL"
|
||||
local function adapterAbilityKey()
|
||||
return Adapter.new({}):abilityOf({ ability = 200 })
|
||||
end
|
||||
|
||||
Strings.load({})
|
||||
assert(Pokemon.abilityName(9) == "STATIC",
|
||||
"an ability name keeps its English ROM value without translations")
|
||||
assert(SummaryData.contestCategoryName("Cool") == "Cool",
|
||||
"a contest category keeps its English source without translations")
|
||||
assert(SummaryData.contestEffectDescription({ description = "Startles the audience." })
|
||||
== "Startles the audience.",
|
||||
"a contest effect description keeps its English source without translations")
|
||||
local english = info()
|
||||
assert(english[3].text == "Wood Gecko gText_Pokemon",
|
||||
"the category keeps its English source when no translation is loaded")
|
||||
assert(english[#english].text == "A small gecko.",
|
||||
"the description keeps its English source when no translation is loaded")
|
||||
assert(starterCategory() == "Wood Gecko gText_Pokemon",
|
||||
"the starter label keeps its English category without translations")
|
||||
assert(FactoryCommon.categoryText(252) == "Wood Gecko gText_Pokemon",
|
||||
"the Battle Factory keeps its English category without translations")
|
||||
assert(contestMoveDescription() == "Startles the audience.",
|
||||
"the contest move window keeps its English effect text without translations")
|
||||
assert(Mapsec.name(0) == "LITTLEROOT TOWN",
|
||||
"a map section keeps its English name without translations")
|
||||
assert(Mapsec.name(99) == "", "an unknown map section has no name")
|
||||
assert(metLocation() == "LITTLEROOT TOWN",
|
||||
"the RSE summary keeps the English met location without translations")
|
||||
assert(adapterAbilityKey() == "NEW_SKILL", "the battle adapter keys an unlisted ability by its ROM name")
|
||||
|
||||
Strings.load({ strings = {
|
||||
STATIC = "STATIQUE",
|
||||
Cool = "Sang-froid",
|
||||
["Startles the audience."] = "Surprend le public.",
|
||||
["Wood Gecko"] = "Gecko des bois",
|
||||
["A small gecko."] = "Un petit gecko.",
|
||||
["LITTLEROOT TOWN"] = "BOURG-EN-VOL",
|
||||
["NEW SKILL"] = "NOUVEAU TALENT",
|
||||
} })
|
||||
assert(Pokemon.abilityName(9) == "STATIQUE",
|
||||
"the shared ability-name getter translates the displayed name")
|
||||
assert(Pokemon.romAbilityName(9) == "STATIC",
|
||||
"the original ROM name stays available for stable ID lookups")
|
||||
assert(BattleText.RESOLVE_RSE[0x17]({ lastAbility = 9 }) == "STATIQUE",
|
||||
"the RSE battle ability placeholder uses the translated shared getter")
|
||||
assert(SummaryData.contestCategoryName("Cool") == "Sang-froid",
|
||||
"the move relearner translates the contest category source")
|
||||
assert(SummaryData.contestEffectDescription({ description = "Startles the audience." })
|
||||
== "Surprend le public.",
|
||||
"the RSE summary and move relearner translate the contest effect source")
|
||||
local french = info()
|
||||
assert(french[3].text == "Gecko des bois gText_Pokemon",
|
||||
"the RSE Pokédex translates the source category at presentation time")
|
||||
assert(french[#french].text == "Un petit gecko.",
|
||||
"the RSE Pokédex translates the source description at presentation time")
|
||||
assert(starterCategory() == "Gecko des bois gText_Pokemon",
|
||||
"the starter label translates the category like the Pokédex")
|
||||
assert(FactoryCommon.categoryText(252) == "Gecko des bois gText_Pokemon",
|
||||
"the Battle Factory translates the category like the Pokédex")
|
||||
assert(contestMoveDescription() == "Surprend le public.",
|
||||
"the contest move window translates the effect text like the summary")
|
||||
assert(Mapsec.name(0) == "BOURG-EN-VOL",
|
||||
"the Emerald map section name goes through the registry")
|
||||
assert(metLocation() == "BOURG-EN-VOL",
|
||||
"the RSE summary translates the met location like the region map")
|
||||
assert(Pokemon.abilityName(200) == "NOUVEAU TALENT", "the display name is translated")
|
||||
assert(adapterAbilityKey() == "NEW_SKILL",
|
||||
"the battle adapter keeps keying on the ROM name when the display name is translated")
|
||||
|
||||
Strings.load({})
|
||||
local reloaded = info()
|
||||
assert(reloaded[#reloaded].text == "A small gecko.",
|
||||
"reloading without a catalog restores the English description")
|
||||
|
||||
print("game3_emerald_translation_runtime_test: PASS")
|
||||
@@ -50,12 +50,13 @@ SummaryChrome.manifest = function() return MANIFEST end
|
||||
local SESSION = nil
|
||||
package.loaded["src.core.game3.runtime"] = { getSession = function() return SESSION end }
|
||||
local SummaryData = require("src.core.game3.summary_data")
|
||||
local Strings = require("src.core.Strings")
|
||||
SummaryData.moveDescription = function() return "" end
|
||||
SummaryData.abilityDescription = function() return "" end
|
||||
local realMemo = SummaryData.formatTrainerMemo
|
||||
SummaryData.formatTrainerMemo = function() return {} end
|
||||
SummaryData.expProgress = function() return { totalExp = 0, expNeeded = 0, progressPercent = 0 } end
|
||||
Pokemon.abilityName = function() return "STATIC" end
|
||||
Pokemon.abilityName = function() return Strings("STATIC") end
|
||||
Pokemon.abilityId = function() return 9 end
|
||||
Pokemon.monFrontPic = function() calls[#calls + 1] = { name = "pic", args = {} } return nil end
|
||||
Pokemon.monIcon = function() calls[#calls + 1] = { name = "icon", args = {} } return nil end
|
||||
@@ -215,6 +216,29 @@ local def = text_at("7")
|
||||
eq(def and def.x, 210 + 27 - 6, "a one-digit stat right-aligns too")
|
||||
SummaryMenu.close()
|
||||
|
||||
print("[test] 5b. translated ability names are looked up once")
|
||||
Strings.load({ strings = { STATIC = "STATIQUE", STATIQUE = "NOM ENCORE TRADUIT" } })
|
||||
local numericAbility = mon()
|
||||
numericAbility.ability = 9
|
||||
SummaryMenu.openMenu({ numericAbility }, 1, { page = SummaryMenu.PAGE_SKILLS })
|
||||
draw()
|
||||
check(text_at("STATIQUE") ~= nil,
|
||||
"the numeric ability getter's translated name is not translated a second time")
|
||||
check(text_at("NOM ENCORE TRADUIT") == nil,
|
||||
"a chained catalog entry does not change the numeric ability label")
|
||||
SummaryMenu.close()
|
||||
|
||||
local externalAbility = mon()
|
||||
externalAbility.ability = "STATIC"
|
||||
SummaryMenu.openMenu({ externalAbility }, 1, { page = SummaryMenu.PAGE_SKILLS })
|
||||
draw()
|
||||
check(text_at("STATIQUE") ~= nil,
|
||||
"a raw external ability label is translated once at the summary consumer")
|
||||
check(text_at("NOM ENCORE TRADUIT") == nil,
|
||||
"a raw external ability label also avoids chained translation")
|
||||
SummaryMenu.close()
|
||||
Strings.load({})
|
||||
|
||||
local function text_xy(x, y)
|
||||
for _, t in ipairs(texts) do if t.x == x and t.y == y then return t end end
|
||||
return nil
|
||||
|
||||
@@ -30,6 +30,15 @@ check(SummaryData.moveDescription(71, "VOL-VIE"):find("absorbs half", 1, true) ~
|
||||
"a renamed move still finds its description")
|
||||
check(SummaryData.abilityDescription(9, "STATIK") == "Paralyzes on contact.",
|
||||
"a renamed ability still finds its description")
|
||||
check(Pokemon.abilityName(9) == "STATIK",
|
||||
"an ability name falls back to the current displayed source")
|
||||
|
||||
Strings.load({ strings = { STATIK = "STATIQUE" } })
|
||||
check(Pokemon.abilityName(9) == "STATIQUE",
|
||||
"the shared ability-name getter translates the current displayed name")
|
||||
check(Pokemon.romAbilityName(9) == "STATIC",
|
||||
"the ROM ability name remains stable for ID-based lookups")
|
||||
Strings.load({})
|
||||
|
||||
Strings.load({ strings = { ["Paralyzes on contact."] = "Paralyse au contact." } })
|
||||
check(SummaryData.abilityDescription(9, "STATIK") == "Paralyse au contact.",
|
||||
|
||||
Reference in New Issue
Block a user