diff --git a/docs/modding/reference/registries.md b/docs/modding/reference/registries.md index abfcc4e5..444acc26 100644 --- a/docs/modding/reference/registries.md +++ b/docs/modding/reference/registries.md @@ -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 | diff --git a/src/core/gen2/PokedexText.lua b/src/core/gen2/PokedexText.lua index f25379ae..3caf1762 100644 --- a/src/core/gen2/PokedexText.lua +++ b/src/core/gen2/PokedexText.lua @@ -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 diff --git a/src/mods/Schemas.lua b/src/mods/Schemas.lua index ba37d848..626a6740 100644 --- a/src/mods/Schemas.lua +++ b/src/mods/Schemas.lua @@ -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), diff --git a/src/ui/gen2/PokedexMenu.lua b/src/ui/gen2/PokedexMenu.lua index c8912cd1..5f8dcb23 100644 --- a/src/ui/gen2/PokedexMenu.lua +++ b/src/ui/gen2/PokedexMenu.lua @@ -64,6 +64,8 @@ local CANCEL_LABEL = Strings.source("CANCEL") local NO_SEARCH_RESULTS = Strings.source("No 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 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 diff --git a/tests/engine/pokedex_metric_units_test.lua b/tests/engine/pokedex_metric_units_test.lua index eb187af3..fbcade1f 100644 --- a/tests/engine/pokedex_metric_units_test.lua +++ b/tests/engine/pokedex_metric_units_test.lua @@ -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")