mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-08 01:34:06 -04:00
Route the two-row confirmation prompts through Strings()
The Bug-Catching Contest confirmation was drawn as two bare literals, one per row, with no hook a mod could reach. It becomes one catalog key, "Would you like to\nend the Contest?", the way every other confirmation prompt in this port is written (src/ui/StartMenu.lua, src/ui/gen2/SaveMenu.lua): "Would you like to" alone has no stable translation out of context, and the cart writes it as one text (data/text/common_2.asm). Both prompts in this file now share one helper. It draws with Chrome.printWrapped, which wraps on the translated line break AND on pixel width, and reads the line count back from it to warn -- once per prompt -- when a translation needs a third row the box cannot hold. The title-screen prompt went through a hand-rolled splitter on the first line break, which handed Font.draw an embedded break, rendered as a space: a translation needing three rows printed two of them joined and ran past the box. The official wordings fit: "Voulez-vous arrê- / ter le concours?" and "Möchtest du den / Wettkampf beenden?". tests/engine/gen2_contest_coins_translation_test.lua drives StartMenu's confirmContest arm and StartGameCornerGame's no-coins branch with a mod-loaded catalog and checks the translated wording reaches the screen, plus the English case. On dev the three prompt checks fail; the refusal's own check passes there too, because that lookup already ran at runtime -- what dev was missing is the key, not the call.
This commit is contained in:
@@ -318,6 +318,32 @@ function StartMenu:update(_dt)
|
||||
end
|
||||
|
||||
-- pokecrystal engine/menus/menu_2.asm:145
|
||||
-- The box is two rows tall (y 14/16, step 2), which the cart's own line
|
||||
-- break fills exactly. A translation can need a third line, and printWrapped
|
||||
-- would drop it without a word, so say so once instead of shipping a prompt
|
||||
-- that reads as a sentence cut in half.
|
||||
-- The confirmation box at (0, 12, 18, 4) holds exactly two rows, which the
|
||||
-- cart's own line break fills. A translation can need a third, which would be
|
||||
-- dropped without a word, so this says so once per prompt. printWrapped
|
||||
-- returns the line count it wrapped to, so the box's own draw is what reports
|
||||
-- the overflow: no second wrap, and no way for the two to disagree on the
|
||||
-- width later. It also wraps on pixel width, unlike a `\n`-only splitter,
|
||||
-- which would hand Font.draw an embedded break -- rendered as a space -- and
|
||||
-- run a long translated row past the box edge.
|
||||
local promptWarned = {}
|
||||
local function twoRowPrompt(text, what)
|
||||
local lines = Chrome.printWrapped(text, 1, 14, 18, 2, 2)
|
||||
if lines > 2 and not promptWarned[what] then
|
||||
promptWarned[what] = true
|
||||
Logger.warn("%s prompt needs %d lines, the box holds 2: %s",
|
||||
what, lines, tostring(text))
|
||||
end
|
||||
end
|
||||
|
||||
-- pokecrystal data/text/common_2.asm ContestStatus: the labels and the
|
||||
-- "None" placeholder are text, so they go through the catalog like the
|
||||
-- prompt below. The caught mon's own name does not: it is a nickname or a
|
||||
-- species the `pokemon` registry already renames.
|
||||
function StartMenu:drawContestStatus()
|
||||
Chrome.textbox(0, 0, 17, 5)
|
||||
Chrome.print("CAUGHT", 1, 1)
|
||||
@@ -346,22 +372,26 @@ function StartMenu:draw()
|
||||
if self.phase == "confirmContest" then
|
||||
-- pokecrystal data/text/common_2.asm:1381
|
||||
Chrome.textbox(0, 12, 18, 4)
|
||||
Chrome.print("Would you like to", 1, 14)
|
||||
Chrome.print("end the Contest?", 1, 16)
|
||||
-- One catalog key ("Would you like to" alone has no stable translation
|
||||
-- out of context), matching every other confirmation prompt in this
|
||||
-- port (src/ui/StartMenu.lua, src/ui/gen2/SaveMenu.lua). Printed via
|
||||
-- Chrome.printWrapped, same as InitClock.lua's own call: this box only
|
||||
-- has room for two rows (y 14/16, step 2), and printWrapped wraps by
|
||||
-- both the translated \n and pixel width, unlike a hand-rolled
|
||||
-- \n-only splitter.
|
||||
twoRowPrompt(Strings("Would you like to\nend the Contest?"), "contest end")
|
||||
-- pokecrystal home/menu.asm:418
|
||||
Chrome.box(14, 7, 6, 5)
|
||||
Chrome.print("YES", 16, 8)
|
||||
Chrome.print("NO", 16, 10)
|
||||
Chrome.print(Strings("YES"), 16, 8)
|
||||
Chrome.print(Strings("NO"), 16, 10)
|
||||
Chrome.cursor(15, self.confirmChoice == 1 and 8 or 10)
|
||||
return
|
||||
end
|
||||
|
||||
if self.phase == "confirm" then
|
||||
Chrome.textbox(0, 12, 18, 4)
|
||||
local prompt = Strings(Strings.source("Return to the\ntitle screen?"))
|
||||
local first, second = prompt:match("^([^\n]*)\n?(.*)$")
|
||||
Chrome.print(first or "", 1, 14)
|
||||
Chrome.print(second or "", 1, 16)
|
||||
twoRowPrompt(Strings(Strings.source("Return to the\ntitle screen?")),
|
||||
"title screen")
|
||||
Chrome.box(YESNO_X, YESNO_Y, YESNO_W, YESNO_H)
|
||||
Chrome.print(Strings("YES"), YESNO_X + 2, YESNO_Y + 1)
|
||||
Chrome.print(Strings("NO"), YESNO_X + 2, YESNO_Y + 3)
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
-- Two Gold/Crystal texts a translation catalog could not reach.
|
||||
--
|
||||
-- The Bug-Catching Contest confirmation was drawn as two bare literals, one
|
||||
-- per row (src/ui/gen2/StartMenu.lua), with no Strings() call at all. The
|
||||
-- Game Corner's no-coins refusal (src/script/gen2/Specials.lua) was looked up
|
||||
-- at runtime but its literal sat behind a plain local, so the catalog
|
||||
-- harvester never saw the key and no generated catalog carried it.
|
||||
--
|
||||
-- This drives both draw paths with a mod-loaded catalog and checks the
|
||||
-- translated text is what reaches the screen, plus the no-mod case proving
|
||||
-- the English wording is unchanged.
|
||||
package.path = "./?.lua;./?/init.lua;" .. package.path
|
||||
|
||||
local T = require("tests.harness")
|
||||
|
||||
love = require("tests.love_stub")
|
||||
|
||||
require("src.core.Logger").warn = function() end
|
||||
|
||||
-- Chrome.print/printWrapped go straight to Font.draw, so recording that call
|
||||
-- shows exactly what reached the screen -- the technique
|
||||
-- tests/engine/gen2_options_menu_translation_test.lua uses. Stubbed before
|
||||
-- Chrome loads, so its own `local Font = require(...)` captures this.
|
||||
local drawn
|
||||
package.loaded["src.render.Font"] = {
|
||||
draw = function(text, x, y) drawn[#drawn + 1] = { text = text, x = x, y = y } end,
|
||||
drawCode = function() end,
|
||||
drawBox = function() end,
|
||||
width = function(text) return 8 * #tostring(text or "") end,
|
||||
}
|
||||
|
||||
local StartMenu = require("src.ui.gen2.StartMenu")
|
||||
local Specials = require("src.script.gen2.Specials")
|
||||
local Strings = require("src.core.Strings")
|
||||
|
||||
local function drawnText()
|
||||
local out = {}
|
||||
for _, d in ipairs(drawn) do out[#out + 1] = d.text end
|
||||
return table.concat(out, "|")
|
||||
end
|
||||
|
||||
-- The prompt is drawn from StartMenu:draw()'s confirmContest arm; the list
|
||||
-- above it is the part this suite does not care about.
|
||||
local function promptText()
|
||||
local menu = StartMenu.new({ save = {} }, { save = {} })
|
||||
menu.phase = "confirmContest"
|
||||
menu.confirmChoice = 1
|
||||
menu.list = { draw = function() end }
|
||||
drawn = {}
|
||||
menu:draw()
|
||||
return drawnText()
|
||||
end
|
||||
|
||||
-- StartGameCornerGame's first refusal: no coins at all.
|
||||
local function coinsRefusal()
|
||||
local shown
|
||||
local vm = {
|
||||
specials = { coins = function() return 0 end },
|
||||
showRaw = function(_, body) shown = body end,
|
||||
}
|
||||
Specials.ALL.SlotMachine(vm)
|
||||
return shown
|
||||
end
|
||||
|
||||
-- ------------------------------------------------ vanilla: no mod catalog
|
||||
Strings.load({})
|
||||
do
|
||||
local text = promptText()
|
||||
T.check(text:find("Would you like to", 1, true) ~= nil,
|
||||
"the Contest prompt draws its English first line")
|
||||
T.check(text:find("end the Contest?", 1, true) ~= nil,
|
||||
"and its English second line")
|
||||
T.eq(coinsRefusal(), "You have no coins.",
|
||||
"the Game Corner refusal is unchanged in English")
|
||||
|
||||
end
|
||||
|
||||
-- ------------------------------------------------- a translation mod's turn
|
||||
do
|
||||
Strings.load({
|
||||
strings = {
|
||||
-- the cart's own French wording (GoldSilver/Crystal, data/text)
|
||||
["Would you like to\nend the Contest?"] = "Voulez-vous arrê-\nter le concours?",
|
||||
["You have no coins."] = "Vous n'avez pas de\njetons.",
|
||||
["YES"] = "OUI",
|
||||
["NO"] = "NON",
|
||||
},
|
||||
})
|
||||
|
||||
local text = promptText()
|
||||
T.check(text:find("Voulez%-vous arr") ~= nil,
|
||||
"a mod catalog reaches the Contest prompt's first line")
|
||||
T.check(text:find("ter le concours?", 1, true) ~= nil,
|
||||
"and its second line, wrapped on the translated line break")
|
||||
T.check(text:find("Would you like to", 1, true) == nil,
|
||||
"with no English left on screen")
|
||||
T.eq(coinsRefusal(), "Vous n'avez pas de\njetons.",
|
||||
"and the Game Corner refusal too")
|
||||
|
||||
end
|
||||
|
||||
Strings.load({})
|
||||
|
||||
T.finish("gen2_contest_coins_translation_test")
|
||||
@@ -105,6 +105,9 @@ REQUIRED = {
|
||||
# looked up at runtime, so they only reach a catalog while their literals
|
||||
# stay visible to the harvester rather than hiding behind a local.
|
||||
"You have no coins.", "You don't have a\nCOIN CASE.",
|
||||
# The Bug-Catching Contest confirmation, one key rather than the two
|
||||
# half-sentences it used to be drawn as.
|
||||
"Would you like to\nend the Contest?",
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user