Merge pull request #1024 from AverageConsumer/feature/semantic-pc-list-kinds

Mod API: expose semantic PC list kinds
This commit is contained in:
bryanthaboi
2026-08-10 14:09:01 -04:00
committed by GitHub
5 changed files with 61 additions and 0 deletions
+5
View File
@@ -300,5 +300,10 @@ update and input ownership, so a mod can mirror a native menu on another
display without reimplementing it. The default is `true`. Treat the wrapper as
a pure predicate: the renderer may ask it more than once per frame.
Scrollable list states expose `state.kind` for use with this hook. Generic
lists fall back to their title; PC lists use stable, localization-independent
identifiers: `pc_box_withdraw`, `pc_box_deposit`, `pc_box_release`,
`pc_box_change`, `pc_item_withdraw`, `pc_item_deposit`, and `pc_item_toss`.
Developer mode also arms the mod loader's dev tripwire, which flags mods
that reach outside their permission set.
+4
View File
@@ -67,6 +67,7 @@ local function withdraw(game)
game.stack:push(ListMenu.new(game,
Strings("BOX %d (WITHDRAW)", game.save.currentBox), items, {
noSound = true, -- PCMainMenu holds BIT_NO_MENU_BUTTON_SOUND (#570)
kind = "pc_box_withdraw",
onChoose = function(item, list)
local mon = box[item.value]
if not mon then return end
@@ -114,6 +115,7 @@ local function deposit(game)
end
game.stack:push(ListMenu.new(game, "PARTY (DEPOSIT)", items, {
noSound = true, -- PCMainMenu holds BIT_NO_MENU_BUTTON_SOUND (#570)
kind = "pc_box_deposit",
onChoose = function(item, list)
local mon = game.save.party[item.value]
if not mon then return end
@@ -160,6 +162,7 @@ local function release(game)
game.stack:push(ListMenu.new(game,
Strings("BOX %d (RELEASE)", game.save.currentBox), items, {
noSound = true, -- PCMainMenu holds BIT_NO_MENU_BUTTON_SOUND (#570)
kind = "pc_box_release",
onChoose = function(_, list)
local mon = box[list.index]
if not mon then return end
@@ -193,6 +196,7 @@ local function changeBox(game)
end
game.stack:push(ListMenu.new(game, "CHANGE BOX", items, {
noSound = true, -- PCMainMenu holds BIT_NO_MENU_BUTTON_SOUND (#570)
kind = "pc_box_change",
onChoose = function(item, list)
-- the original asks BEFORE switching ("When you change a #MON
-- BOX, data will be saved. OK?"); declining aborts the change
+1
View File
@@ -51,6 +51,7 @@ function ListMenu.new(game, title, items, opts)
local self = setmetatable({}, ListMenu)
self.game = game
self.title = title
self.kind = opts.kind or title
self.items = items
self.index = 1
self.scroll = 0
+3
View File
@@ -72,6 +72,7 @@ end
local function withdraw(game)
local pc = game.save.pcItems
game.stack:push(ListMenu.new(game, "WITHDRAW ITEM", buildItems(game, pc), {
kind = "pc_item_withdraw",
messageBox = true,
noSound = true, -- PlayerPCMenu holds BIT_NO_MENU_BUTTON_SOUND (#570)
onChoose = function(item, list)
@@ -110,6 +111,7 @@ local function deposit(game)
if not Bag.isBadge(id) then depositable[id] = count end
end
game.stack:push(ListMenu.new(game, "DEPOSIT ITEM", buildItems(game, depositable), {
kind = "pc_item_deposit",
messageBox = true,
noSound = true, -- PlayerPCMenu holds BIT_NO_MENU_BUTTON_SOUND (#570)
onChoose = function(item, list)
@@ -131,6 +133,7 @@ end
local function toss(game)
local pc = game.save.pcItems
game.stack:push(ListMenu.new(game, "TOSS ITEM", buildItems(game, pc), {
kind = "pc_item_toss",
messageBox = true,
noSound = true, -- PlayerPCMenu holds BIT_NO_MENU_BUTTON_SOUND (#570)
onChoose = function(item, list)
+48
View File
@@ -0,0 +1,48 @@
-- Stable ListMenu identities for screen.render_visible and companion UIs.
package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.modkit")
local Data = T.fixtures.load()
local SaveData = require("src.core.SaveData")
local BoxMenu = require("src.ui.BoxMenu")
local ListMenu = require("src.ui.ListMenu")
local PlayerPC = require("src.ui.PlayerPC")
local Boxes = require("src.pokemon.Boxes")
local pushed
local game = {
data = Data,
save = SaveData.newGame(),
stack = { push = function(_, state) pushed = state end },
}
local species = T.fixtures.ids.species[1]
Boxes.ensure(game.save)[1][1] = { species = species, level = 5 }
game.save.party[1] = { species = species, level = 5 }
game.save.party[2] = { species = species, level = 6 }
game.save.pcItems = { FIX_POTION = 2 }
game.save.inventory.FIX_POTION = 2
local generic = ListMenu.new(game, "VISIBLE TITLE", {}, {})
T.eq(generic.kind, "VISIBLE TITLE", "generic lists fall back to their title")
local explicit = ListMenu.new(game, "Localized title", {}, { kind = "stable_id" })
T.eq(explicit.kind, "stable_id", "explicit list kind is preserved")
local box = BoxMenu.new(game)
for i, kind in ipairs({ "pc_box_withdraw", "pc_box_deposit",
"pc_box_release", "pc_box_change" }) do
pushed = nil
box.items[i].onSelect()
T.eq(pushed and pushed.kind, kind, kind .. " is stable")
end
local items = PlayerPC.new(game)
for i, kind in ipairs({ "pc_item_withdraw", "pc_item_deposit",
"pc_item_toss" }) do
pushed = nil
items.items[i].onSelect()
T.eq(pushed and pushed.kind, kind, kind .. " is stable")
end
T.finish("pc_list_kinds")