Merge pull request #1543 from AverageConsumer/codex/gen2-party-grid-navigation

fix(gen2): honor battle party grid navigation
This commit is contained in:
bryanthaboi
2026-08-19 06:00:21 -04:00
committed by GitHub
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
numeric flag space forces.
- *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.list_menu`, `transition.style`. `ui.list_menu` covers Gold's script
`ui.options.rows`, `ui.party.submenu`, `ui.party.grid_navigation`,
`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 draw with does not raise it yet, so those two are composed through
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
-- carries BattleMonMenu; PickPartyMonInBattle has no submenu.
prompt = forced and "which" or "choose",
battle = true,
battleSubmenu = not forced,
onCancel = function()
stack:pop()
@@ -2762,6 +2763,7 @@ function BattleState:openShiftParty()
self.phase = "submenu"
Screens.push(self.game, "Gen2PartyMenu", {
prompt = "which",
battle = true,
onCancel = function()
stack:pop()
self.phase = "resolving"
@@ -3135,6 +3137,7 @@ function BattleState:useOnPartyMon(itemId, action)
self.phase = "submenu"
Screens.push(self.game, "Gen2PartyMenu", {
prompt = "useItem",
battle = true,
party = self.battle.party or (self.save and self.save.party),
onCancel = function()
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.
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:drawsWidescreen() return true end
@@ -114,6 +131,7 @@ function PartyMenu.new(game, opts)
self.wantsSubmenu = opts.submenu == true
-- BattleMenu_PKMN's `callfar BattleMonMenu` (engine/battle/core.asm:4810).
self.wantsBattleSubmenu = opts.battleSubmenu == true
self.battle = opts.battle == true
self.submenu = nil
-- The held slot while SwitchPartyMons' second pick is open; nil otherwise.
self.switchFrom = nil
@@ -146,6 +164,13 @@ function PartyMenu:isCancel()
return self.index > #self.party
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
-- GetMonSubmenuItems, in its own order: every field move the mon knows first,
@@ -477,7 +502,18 @@ function PartyMenu:update(_dt)
return
end
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
elseif input:wasPressed("down") then
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",
-- menus and the battle intro
"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",
-- battle
"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 ChoiceBox = require("src.ui.ChoiceBox")
local PartyMenu = require("src.ui.PartyMenu")
local Gen2PartyMenu = require("src.ui.gen2.PartyMenu")
local Player = require("src.world.Player")
local Music = require("src.core.Music")
@@ -295,6 +296,16 @@ do
menu:update(0)
check(menu.index == 4,
"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
-- ------- music.volume (distance / indoor muffling)