fix(gen2): honor battle party grid navigation

This commit is contained in:
AverageConsumer
2026-08-19 00:21:02 +02:00
parent 580449b8df
commit 66079686fc
5 changed files with 56 additions and 4 deletions
+3 -2
View File
@@ -512,8 +512,9 @@ gains a field instead of the name gaining a prefix.
id under Gen 1's `name` key, which is the one payload difference the id under Gen 1's `name` key, which is the one payload difference the
numeric flag space forces. numeric flag space forces.
- *Menus (`src/ui/gen2/`):* `ui.start_menu.items`, `ui.title_menu.items`, - *Menus (`src/ui/gen2/`):* `ui.start_menu.items`, `ui.title_menu.items`,
`ui.options.rows`, `ui.party.submenu`, `ui.naming.grid`, `ui.pc.items`, `ui.options.rows`, `ui.party.submenu`, `ui.party.grid_navigation`,
`ui.list_menu`, `transition.style`. `ui.list_menu` covers Gold's script `ui.naming.grid`, `ui.pc.items`, `ui.list_menu`, `transition.style`.
`ui.list_menu` covers Gold's script
menus (`ScriptMenu.lua`); the `Chrome.List` widget the START and title menus (`ScriptMenu.lua`); the `Chrome.List` widget the START and title
menus draw with does not raise it yet, so those two are composed through menus draw with does not raise it yet, so those two are composed through
their own hooks only. their own hooks only.
+3
View File
@@ -2290,6 +2290,7 @@ function BattleState:openParty(forced)
-- :2702; engine/pokemon/party_menu.asm:660-679). Only the voluntary list -- :2702; engine/pokemon/party_menu.asm:660-679). Only the voluntary list
-- carries BattleMonMenu; PickPartyMonInBattle has no submenu. -- carries BattleMonMenu; PickPartyMonInBattle has no submenu.
prompt = forced and "which" or "choose", prompt = forced and "which" or "choose",
battle = true,
battleSubmenu = not forced, battleSubmenu = not forced,
onCancel = function() onCancel = function()
stack:pop() stack:pop()
@@ -2762,6 +2763,7 @@ function BattleState:openShiftParty()
self.phase = "submenu" self.phase = "submenu"
Screens.push(self.game, "Gen2PartyMenu", { Screens.push(self.game, "Gen2PartyMenu", {
prompt = "which", prompt = "which",
battle = true,
onCancel = function() onCancel = function()
stack:pop() stack:pop()
self.phase = "resolving" self.phase = "resolving"
@@ -3135,6 +3137,7 @@ function BattleState:useOnPartyMon(itemId, action)
self.phase = "submenu" self.phase = "submenu"
Screens.push(self.game, "Gen2PartyMenu", { Screens.push(self.game, "Gen2PartyMenu", {
prompt = "useItem", prompt = "useItem",
battle = true,
party = self.battle.party or (self.save and self.save.party), party = self.battle.party or (self.save and self.save.party),
onCancel = function() onCancel = function()
stack:pop() stack:pop()
+37 -1
View File
@@ -76,6 +76,23 @@ local BATTLE_SUBMENU_LEFT, BATTLE_SUBMENU_TOP = 11, 11
-- HP bar is 6 tiles wide (48px) in the party list. -- HP bar is 6 tiles wide (48px) in the party list.
local function gridIndex(index, count, direction)
if count < 1 then return nil end
local row, col = math.floor((index - 1) / 2), (index - 1) % 2
if direction == "left" or direction == "right" then
local other = row * 2 + (1 - col) + 1
return other <= count and other or index
end
local step = direction == "up" and -1 or direction == "down" and 1
if not step then return nil end
local rows = math.ceil(count / 2)
for offset = 1, rows do
local other = ((row + step * offset) % rows) * 2 + col + 1
if other <= count then return other end
end
return index
end
function PartyMenu:wantsFillScale() return true end function PartyMenu:wantsFillScale() return true end
function PartyMenu:drawsWidescreen() return true end function PartyMenu:drawsWidescreen() return true end
@@ -114,6 +131,7 @@ function PartyMenu.new(game, opts)
self.wantsSubmenu = opts.submenu == true self.wantsSubmenu = opts.submenu == true
-- BattleMenu_PKMN's `callfar BattleMonMenu` (engine/battle/core.asm:4810). -- BattleMenu_PKMN's `callfar BattleMonMenu` (engine/battle/core.asm:4810).
self.wantsBattleSubmenu = opts.battleSubmenu == true self.wantsBattleSubmenu = opts.battleSubmenu == true
self.battle = opts.battle == true
self.submenu = nil self.submenu = nil
-- The held slot while SwitchPartyMons' second pick is open; nil otherwise. -- The held slot while SwitchPartyMons' second pick is open; nil otherwise.
self.switchFrom = nil self.switchFrom = nil
@@ -146,6 +164,13 @@ function PartyMenu:isCancel()
return self.index > #self.party return self.index > #self.party
end end
function PartyMenu:gridNavigation()
if not self.battle
or not Runtime.wantsHook("ui.party.grid_navigation") then return false end
return Runtime.call("ui.party.grid_navigation", function() return false end,
self) == true
end
-- ------------------------------------------------------------- mon submenu -- ------------------------------------------------------------- mon submenu
-- GetMonSubmenuItems, in its own order: every field move the mon knows first, -- GetMonSubmenuItems, in its own order: every field move the mon knows first,
@@ -477,7 +502,18 @@ function PartyMenu:update(_dt)
return return
end end
local total = self:count() local total = self:count()
if input:wasPressed("up") then local grid
if self:gridNavigation() then
local direction = input:wasPressed("left") and "left"
or input:wasPressed("right") and "right"
or input:wasPressed("up") and "up"
or input:wasPressed("down") and "down"
grid = gridIndex(self.index, #self.party, direction)
end
if grid then
self.index = grid
self:storeCursor()
elseif input:wasPressed("up") then
self.index = self.index > 1 and self.index - 1 or total self.index = self.index > 1 and self.index - 1 or total
elseif input:wasPressed("down") then elseif input:wasPressed("down") then
self.index = self.index < total and self.index + 1 or 1 self.index = self.index < total and self.index + 1 or 1
+2 -1
View File
@@ -397,7 +397,8 @@ local GEN2_HOOKS = {
"world.tod", "map.palette", "fieldmove.eligibility", "world.tod", "map.palette", "fieldmove.eligibility",
-- menus and the battle intro -- menus and the battle intro
"ui.start_menu.items", "ui.title_menu.items", "ui.options.rows", "ui.start_menu.items", "ui.title_menu.items", "ui.options.rows",
"ui.party.submenu", "ui.naming.grid", "ui.pc.items", "ui.list_menu", "ui.party.submenu", "ui.party.grid_navigation", "ui.naming.grid",
"ui.pc.items", "ui.list_menu",
"transition.style", "transition.style",
-- battle -- battle
"battle.damage", "battle.crit", "battle.accuracy", "battle.turn_order", "battle.damage", "battle.crit", "battle.accuracy", "battle.turn_order",
+11
View File
@@ -14,6 +14,7 @@ local NamingScreen = require("src.ui.NamingScreen")
local TextBox = require("src.render.TextBox") local TextBox = require("src.render.TextBox")
local ChoiceBox = require("src.ui.ChoiceBox") local ChoiceBox = require("src.ui.ChoiceBox")
local PartyMenu = require("src.ui.PartyMenu") local PartyMenu = require("src.ui.PartyMenu")
local Gen2PartyMenu = require("src.ui.gen2.PartyMenu")
local Player = require("src.world.Player") local Player = require("src.world.Player")
local Music = require("src.core.Music") local Music = require("src.core.Music")
@@ -295,6 +296,16 @@ do
menu:update(0) menu:update(0)
check(menu.index == 4, check(menu.index == 4,
"removing the hook restores native list navigation immediately") "removing the hook restores native list navigation immediately")
local gold = Gen2PartyMenu.new(game, { battle = true })
unsub = wrap("ui.party.grid_navigation", function() return true end)
gold:update(0)
check(gold.index == 3,
"a Gold battle party can follow the same companion grid")
unsub()
gold:update(0)
check(gold.index == 4,
"Gold restores native party list navigation without the hook")
end end
-- ------- music.volume (distance / indoor muffling) -- ------- music.volume (distance / indoor muffling)