Files
gen1recomp/src/ui/NamingScreen.lua
T
Andrew Quenehen efd81d8e34 fix(input): ignore raw face presses when Joy-Con is gamepad
love-nx emits gamepad+raw on one press; NamingScreen saw a+b and always
erased. Skip raw when isGamepad(); align NX Y→a/X→b; prefer A if both.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-01 04:15:47 -03:00

201 lines
6.6 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- Gen 1 letter-grid naming screen (engine/menus/naming_screen.asm).
-- Full gen-1 glyph grid (data/text/alphabets.asm): five 9-cell rows
-- ending in ED, plus a case-switch row. A picks a letter, B deletes,
-- SELECT flips case, START or the ED cell confirms. If opts.presets is
-- given, a "NEW NAME" + presets menu is shown first
-- (engine/menus/main_menu.asm name lists).
-- Pops itself from the stack, then calls opts.onDone(name).
--
-- ui.naming.grid may replace either page; keep an "ED" cell and a
-- single-cell case-switch row so confirm / case-flip keep working.
local Font = require("src.render.Font")
local Runtime = require("src.mods.Runtime")
local Sound = require("src.core.Sound")
local Theme = require("src.ui.Theme")
local Strings = require("src.core.Strings")
local NamingScreen = {}
NamingScreen.__index = NamingScreen
NamingScreen.isOpaque = true
-- SGB: generic whole-screen palette (SET_PAL_GENERIC)
function NamingScreen:sgbPalettes(game)
return require("src.render.PaletteFX").wholeNamed(game.data, "MEWMON")
end
-- both letter pages (wAlphabetCase, data/text/alphabets.asm): row 6 is
-- the case-switch cell, labelled with the page it flips to
local GRID_UPPER = {
{ "A", "B", "C", "D", "E", "F", "G", "H", "I" },
{ "J", "K", "L", "M", "N", "O", "P", "Q", "R" },
{ "S", "T", "U", "V", "W", "X", "Y", "Z", " " },
{ "×", "(", ")", ":", ";", "[", "]", "<PK>", "<MN>" },
{ "-", "?", "!", "", "", "/", ".", ",", "ED" },
{ "lower case" },
}
local GRID_LOWER = {
{ "a", "b", "c", "d", "e", "f", "g", "h", "i" },
{ "j", "k", "l", "m", "n", "o", "p", "q", "r" },
{ "s", "t", "u", "v", "w", "x", "y", "z", " " },
{ "×", "(", ")", ":", ";", "[", "]", "<PK>", "<MN>" },
{ "-", "?", "!", "", "", "/", ".", ",", "ED" },
{ "UPPER CASE" },
}
-- locate the ED confirm cell and the case-switch row on a (possibly
-- modded) grid; falls back to vanilla coordinates
local function findMeta(grid)
local caseRow, edRow, edCol = #grid, 5, 9
for r, row in ipairs(grid) do
if #row == 1 and (row[1] == "lower case" or row[1] == "UPPER CASE"
or row[1] == "lower" or row[1] == "UPPER") then
caseRow = r
end
for c, cell in ipairs(row) do
if cell == "ED" then edRow, edCol = r, c end
end
end
return caseRow, edRow, edCol
end
local function sameGrid(grid) return grid end
function NamingScreen.new(game, opts)
opts = opts or {}
local self = setmetatable({}, NamingScreen)
self.game = game
self.title = opts.title or Strings("YOUR NAME?")
self.presets = opts.presets
self.maxLen = opts.maxLen or 7
self.default = opts.default
self.onDone = opts.onDone
self.glyphs = {} -- typed glyphs; multi-byte cells (<PK>, ♂, ×) count as 1
self.row, self.col = 1, 1
self.lower = false
return self
end
function NamingScreen:enter()
if self.presets and #self.presets > 0 then
local Menu = require("src.ui.Menu")
local items = { { label = Strings("NEW NAME") } }
for _, preset in ipairs(self.presets) do
table.insert(items, {
label = preset,
onSelect = function()
-- the menu already popped itself; pop the naming screen too
self.game.stack:pop()
if self.onDone then self.onDone(preset) end
end,
})
end
self.game.stack:push(Menu.new(self.game, items, {
tx = 4, ty = 0, tw = 12, th = #items * 2 + 2, cancelable = false,
}))
end
end
function NamingScreen:confirm()
local name = table.concat(self.glyphs)
if name == "" then
name = (self.presets and self.presets[1]) or self.default or "A"
end
Sound.play(self.game.data, "Press_AB")
self.game.stack:pop()
if self.onDone then self.onDone(name) end
end
function NamingScreen:grid()
local base = self.lower and GRID_LOWER or GRID_UPPER
if not Runtime.wantsHook("ui.naming.grid") then return base end
local hooked = Runtime.call("ui.naming.grid", sameGrid, base, {
lower = self.lower and true or false,
title = self.title,
maxLen = self.maxLen,
game = self.game,
})
if type(hooked) ~= "table" or #hooked == 0 then return base end
return hooked
end
-- Gen 1 jumps the cursor to ED once the name is full.
function NamingScreen:jumpToEnd()
local _, edRow, edCol = findMeta(self:grid())
self.row, self.col = edRow, edCol
end
function NamingScreen:update(dt)
local GRID = self:grid()
local caseRow, edRow, edCol = findMeta(GRID)
local input = self.game.input
if input:wasPressed("start") then
self:confirm()
return
end
if input:wasPressed("select") then -- SELECT also flips the case page
self.lower = not self.lower
return
end
if input:wasPressed("up") then
-- wrapping up from the top row lands on the case-switch cell
self.row = self.row > 1 and self.row - 1 or caseRow
self.col = math.min(self.col, #GRID[self.row])
elseif input:wasPressed("down") then
self.row = self.row < #GRID and self.row + 1 or 1
self.col = math.min(self.col, #GRID[self.row])
elseif input:wasPressed("left") then
-- no horizontal movement on the case-switch row
if self.row ~= caseRow then
self.col = self.col > 1 and self.col - 1 or #GRID[self.row]
end
elseif input:wasPressed("right") then
if self.row ~= caseRow then
self.col = self.col < #GRID[self.row] and self.col + 1 or 1
end
else
-- Prefer A over B when both edges fire in one frame (love-nx dual
-- gamepad+raw path historically set both; erase must not win).
local pressedA = input:wasPressed("a")
local pressedB = input:wasPressed("b")
if pressedA and pressedB then pressedB = false end
if pressedB then
table.remove(self.glyphs)
elseif pressedA then
if self.row == edRow and self.col == edCol then
self:confirm()
return
end
if self.row == caseRow then
self.lower = not self.lower
return
end
if #self.glyphs < self.maxLen then
Sound.play(self.game.data, "Press_AB")
table.insert(self.glyphs, GRID[self.row][self.col])
if #self.glyphs >= self.maxLen then self:jumpToEnd() end
end
end
end
end
function NamingScreen:draw()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.rectangle("fill", 0, 0, 160, 144)
love.graphics.setColor(0, 0, 0, 1)
Font.draw(self.title, 8, 8)
-- typed name with dashes for the empty slots
for i = 1, self.maxLen do
Font.draw(self.glyphs[i] or "-", 56 + (i - 1) * 8, 24)
end
for r, row in ipairs(self:grid()) do
for c, cell in ipairs(row) do
Font.draw(Strings(cell), c * 16, 32 + r * 16)
end
end
Font.drawCode(Theme.cursor, self.col * 16 - 8, 32 + self.row * 16)
love.graphics.setColor(1, 1, 1, 1)
end
return NamingScreen