-- PC storage: 12 boxes of 20 (engine/pokemon/bills_pc.asm semantics via -- src/pokemon/Boxes.lua): withdraw from / deposit to the current box, -- plus CHANGE BOX. local Boxes = require("src.pokemon.Boxes") local Font = require("src.render.Font") local ListMenu = require("src.ui.ListMenu") local Menu = require("src.ui.Menu") local Party = require("src.pokemon.Party") local TextBox = require("src.render.TextBox") local BoxMenu = {} local function monLabel(game, mon) local def = game.data.pokemon[mon.species] return ("%s :L%d"):format(mon.nickname or def.name, mon.level) end local function monName(game, mon) local def = game.data.pokemon[mon.species] return mon.nickname or def.name end -- Per-mon submenu (bills_pc.asm DisplayDepositWithdrawMenu): the chosen -- action + STATS + CANCEL. STATS shows the status screen and returns -- here; CANCEL/B goes back to the list. local function monSubmenu(game, action, mon, onAction) game.stack:push(Menu.new(game, { { label = action, onSelect = onAction }, { label = "STATS", keepOpen = true, onSelect = function() require("src.ui.Screens").push(game, "SummaryMenu", mon) end, }, { label = "CANCEL" }, }, { tx = 9, ty = 10, tw = 11, th = 8, noSound = true })) end -- After a successful transfer: close the mon list (BoxMenu stays beneath -- via keepOpen) and show the taken-out / stored text (jp BillsPCMenu). local function afterTransfer(game, list, text) list:close() game.stack:push(TextBox.new(game, text)) end local function withdraw(game) local box = Boxes.active(game.save) local t = game.data.text if #box == 0 then game.stack:push(TextBox.new(game, t._NoMonText or "What? There are\nno POKéMON here!")) return end if #game.save.party >= Party.MAX then game.stack:push(TextBox.new(game, t._CantTakeMonText or "You can't take\nany more POKéMON.\fDeposit POKéMON\nfirst.")) return end local items = {} for i, mon in ipairs(box) do table.insert(items, { label = monLabel(game, mon), value = i }) end game.stack:push(ListMenu.new(game, ("BOX %d (WITHDRAW)"):format(game.save.currentBox), items, { onChoose = function(item, list) local mon = box[item.value] if not mon then return end monSubmenu(game, "WITHDRAW", mon, function() if #game.save.party >= Party.MAX then list.footer = "The party is full!" return end table.remove(box, item.value) table.insert(game.save.party, mon) local name = monName(game, mon) game.stringBuffer = name require("src.core.Sound").playCry(game.data, mon.species) afterTransfer(game, list, t._MonIsTakenOutText or (name .. " is\ntaken out.\vGot " .. name .. ".")) end) end, })) end local function deposit(game) local t = game.data.text if #game.save.party <= 1 then game.stack:push(TextBox.new(game, t._CantDepositLastMonText or "You can't deposit\nthe last POKéMON!")) return end local box = Boxes.active(game.save) if #box >= Boxes.CAPACITY then game.stack:push(TextBox.new(game, t._BoxFullText or "Oops! This Box is\nfull of POKéMON.")) return end local items = {} for i, mon in ipairs(game.save.party) do table.insert(items, { label = monLabel(game, mon), value = i }) end game.stack:push(ListMenu.new(game, "PARTY (DEPOSIT)", items, { onChoose = function(item, list) local mon = game.save.party[item.value] if not mon then return end monSubmenu(game, "DEPOSIT", mon, function() if #game.save.party <= 1 then list.footer = "You need at least\none POKéMON!" return end local active = Boxes.active(game.save) if #active >= Boxes.CAPACITY then list.footer = ("BOX %d is full!"):format(game.save.currentBox) return end table.remove(game.save.party, item.value) table.insert(active, mon) local name = monName(game, mon) game.stringBuffer = name game.boxNumString = tostring(game.save.currentBox) require("src.core.Sound").playCry(game.data, mon.species) afterTransfer(game, list, t._MonWasStoredText or (name .. " was\nstored in Box " .. game.boxNumString .. ".")) end) end, })) end -- RELEASE POKéMON (bills_pc.asm BillsPCRelease): confirm, then "Bye [MON]!". -- Index by list.index (not stale item.value) after removeCurrent (#171). local function release(game) local box = Boxes.active(game.save) local t = game.data.text if #box == 0 then game.stack:push(TextBox.new(game, t._NoMonText or "What? There are\nno POKéMON here!")) return end local items = {} for i, mon in ipairs(box) do table.insert(items, { label = monLabel(game, mon), value = i }) end game.stack:push(ListMenu.new(game, ("BOX %d (RELEASE)"):format(game.save.currentBox), items, { onChoose = function(_, list) local mon = box[list.index] if not mon then return end local name = monName(game, mon) local ChoiceBox = require("src.ui.ChoiceBox") game.stack:push(TextBox.new(game, "Once released,\n" .. name .. " is\ngone forever. OK?", function() game.stack:push(ChoiceBox.new(game, function(yes) if not yes then return end table.remove(box, list.index) require("src.core.Sound").playCry(game.data, mon.species) game.stack:push(TextBox.new(game, ("%s was\nreleased outside.\fBye %s!"):format(name, name))) list:removeCurrent() end, { defaultNo = true, noSound = true })) end)) end, })) end local function changeBox(game) local boxes = Boxes.ensure(game.save) local items = {} for i = 1, Boxes.COUNT do local mark = i == game.save.currentBox and "*" or " " table.insert(items, { label = ("%sBOX %2d"):format(mark, i), right = ("%d/%d"):format(#boxes[i], Boxes.CAPACITY), value = i, }) end game.stack:push(ListMenu.new(game, "CHANGE BOX", items, { onChoose = function(item, list) -- the original asks BEFORE switching ("When you change a #MON -- BOX, data will be saved. OK?"); declining aborts the change local ChoiceBox = require("src.ui.ChoiceBox") game.stack:push(TextBox.new(game, "When you change a\nPOKéMON BOX, data\nwill be saved. OK?", function() game.stack:push(ChoiceBox.new(game, function(yes) if not yes then return end game.save.currentBox = item.value if game.writeSave then game:writeSave() end list:close() end, { noSound = true })) end)) end, })) end -- bills_pc.asm BillsPCMenu chrome: What? text box + BOX No. overlay local function drawChrome(game) Font.drawBox(0, 12, 20, 6) love.graphics.setColor(0, 0, 0, 1) Font.draw("What?", 8, 112) Font.drawBox(9, 14, 11, 4) love.graphics.setColor(0, 0, 0, 1) Font.draw("BOX No.", 80, 128) local n = game.save.currentBox or 1 if n >= 10 then Font.draw(tostring(n), 136, 128) else Font.draw(tostring(n), 144, 128) end love.graphics.setColor(1, 1, 1, 1) end function BoxMenu.new(game) Boxes.ensure(game.save) -- bills_pc.asm BillsPCMenu: TextBoxBorder at (0,0) with interior -- 12x10 → total 14x12. "CHANGE BOX" / "WITHDRAW " need the -- full interior (cursor col + label). keepOpen so WITHDRAW/DEPOSIT/ -- RELEASE/CHANGE BOX leave this menu underneath (jp BillsPCMenu). local menu = Menu.new(game, { { label = "WITHDRAW ", keepOpen = true, onSelect = function() withdraw(game) end }, { label = "DEPOSIT ", keepOpen = true, onSelect = function() deposit(game) end }, { label = "RELEASE ", keepOpen = true, onSelect = function() release(game) end }, { label = "CHANGE BOX", keepOpen = true, onSelect = function() changeBox(game) end }, { label = "SEE YA!" }, -- Bill's PC runs silent end to end (BIT_NO_MENU_BUTTON_SOUND, -- engine/menus/pokemon_pc.asm) }, { tx = 0, ty = 0, tw = 14, th = 12, noSound = true }) local baseDraw = menu.draw function menu:draw() baseDraw(self) drawChrome(game) end return menu end return BoxMenu