Route the Gen2 #DEX screen's kind/text through the pokemon registry

src/ui/gen2/PokedexMenu.lua reads its KIND label and both description
pages from data.gen2Pokedex.entries, loaded straight from disk before
mods:load runs -- a separate table from data.pokemon, the `pokemon`
registry's own merge target. mod.content.pokemon:patch(id, { dexEntry =
... }) therefore validated but never reached the screen. Adds
src/core/gen2/PokedexText.lua to project a patched dexEntry onto the
#DEX table after the merge (Game2:load, alongside the other Gen 2
post-merge registries), and a text2 field to the dexEntry schema for
the entry's second description page, which the screen already reads
but the registry had no field for. Also routes the OPTION/SEARCH panel
titles (PokedexMenu.lua) through Strings(), the same literal-wrapping
pattern already used elsewhere in this screen and its siblings.
This commit is contained in:
thibautbus
2026-08-26 19:43:53 +02:00
parent 017eafc51b
commit 273350d11e
5 changed files with 59 additions and 5 deletions
+1 -1
View File
@@ -821,7 +821,7 @@ mod.content.phone_contacts:patch("PHONE_YOUNGSTER_JOEY", { map = "ROUTE_31" })
| `catchRate` | integer 0..255 | yes | | `catchRate` | integer 0..255 | yes |
| `cry` | cries id | no | | `cry` | cries id | no |
| `dex` | integer >= 1 | yes | | `dex` | integer >= 1 | yes |
| `dexEntry` | {heightFt, heightIn, heightM?, kind, text, weight, weightKg?} | no | | `dexEntry` | {heightFt, heightIn, heightM?, kind, text, text2?, weight, weightKg?} | no |
| `evolutions` | list of {item?, level?, method, species} | yes | | `evolutions` | list of {item?, level?, method, species} | yes |
| `frontSize` | integer 1..7 | yes | | `frontSize` | integer 1..7 | yes |
| `growthRate` | growth_rates id | yes | | `growthRate` | growth_rates id | yes |
+5
View File
@@ -1024,6 +1024,11 @@ function Game2:load()
require("src.core.gen2.Phone").useRegistry(self.data) require("src.core.gen2.Phone").useRegistry(self.data)
require("src.core.gen2.Decorations").useRegistry(self.data) require("src.core.gen2.Decorations").useRegistry(self.data)
require("src.core.gen2.Apricorns").useRegistry(self.data) require("src.core.gen2.Apricorns").useRegistry(self.data)
-- data.gen2Pokedex is a separate table from the `pokemon` registry's own
-- merge target (data.pokemon): a translation mod's
-- mod.content.pokemon:patch(id, { dexEntry = ... }) would otherwise never
-- reach the #DEX screen. See src/core/gen2/PokedexText.lua.
require("src.core.gen2.PokedexText").apply(self.data)
-- Rendering pipelines: the engine half of the render_pipelines registry -- Rendering pipelines: the engine half of the render_pipelines registry
-- (src/render/Pipelines.lua). install() points it at GOLD's merged dataset -- (src/render/Pipelines.lua). install() points it at GOLD's merged dataset
+39
View File
@@ -0,0 +1,39 @@
-- Projects a mod's `pokemon` registry dexEntry onto the #DEX screen's own
-- data table.
--
-- data.gen2Pokedex.entries[species] (data/generated/pokedex.lua,
-- RomExtractorGen2:extractPokedex) is what src/ui/gen2/PokedexMenu.lua
-- actually reads for the KIND label and the two description pages
-- (entry.kind, entry.text, entry.text2) -- a table loaded straight from
-- disk in Game2:load, BEFORE mods:load runs, and never routed through a
-- registry. The `pokemon` registry's own merge target is the separate
-- data.pokemon table (src/mods/Schemas.lua, R.pokemon: `target = "pokemon"`),
-- which mod.content.pokemon:patch(id, { dexEntry = { kind = ..., text = ...,
-- text2 = ... } }) already reaches -- so a translation mod's #DEX text was
-- silently invisible in-game despite validating against the registry.
--
-- This is the missing link: called once after the merge (src/core/Game2.lua),
-- the same way ItemEffects.applyHeldItems projects held_items onto
-- data.gen2HeldItems. height/weight/dex stay untouched -- game state, not
-- text a translation carries.
local PokedexText = {}
function PokedexText.apply(data)
local dex = data and data.gen2Pokedex
local pokemon = data and data.pokemon
if not (dex and dex.entries and pokemon) then return 0 end
local count = 0
for species, entry in pairs(dex.entries) do
local def = pokemon[species]
local override = def and def.dexEntry
if override and (override.kind or override.text or override.text2) then
if override.kind then entry.kind = override.kind end
if override.text then entry.text = override.text end
if override.text2 then entry.text2 = override.text2 end
count = count + 1
end
end
return count
end
return PokedexText
+5 -1
View File
@@ -826,10 +826,14 @@ R.pokemon = {
item = f.opt(f.id("items")), item = f.opt(f.id("items")),
species = f.id("pokemon") }), species = f.id("pokemon") }),
spriteFront = f.path, spriteBack = f.path, frontSize = f.int(1, 7), spriteFront = f.path, spriteBack = f.path, frontSize = f.int(1, 7),
-- text2 is the #DEX entry's second description page (Pokedex_asm's bare
-- `page` macro, engine/pokedex/pokedex.asm): PokedexMenu:drawEntryBody
-- shows `entry.text` on page 1 and `entry.text2` on page 2, so a
-- translation needs both to cover the whole entry.
dexEntry = f.opt(f.rec{ kind = f.str, heightFt = f.int(0), dexEntry = f.opt(f.rec{ kind = f.str, heightFt = f.int(0),
heightIn = f.int(0, 11), weight = f.num, heightIn = f.int(0, 11), weight = f.num,
heightM = f.opt(f.num), weightKg = f.opt(f.num), heightM = f.opt(f.num), weightKg = f.opt(f.num),
text = f.str }), text = f.str, text2 = f.opt(f.str) }),
icon = f.opt(f.union{ f.str, f.rec{ image = f.path, icon = f.opt(f.union{ f.str, f.rec{ image = f.path,
frames = f.opt(f.int(1)) } }), frames = f.opt(f.int(1)) } }),
cry = f.opt(f.id("cries")), palette = f.opt(f.id("palettes")), cry = f.opt(f.id("cries")), palette = f.opt(f.id("palettes")),
+9 -3
View File
@@ -37,6 +37,13 @@ local TileSheet = require("src.ui.gen2.TileSheet")
local Nests = require("src.core.gen2.Nests") local Nests = require("src.core.gen2.Nests")
local Sound = require("src.core.Sound") local Sound = require("src.core.Sound")
local Unown = require("src.core.gen2.Unown") local Unown = require("src.core.gen2.Unown")
local Strings = require("src.core.Strings")
-- `db $3b, " OPTION ", $3c` / `db $3b, " SEARCH ", $3c"`: the panel titles
-- drawn by drawOption/drawSearch below, declared here (rather than inline)
-- so Strings.source puts them in the catalog harvest.
local OPTION_LABEL = Strings.source(" OPTION ")
local SEARCH_LABEL = Strings.source(" SEARCH ")
local PokedexMenu = {} local PokedexMenu = {}
PokedexMenu.__index = PokedexMenu PokedexMenu.__index = PokedexMenu
@@ -776,7 +783,6 @@ function PokedexMenu:printEntry()
local row = self:current() local row = self:current()
if not row then return end if not row then return end
local Printer = require("src.core.Printer") local Printer = require("src.core.Printer")
local Strings = require("src.core.Strings")
local TextBox = require("src.render.TextBox") local TextBox = require("src.render.TextBox")
local name = (self.pokemon and self.pokemon[row.species] local name = (self.pokemon and self.pokemon[row.species]
and self.pokemon[row.species].name) or tostring(row.species) and self.pokemon[row.species].name) or tostring(row.species)
@@ -1385,7 +1391,7 @@ function PokedexMenu:drawOption()
-- `db $3b, " OPTION ", $3c`: the two end-cap tiles are the dex sheet's, not -- `db $3b, " OPTION ", $3c`: the two end-cap tiles are the dex sheet's, not
-- font glyphs. -- font glyphs.
self:tile(0x3b, 0, 1) self:tile(0x3b, 0, 1)
self:text(" OPTION ", 1, 1) self:text(Strings(OPTION_LABEL), 1, 1)
self:tile(0x3c, 9, 1) self:tile(0x3c, 9, 1)
local rows = self:optionRows() local rows = self:optionRows()
for i, row in ipairs(rows) do for i, row in ipairs(rows) do
@@ -1405,7 +1411,7 @@ function PokedexMenu:drawSearch()
self:fill(TILE_BG, 0, 0, Chrome.SCREEN_W, Chrome.SCREEN_H) self:fill(TILE_BG, 0, 0, Chrome.SCREEN_W, Chrome.SCREEN_H)
self:border(0, 2, 14, 18) self:border(0, 2, 14, 18)
self:tile(0x3b, 0, 1) self:tile(0x3b, 0, 1)
self:text(" SEARCH ", 1, 1) self:text(Strings(SEARCH_LABEL), 1, 1)
self:tile(0x3c, 9, 1) self:tile(0x3c, 9, 1)
self:text("TYPE1", 3, 4) self:text("TYPE1", 3, 4)
self:text("TYPE2", 3, 6) self:text("TYPE2", 3, 6)