mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-08 09:42:55 -04:00
Read Ruby and Sapphire's native screens' cart text from the script cache
The Ruby/Sapphire shop, decoration menus, move relearner and contest
paintings printed the cart strings their extractors copied into their
packs (textBytes, keyed by the strings' pokeruby labels), so a
translation never reached them. The script cache holds the same strings
under the same labels, where a mod's text overrides land: these screens
now read it there, with the pack's copy as the fallback, the way
Emerald's screens do (RomText.irOr). The shop, the decoration menus and
the move relearner keep each text they resolve until the screen opens
again, the painting its caption once it is built.
A hall painting's caption names the trainer, then the POKéMON, as the
US cart does; the European carts name the POKéMON first, their
possessive row starting with a space (" von ", " de ", " di ",
pokeruby/src/contest_painting.c:234), and so does the caption now
when the row does.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
local Base = require("src.ui.game3.rse.contest_painting")
|
||||
local IR = require("src.core.game3.scripting.text_ir")
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
local Kit = require("src.ui.game3.rse.scene_kit")
|
||||
local Font = require("src.ui.game3.frlg_font")
|
||||
local Painting = {ID = Base.ID, SUB = Base.SUB}
|
||||
@@ -11,9 +12,9 @@ local function manifest()
|
||||
return man
|
||||
end
|
||||
|
||||
local function render(bytes)
|
||||
local function render(ir)
|
||||
local out = {}
|
||||
for _, seg in ipairs(IR.decode(bytes, {dialect = "rs"})) do
|
||||
for _, seg in ipairs(ir) do
|
||||
if seg.t == "ext" then
|
||||
out[#out + 1] = string.char(252, seg.cmd)
|
||||
for _, arg in ipairs(seg.args or {}) do out[#out + 1] = string.char(arg) end
|
||||
@@ -21,7 +22,10 @@ local function render(bytes)
|
||||
end
|
||||
return table.concat(out)
|
||||
end
|
||||
local function text(man, key) return render(assert(man.textBytes[key], "native painting caption missing: " .. key)) end
|
||||
local function text(man, key)
|
||||
local bytes = assert(man.textBytes[key], "native painting caption missing: " .. key)
|
||||
return render(RomText.irOr(key, IR.decode(bytes, {dialect = "rs"})))
|
||||
end
|
||||
local function name(value, limit)
|
||||
if type(value) == "table" then
|
||||
local bytes = {}
|
||||
@@ -30,7 +34,7 @@ local function name(value, limit)
|
||||
bytes[#bytes + 1] = value[i]
|
||||
end
|
||||
bytes[#bytes + 1] = 255
|
||||
return render(bytes)
|
||||
return render(IR.decode(bytes, {dialect = "rs"}))
|
||||
end
|
||||
if type(value) ~= "string" then return "" end
|
||||
if not limit then return value end
|
||||
@@ -48,9 +52,11 @@ function Painting.caption(saveIdx, winner, artist, man)
|
||||
local nickname = name(winner.monName or winner.nickname, man.captionLayout.nicknameBytes)
|
||||
local category = tonumber(winner.contestCategory) or 0
|
||||
if saveIdx < man.captionLayout.museumStart then
|
||||
-- pokeruby/src/contest_painting.c:234
|
||||
local possessive, first, second = text(man, man.hallPossessive), name(winner.trainerName), nickname
|
||||
if possessive:find("^[ ,]") then first, second = nickname, name(winner.trainerName) end
|
||||
return text(man, assert(man.rankNames[category], "native painting category")) .. text(man, man.hallCaption)
|
||||
.. name(winner.trainerName) .. string.char(unpack(man.captionLayout.hallLatinControl))
|
||||
.. text(man, man.hallPossessive) .. nickname
|
||||
.. first .. string.char(unpack(man.captionLayout.hallLatinControl)) .. possessive .. second
|
||||
end
|
||||
local pair = assert(man.captionParts[category], "native museum caption pair")
|
||||
return text(man, pair.prefix) .. nickname .. text(man, pair.suffix)
|
||||
|
||||
@@ -27,9 +27,16 @@ local aliases = {
|
||||
UI.TEXT_ALIASES = {gText_ApostropheSBase = "gOtherText_PlayersBase"}
|
||||
local cats = {gText_Desk = 0, gText_Chair = 1, gText_Plant = 2, gText_Ornament = 3,
|
||||
gText_Mat = 4, gText_Poster = 5, gText_Doll = 6, gText_Cushion = 7}
|
||||
local resolved = {}
|
||||
local function nativeText(key, vars)
|
||||
if cats[key] ~= nil then return Inv.categoryName(cats[key]) end
|
||||
local native, m = aliases[key] or key, Decor.manifest()
|
||||
if not vars and resolved[native] then return resolved[native] end
|
||||
if Text.has(native) then
|
||||
local value = Text.plain(native, vars and {stringVars = vars} or nil)
|
||||
if not vars then resolved[native] = value end
|
||||
return value
|
||||
end
|
||||
if m.textBytes and m.textBytes[native] then
|
||||
return IR.toPlain(IR.decode(m.textBytes[native], {dialect = "rs"}), {stringVars = vars or {}})
|
||||
end
|
||||
@@ -116,6 +123,7 @@ function UI.draw(d, host)
|
||||
end
|
||||
local function options(opts)
|
||||
opts = opts or {}
|
||||
resolved = {}
|
||||
opts.text, opts.draw = nativeText, UI.draw
|
||||
opts.recordSecretBaseVisit = false
|
||||
opts.avatarGfx = function(s, female)
|
||||
|
||||
@@ -3,6 +3,7 @@ local Kit = require("src.ui.game3.rse.scene_kit")
|
||||
local Font = require("src.ui.game3.frlg_font")
|
||||
local Pokemon = require("src.core.game3.pokemon")
|
||||
local IR = require("src.core.game3.scripting.text_ir")
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
local bit = require("bit")
|
||||
local UI = {}
|
||||
local keys = {gText_TeachWhichMoveToPkmn = "gOtherText_TeachWhichMove",
|
||||
@@ -13,13 +14,20 @@ local function manifest()
|
||||
assert(m.assetLayout == "rs", "native RS move tutor pack required")
|
||||
return m
|
||||
end
|
||||
local resolved = {}
|
||||
local function cartIr(native)
|
||||
if not resolved[native] then
|
||||
resolved[native] = RomText.irOr(native,
|
||||
IR.decode(assert(manifest().textBytes[native], "native tutor text " .. native), {dialect = "rs"}))
|
||||
end
|
||||
return resolved[native]
|
||||
end
|
||||
local function text(key, ctx)
|
||||
local m, native = manifest(), keys[key] or key
|
||||
return IR.toPlain(IR.decode(assert(m.textBytes[native], "native tutor text " .. native), {dialect = "rs"}), ctx or {})
|
||||
return IR.toPlain(cartIr(keys[key] or key), ctx or {})
|
||||
end
|
||||
local function pages(key, vars)
|
||||
local out = {}
|
||||
local value = IR.toAscii(IR.decode(assert(manifest().textBytes[key]), {dialect = "rs"}), {stringVars = vars})
|
||||
local value = IR.toAscii(cartIr(key), {stringVars = vars})
|
||||
for page in (value .. "\\p"):gmatch("(.-)\\p") do if page ~= "" then out[#out + 1] = page end end
|
||||
return out
|
||||
end
|
||||
@@ -164,6 +172,7 @@ function UI.draw(st)
|
||||
end
|
||||
function UI.show(mon, opts)
|
||||
manifest(); opts = opts or {}
|
||||
resolved = {}
|
||||
opts.maxShown, opts.text, opts.draw, opts.startLearn = 3, text, UI.draw, startLearn
|
||||
return Base.show(mon, opts)
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ local Chrome = require("src.ui.game3.chrome")
|
||||
local Cursor = require("src.ui.game3.rs.menu_cursor")
|
||||
local Window = require("src.ui.game3.window")
|
||||
local TextIR = require("src.core.game3.scripting.text_ir")
|
||||
local RomText = require("src.core.game3.rom_text")
|
||||
local Items = require("src.core.game3.items_data")
|
||||
local UI = {CAMERA_OFFSET = {x = -3, y = -3}}
|
||||
UI.WIN = {money = Window.template(1, 1, 12, 2), qty = Window.template(1, 11, 12, 2),
|
||||
@@ -15,10 +16,14 @@ local function manifest()
|
||||
assert(man.assetLayout == "rs" and man.shopVersion == 2, "native RS shop schema required")
|
||||
return man
|
||||
end
|
||||
local resolved = {}
|
||||
function UI.ir(key)
|
||||
if resolved[key] then return resolved[key] end
|
||||
local man = manifest()
|
||||
local native = assert(man.textAliases[key] or (man.textBytes[key] and key), "native RS shop text policy missing: " .. key)
|
||||
return TextIR.decode(assert(man.textBytes[native], "native RS shop text bytes missing: " .. native), {dialect = "rs"})
|
||||
resolved[key] = RomText.irOr(native,
|
||||
TextIR.decode(assert(man.textBytes[native], "native RS shop text bytes missing: " .. native), {dialect = "rs"}))
|
||||
return resolved[key]
|
||||
end
|
||||
function UI.plain(key, ctx) return TextIR.toPlain(UI.ir(key), ctx or {}) end
|
||||
function UI.box(key, ctx) return UI.plain(key, ctx) end
|
||||
@@ -176,6 +181,7 @@ function UI.drawSell(sale)
|
||||
end
|
||||
function UI.show(shop, opts)
|
||||
opts = opts or {}; opts.nativePolicy = UI
|
||||
resolved = {}
|
||||
manifest()
|
||||
shop._rsShopFrame = 0
|
||||
return Base.show(shop, opts)
|
||||
|
||||
@@ -134,6 +134,65 @@ check(Entries.ready(entriesCache("return { [277] = { descriptionLabel = \"DexDes
|
||||
"an R/S cache with the labels keeps its entries")
|
||||
Registry.active = active
|
||||
|
||||
-- Native screens that keep a cart string in their pack under its pret label
|
||||
-- read the script cache's text under that label first.
|
||||
local COPY = { 0xBD, 0xC9, 0xCA, 0xD3, 0xFF } -- "COPY"
|
||||
local Kit = require("src.ui.game3.rse.scene_kit")
|
||||
local MANIFESTS = {
|
||||
["items/shop"] = { assetLayout = "rs", shopVersion = 2, textAliases = { gText_HowMayIServeYou = "gOtherText_HowMayIServe" },
|
||||
textBytes = { gOtherText_HowMayIServe = COPY, gOtherText_Unnamed = COPY } },
|
||||
}
|
||||
Kit.manifest = function(sub)
|
||||
if MANIFESTS[sub] then return MANIFESTS[sub] end
|
||||
return { assetLayout = "rs", textBytes = { gOtherText_TeachWhichMove = COPY, gOtherText_Unnamed = COPY } }
|
||||
end
|
||||
local Shop = require("src.ui.game3.rs.shop_menu")
|
||||
BUNDLE.text = { gOtherText_HowMayIServe = ir("Que puis-je faire pour vous ?"),
|
||||
gOtherText_TeachWhichMove = ir("Quelle capacité apprendre ?") }
|
||||
check(Shop.plain("gText_HowMayIServeYou") == "Que puis-je faire pour vous ?", "the shop reads the cache by its label")
|
||||
check(Shop.plain("gOtherText_Unnamed") == "COPY", "a shop line missing from the cache keeps the pack's copy")
|
||||
|
||||
-- The move relearner, the decoration menus and the museum's painting
|
||||
-- captions, through the text function each screen hands its shared base.
|
||||
package.loaded["src.ui.game3.rse.move_relearner"] = { SUB = "tutor", show = function(_, opts) return opts end }
|
||||
local tutorText = require("src.ui.game3.rs.move_relearner").show({}, {}).text
|
||||
check(tutorText("gText_TeachWhichMoveToPkmn") == "Quelle capacité apprendre ?", "the move relearner reads the cache by its label")
|
||||
check(tutorText("gOtherText_Unnamed") == "COPY", "a move relearner line missing from the cache keeps the pack's copy")
|
||||
BUNDLE.text.gOtherText_TeachWhichMove = ir("Autre texte")
|
||||
check(tutorText("gText_TeachWhichMoveToPkmn") == "Quelle capacité apprendre ?", "a screen resolves its text once while it is open")
|
||||
tutorText = require("src.ui.game3.rs.move_relearner").show({}, {}).text
|
||||
check(tutorText("gText_TeachWhichMoveToPkmn") == "Autre texte", "and again when it opens")
|
||||
|
||||
package.loaded["src.ui.game3.rse.decoration"] = { open = function(opts) return opts end }
|
||||
package.loaded["src.core.game3.rse.decoration"] = { manifest = function()
|
||||
return { textBytes = { gSecretBaseText_DecorReturned = COPY, gSecretBaseText_NoDecor = COPY }, strings = {} }
|
||||
end }
|
||||
package.loaded["src.core.game3.rse.decoration_inventory"] = { categoryName = function() return "" end }
|
||||
local decorText = require("src.ui.game3.rs.decoration").open().text
|
||||
BUNDLE.text = { gSecretBaseText_DecorReturned = ir("La décoration est retournée au PC.") }
|
||||
check(decorText("gText_DecorationReturnedToPC") == "La décoration est retournée au PC.", "the decoration menus read the cache by their labels")
|
||||
check(decorText("gText_NoDecorationHere") == "COPY", "a decoration line missing from the cache keeps the pack's copy")
|
||||
|
||||
package.loaded["src.ui.game3.rse.contest_painting"] = { ID = "contest_painting", SUB = "contest_painting" }
|
||||
local Painting = require("src.ui.game3.rs.contest_painting")
|
||||
local PAINT = { captionLayout = { museumStart = 5, nicknameBytes = 10 },
|
||||
captionParts = { [0] = { prefix = "gContestPaintingCool1", suffix = "gContestPaintingCool2" } },
|
||||
textBytes = { gContestPaintingCool1 = COPY, gContestPaintingCool2 = COPY } }
|
||||
BUNDLE.text = { gContestPaintingCool1 = ir("Le POKéMON ") }
|
||||
check(Painting.caption(5, { nickname = "ZIGZATON", contestCategory = 0 }, nil, PAINT) == "Le POKéMON ZIGZATONCOPY",
|
||||
"a painting's caption reads the cache by its labels, the pack's copy where the cache has none")
|
||||
-- pokeruby/src/contest_painting.c:234: the European carts name the POKéMON
|
||||
-- first ("ZIGZATON von MAY"), the US and Japanese ones the trainer.
|
||||
PAINT.rankNames = { [0] = "gContestRankNormal" }
|
||||
PAINT.hallCaption, PAINT.hallPossessive = "gContestText_ContestWinner", "gOtherText_Unknown1"
|
||||
PAINT.captionLayout.hallLatinControl = {}
|
||||
PAINT.textBytes.gContestRankNormal, PAINT.textBytes.gContestText_ContestWinner, PAINT.textBytes.gOtherText_Unknown1 = COPY, COPY, COPY
|
||||
local winner = { nickname = "ZIGZATON", trainerName = "MAY", contestCategory = 0 }
|
||||
BUNDLE.text = { gContestRankNormal = ir("NORMAL "), gContestText_ContestWinner = ir("WINNER "), gOtherText_Unknown1 = ir("'s ") }
|
||||
check(Painting.caption(0, winner, nil, PAINT) == "NORMAL WINNER MAY's ZIGZATON", "the US hall caption names the trainer first")
|
||||
BUNDLE.text.gOtherText_Unknown1 = ir(" von ")
|
||||
check(Painting.caption(0, winner, nil, PAINT) == "NORMAL WINNER ZIGZATON von MAY", "a European hall caption names the POKéMON first")
|
||||
|
||||
if failed > 0 then
|
||||
print(failed .. " check(s) failed")
|
||||
os.exit(1)
|
||||
|
||||
Reference in New Issue
Block a user