Print Gold and Silver's Pokédex heights and weights in metric units

The #DEX page prints the US cart's height in feet and inches, with the foot and inch tiles, and its weight in pounds; the localized carts print metres and kilograms ("TAI  ???m", "PDS  ???kg"). A mod can now give a species its metric height and weight the way it can on Red/Blue: mod.content.pokemon:patch(id, { dexEntry = { heightM = ..., weightKg = ... } }). src/core/gen2/PokedexText.lua copies them onto the #DEX entry beside the cart's own values, and the page then prints them with one decimal and a comma, right-aligned before the "m" and "kg" labels, "???" until the species is caught; the printout draws the same body, and the plain page drawn without the cache's dex sheet prints the metric values as it prints the imperial ones. The Gen 2 pokemon schema declares the dexEntry fields the #DEX page reads.

The Pokédex resolves the "m" and "kg" labels when it opens (PokedexMenu.new) rather than on every frame.
This commit is contained in:
thibautbus
2026-10-07 17:29:17 +02:00
parent 20a0fc65cd
commit 722c2fc45e
5 changed files with 87 additions and 21 deletions
+1
View File
@@ -941,6 +941,7 @@ do not.
| `catchRate` | integer 0..255 | yes |
| `cry` | cries id | no |
| `dex` | integer >= 1 | yes |
| `dexEntry` | {heightM?, kind?, text?, text2?, weightKg?} | no |
| `eggGroups` | list of string | no |
| `eggGroupsRaw` | integer 0..255 | no |
| `eggMoves` | list of moves id | no |
+4 -1
View File
@@ -26,10 +26,13 @@ function PokedexText.apply(data)
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 and (override.kind or override.text or override.text2 or override.heightM) 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
if override.heightM and override.weightKg then
entry.heightM, entry.weightKg = override.heightM, override.weightKg
end
count = count + 1
end
end
+3
View File
@@ -1809,6 +1809,9 @@ R.pokemon = {
genderRatio = f.opt(f.int(0, 255)),
-- the two wild held items, in the ROM's own order (rare then common)
items = f.opt(f.list(f.id("items"))),
dexEntry = f.opt(f.rec{ kind = f.opt(f.str), text = f.opt(f.str),
text2 = f.opt(f.str), heightM = f.opt(f.num),
weightKg = f.opt(f.num) }),
spriteFront = f.path, spriteBack = f.path, picSize = f.int(1, 7),
source = f.opt(f.str),
cry = f.opt(f.id("cries")), trueColor = f.opt(f.bool),
+42 -20
View File
@@ -64,6 +64,8 @@ local CANCEL_LABEL = Strings.source("CANCEL")
local NO_SEARCH_RESULTS = Strings.source("No <PK><MN> found!")
local ENTRY_ACTION_LABEL = Strings.source(" PAGE AREA CRY PRNT")
local POUND_LABEL = Strings.source("lb")
local METRE_LABEL = Strings.source("m")
local KILOGRAM_LABEL = Strings.source("kg")
local NEST_TITLE = Strings.source("%s'S NEST")
local LIST_DIRS = { "up", "down" }
@@ -173,6 +175,7 @@ function PokedexMenu.new(game, opts)
local self = setmetatable({}, PokedexMenu)
self.game = game
self.save = opts.save or (game and game.save)
self.metricLabels = { Strings(METRE_LABEL), Strings(KILOGRAM_LABEL) }
local data = game and game.data or {}
-- engine/pokedex/pokedex.asm:447
self.data = data
@@ -641,6 +644,10 @@ function PokedexMenu:border(tx, ty, interiorRows, interiorCols)
self:tile(B.bottomRight, tx + interiorCols + 1, bottom)
end
local function metricString(value)
return (("%.1f"):format(value or 0):gsub("%.", ","))
end
-- PrintNum: a right-aligned field of `digits` characters, space-padded unless
-- PRINTNUM_LEADINGZEROS was set. `before` splits the field into an integer
-- part and a fraction with a '.' between them.
@@ -1041,26 +1048,36 @@ function PokedexMenu:drawEntryBody(row, entry)
-- "HT ?'??"" at (9,7) and "WT ???lb" at (9,9).
self:text(Strings(HEIGHT_LABEL), 9, 7)
self:text(Strings(WEIGHT_LABEL), 9, 9)
self:tile(TILE_FOOT, 14, 7)
self:text(Strings(POUND_LABEL), 17, 9)
if entry.heightM then
self:text(self.metricLabels[1], 17, 7)
self:text(self.metricLabels[2], 17, 9)
local height = row.caught and metricString(entry.heightM) or "???"
local weight = row.caught and metricString(entry.weightKg) or "???"
self:text(height, 17 - #height, 7)
self:text(weight, 17 - #weight, 9)
if not row.caught then return end
else
self:tile(TILE_FOOT, 14, 7)
self:text(Strings(POUND_LABEL), 17, 9)
if not row.caught then
self:text(" ?", 11, 7)
self:text("??", 15, 7)
if not row.caught then
self:text(" ?", 11, 7)
self:text("??", 15, 7)
self:tile(TILE_INCH, 17, 7)
self:text(" ???", 11, 9)
return
end
-- The height word is four digits with two in front of the point and the
-- point replaced by the foot mark; the weight word is five with four in
-- front. Both are already the digits the cart prints.
local height = printNumString(entry.height or 0, 4, false, 2)
self:text(height:sub(1, 2), 12, 7)
self:text(height:sub(4), 15, 7)
self:tile(TILE_INCH, 17, 7)
self:text(" ???", 11, 9)
return
self:text(printNumString(entry.weight or 0, 5, false, 4), 11, 9)
end
-- The height word is four digits with two in front of the point and the
-- point replaced by the foot mark; the weight word is five with four in
-- front. Both are already the digits the cart prints.
local height = printNumString(entry.height or 0, 4, false, 2)
self:text(height:sub(1, 2), 12, 7)
self:text(height:sub(4), 15, 7)
self:tile(TILE_INCH, 17, 7)
self:text(printNumString(entry.weight or 0, 5, false, 4), 11, 9)
-- Page marker, then the description. ClearBox(2,11) is 5 rows by 18
-- columns and <NEXT> steps two rows, so the three lines land on 11/13/15.
self:tile(TILE_PAGE_TOP, 1, 9)
@@ -1114,10 +1131,15 @@ function PokedexMenu:drawPlain()
Chrome.print(("%s %s"):format(
Chrome.number(entry.dex or 0, 3, true), self:monName(row.species)), 1, 1)
Chrome.print(entry.kind or "", 1, 3)
Chrome.print(Strings(HEIGHT_LABEL) .. " "
.. printNumString(entry.height or 0, 4, false, 2), 1, 5)
Chrome.print(Strings(WEIGHT_LABEL) .. " "
.. printNumString(entry.weight or 0, 5, false, 4), 1, 7)
if entry.heightM then
Chrome.print(Strings(HEIGHT_LABEL) .. " " .. metricString(entry.heightM) .. self.metricLabels[1], 1, 5)
Chrome.print(Strings(WEIGHT_LABEL) .. " " .. metricString(entry.weightKg) .. self.metricLabels[2], 1, 7)
else
Chrome.print(Strings(HEIGHT_LABEL) .. " "
.. printNumString(entry.height or 0, 4, false, 2), 1, 5)
Chrome.print(Strings(WEIGHT_LABEL) .. " "
.. printNumString(entry.weight or 0, 5, false, 4), 1, 7)
end
self:drawPic(row, 12, 1, true)
Chrome.box(0, 10, 20, 8)
local ty = 11
@@ -39,4 +39,41 @@ check(has("???") and has("lb") and not has("GR. ???m"), "an entry without metric
Font.draw = fontDraw
local PokedexText = require("src.core.gen2.PokedexText")
local data = {
gen2Pokedex = { entries = { CHIKORITA = { dex = 152, kind = "LEAF", height = 211, weight = 141 } } },
pokemon = { CHIKORITA = { dexEntry = { heightM = 0.9, weightKg = 6.4 } } },
}
PokedexText.apply(data)
local entry = data.gen2Pokedex.entries.CHIKORITA
check(entry.heightM == 0.9 and entry.weightKg == 6.4 and entry.height == 211,
"a mod's metric values reach the #DEX entry beside the US cart's")
local PokedexMenu = require("src.ui.gen2.PokedexMenu")
local texts, tiles
local menu = setmetatable({ page = 1, metricLabels = { "m", "kg" } }, { __index = PokedexMenu })
function menu:text(str, tx, ty) texts[#texts + 1] = { tostring(str), tx, ty } end
function menu:tile(id, tx, ty) tiles[#tiles + 1] = { id, tx, ty } end
for _, name in ipairs({ "fill", "border", "blank", "drawPic", "drawFootprint" }) do menu[name] = function() end end
function menu:cursorVisible() return false end
function menu:monName() return "CHIKORITA" end
local function at(str, tx, ty)
for _, t in ipairs(texts) do if t[1] == str and t[2] == tx and t[3] == ty then return true end end
return false
end
texts, tiles = {}, {}
menu:drawEntryBody({ species = "CHIKORITA", caught = true }, entry)
check(at("0,9", 14, 7) and at("m", 17, 7) and at("6,4", 14, 9) and at("kg", 17, 9),
"a caught Gen 2 entry prints its metric height and weight right-aligned before the unit")
local footTile = false
for _, t in ipairs(tiles) do if t[2] == 14 and t[3] == 7 then footTile = true end end
check(not footTile and not at("lb", 17, 9), "a metric Gen 2 entry prints neither the foot mark nor the pound label")
texts, tiles = {}, {}
menu:drawEntryBody({ species = "CHIKORITA", caught = false }, entry)
check(at("???", 14, 7) and at("???", 14, 9), "a seen Gen 2 entry prints the metric unknown masks")
texts, tiles = {}, {}
menu:drawEntryBody({ species = "CHIKORITA", caught = true },
{ dex = 152, kind = "LEAF", height = 211, weight = 141 })
check(at("lb", 17, 9) and not at("m", 17, 7), "an entry without metric values keeps the US fields")
T.finish("pokedex metric units")