mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-13 17:00:58 +02:00
77 lines
2.9 KiB
Lua
77 lines
2.9 KiB
Lua
-- Generic bordered list menu with the blinking ▶ cursor.
|
|
-- items: { { label=..., onSelect=function }, ... }
|
|
-- Pops itself on B (unless cancelable=false); also on START only when
|
|
-- opts.startCloses is set -- pokered's wMenuWatchedKeys mask varies per
|
|
-- menu and only the start menu's adds PAD_START.
|
|
|
|
local Font = require("src.render.Font")
|
|
local Theme = require("src.ui.Theme")
|
|
|
|
local Menu = {}
|
|
Menu.__index = Menu
|
|
|
|
function Menu.new(game, items, opts)
|
|
local self = setmetatable({}, Menu)
|
|
opts = opts or {}
|
|
self.game = game
|
|
self.items = items
|
|
self.index = 1
|
|
self.tx = opts.tx or 10
|
|
self.ty = opts.ty or 0
|
|
self.tw = opts.tw or 10
|
|
self.th = opts.th or (#items * 2 + 2)
|
|
self.cancelable = opts.cancelable ~= false
|
|
-- Whether START closes the menu. In pokered a menu responds only to the
|
|
-- keys in its wMenuWatchedKeys mask; the common PAD_A | PAD_B (and the
|
|
-- list menu's PAD_A | PAD_B | PAD_SELECT) masks leave START unwatched, so
|
|
-- only menus whose real mask includes PAD_START -- the start menu
|
|
-- (engine/menus/draw_start_menu.asm) -- opt in here.
|
|
self.startCloses = opts.startCloses or false
|
|
self.onCancel = opts.onCancel
|
|
-- BIT_NO_MENU_BUTTON_SOUND (wMiscFlags): the PC session runs its
|
|
-- menus silent (home/window.asm HandleMenuInput_)
|
|
self.noSound = opts.noSound or false
|
|
return self
|
|
end
|
|
|
|
function Menu:update(dt)
|
|
local input = self.game.input
|
|
if input:wasPressed("up") then
|
|
self.index = self.index > 1 and self.index - 1 or #self.items
|
|
elseif input:wasPressed("down") then
|
|
self.index = self.index < #self.items and self.index + 1 or 1
|
|
elseif input:wasPressed("a") then
|
|
-- HandleMenuInput_ (home/window.asm): SFX_PRESS_AB on every A press
|
|
if not self.noSound then
|
|
require("src.core.Sound").play(self.game.data, "Press_AB")
|
|
end
|
|
local item = self.items[self.index]
|
|
-- keepOpen entries run without closing the menu (e.g. the
|
|
-- Pokédex CRY option keeps the side menu up)
|
|
if not item.keepOpen then self.game.stack:pop() end
|
|
if item.onSelect then item.onSelect() end
|
|
elseif self.cancelable and (input:wasPressed("b")
|
|
or (self.startCloses and input:wasPressed("start"))) then
|
|
-- HandleMenuInput_ returns for any watched key, but only replays
|
|
-- SFX_PRESS_AB for the PAD_A | PAD_B branch -- so B beeps and START
|
|
-- (when watched, e.g. the start menu) closes silently.
|
|
if input:wasPressed("b") and not self.noSound then
|
|
require("src.core.Sound").play(self.game.data, "Press_AB")
|
|
end
|
|
self.game.stack:pop()
|
|
if self.onCancel then self.onCancel() end
|
|
end
|
|
end
|
|
|
|
function Menu:draw()
|
|
Font.drawBox(self.tx, self.ty, self.tw, self.th)
|
|
love.graphics.setColor(0, 0, 0, 1)
|
|
for i, item in ipairs(self.items) do
|
|
Font.draw(item.label, (self.tx + 2) * 8, (self.ty + i * 2 - 1) * 8)
|
|
end
|
|
Font.drawCode(Theme.cursor, (self.tx + 1) * 8, (self.ty + self.index * 2 - 1) * 8)
|
|
love.graphics.setColor(1, 1, 1, 1)
|
|
end
|
|
|
|
return Menu
|