Merge pull request #1068 from anxiousintrovert/agent/fix-disabled-battle-ui-background

Fix hidden battle UI overlay backgrounds
This commit is contained in:
bryanthaboi
2026-08-12 16:56:46 -04:00
committed by GitHub
6 changed files with 69 additions and 12 deletions
+6 -3
View File
@@ -454,9 +454,12 @@ identifiers: `pc_box_withdraw`, `pc_box_deposit`, `pc_box_release`,
`battle.bottom_ui_visible` and `battle.status_hud_visible` independently
control the battle text/menu layer and the HP/status panels. Both receive
`(next, state)` and default to `true`, so vanilla rendering is unchanged.
Pushed text boxes also pass through `battle.bottom_ui_visible`; a wrapper that
only owns battle presentation should return `false` only for its active battle
or text-box state.
Text boxes and YES/NO prompts pushed above a battle inherit a `false` result
for that battle, so hiding the bottom layer cannot leave their white backing
behind under another overlay. Text boxes also pass through the hook as their
own state, preserving selective control outside a battle; a wrapper that only
owns battle presentation should return `false` only for its active battle or
text-box state.
`core.logic_speed` receives `(next, game)` once per `Game:logicSpeed()` call
(once per frame). Vanilla behavior resolves the per-category GAME SPEED
+2 -3
View File
@@ -28,6 +28,7 @@ local Timing = require("src.core.Timing")
local TrainerAI = require("src.battle.TrainerAI")
local TurnOrder = require("src.battle.TurnOrder")
local TypeChart = require("src.battle.TypeChart")
local UIVisibility = require("src.battle.UIVisibility")
local RomText = require("src.core.RomText")
local Strings = require("src.core.Strings")
local WideBattle = require("src.battle.WideBattle")
@@ -135,9 +136,7 @@ function BattleState:sgbPalettes()
end
function BattleState:bottomUIVisible()
if not Runtime.wantsHook("battle.bottom_ui_visible") then return true end
return Runtime.call("battle.bottom_ui_visible", function() return true end,
self) ~= false
return UIVisibility.bottomVisible(self, true)
end
function BattleState:statusHUDVisible()
+39
View File
@@ -0,0 +1,39 @@
-- Shared visibility rules for battle-owned UI states. Text and choice
-- overlays live above BattleState on the state stack, but they are still part
-- of its bottom UI layer and must inherit that layer's visibility.
local Runtime = require("src.mods.Runtime")
local UIVisibility = {}
local function enclosingBattle(state)
local stack = state and state.game and state.game.stack
local states = stack and stack.states
local found = false
for i = #(states or {}), 1, -1 do
local candidate = states[i]
if candidate == state then found = true end
if found and candidate and candidate.isBattle then return candidate end
end
return nil
end
-- queryState keeps the existing TextBox contract: a mod may still decide
-- visibility for that individual box. ChoiceBox only inherits the enclosing
-- battle decision, so field YES/NO prompts never become battle-hook states.
function UIVisibility.bottomVisible(state, queryState)
if not Runtime.wantsHook("battle.bottom_ui_visible") then return true end
local battle = enclosingBattle(state)
if battle and battle ~= state
and Runtime.call("battle.bottom_ui_visible",
function() return true end, battle) == false then
return false
end
if queryState or battle == state then
return Runtime.call("battle.bottom_ui_visible",
function() return true end, state) ~= false
end
return true
end
return UIVisibility
+2 -6
View File
@@ -7,7 +7,7 @@
-- the text is exhausted and A is pressed, then calls onDone.
local Font = require("src.render.Font")
local Runtime = require("src.mods.Runtime")
local UIVisibility = require("src.battle.UIVisibility")
local Theme = require("src.ui.Theme")
local Timing = require("src.core.Timing")
@@ -393,11 +393,7 @@ function TextBox:update(dt)
end
function TextBox:draw()
if Runtime.wantsHook("battle.bottom_ui_visible")
and Runtime.call("battle.bottom_ui_visible", function() return true end,
self) == false then
return
end
if not UIVisibility.bottomVisible(self, true) then return end
-- The dialogue box belongs against the bottom of the screen, not floating
-- in the middle of a zoomed-out letterbox. Declared per frame; the
-- renderer blits this region to the screen edge and the rest of the UI
+2
View File
@@ -1,6 +1,7 @@
-- YES/NO choice box (InitYesNoTextBoxParameters: above the text box, right).
local Font = require("src.render.Font")
local UIVisibility = require("src.battle.UIVisibility")
local Theme = require("src.ui.Theme")
local Strings = require("src.core.Strings")
local Timing = require("src.core.Timing")
@@ -67,6 +68,7 @@ function ChoiceBox:update(dt)
end
function ChoiceBox:draw()
if not UIVisibility.bottomVisible(self, false) then return end
local tx, ty, tw, th = self.tx, self.ty, self.tw, self.th
-- rides the same bottom anchor as the dialogue box it sits above, so the
-- pair travels together (the anchor keeps each element's gap from the edge)
+18
View File
@@ -12,6 +12,7 @@ local Zoom = require("src.render.Zoom")
local ListMenu = require("src.ui.ListMenu")
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 Player = require("src.world.Player")
local Music = require("src.core.Music")
@@ -180,6 +181,23 @@ do
text:draw()
check(seen == text, "pushed text boxes use the same visibility hook")
unsub()
local battle = setmetatable({ isBattle = true }, BattleState)
local game = { stack = { states = {} } }
text = setmetatable({ game = game }, TextBox)
local choice = setmetatable({ game = game }, ChoiceBox)
game.stack.states = { battle, text, choice }
local queried = {}
unsub = wrap("battle.bottom_ui_visible", function(_, state)
queried[#queried + 1] = state
return state ~= battle
end)
text:draw()
choice:draw()
check(queried[1] == battle and queried[2] == battle and #queried == 2,
"battle overlays inherit a hidden bottom layer without drawing backings")
unsub()
check(BattleState.bottomUIVisible({ phase = "moveSelect" }),
"battle bottom UI returns when the hook is removed")