This commit is contained in:
bryanthaboi
2026-08-20 20:07:10 -04:00
parent 4bdb9435a4
commit 90163a3ff2
4 changed files with 97 additions and 16 deletions
+3
View File
@@ -70,6 +70,9 @@ function StartMenu.new(game)
-- leaves it up under the prompt -- engine/menus/main_menu.asm:381-405 -- leaves it up under the prompt -- engine/menus/main_menu.asm:381-405
local panel local panel
panel = { panel = {
-- the panel overlaps the kept-open START menu box (start_sub_menus.asm:
-- 641-647), so neither can be docked to a screen edge on its own
holdsUIAnchors = true,
delay = 0, delay = 0,
update = function() update = function()
-- ld c, 30 / jp DelayFrames: the bare panel holds before the -- ld c, 30 / jp DelayFrames: the bare panel holds before the
+27 -6
View File
@@ -43,6 +43,28 @@ local function withWhiteOf(pal, ref)
return { ref[1], pal[2], pal[3], pal[4] } return { ref[1], pal[2], pal[3], pal[4] }
end end
-- Every drawn box, not just the topmost state's: DisplayContinueGameInfo
-- leaves the menu box up behind the info window (main_menu.asm:36-39), so both
-- are on screen and both need the overlay below.
local function titleUiBoxes(game)
local stack = game and game.stack
local states = stack and stack.states
if not states then
local top = stack and stack.top and stack:top()
local box = top and top.titleUiBox
return box and { box } or {}
end
local boxes = {}
for i = (stack.visibleBase and stack:visibleBase() or 1), #states do
local state = states[i]
local shown = not stack.renderVisible or stack:renderVisible(state)
if shown and state and state.titleUiBox then
boxes[#boxes + 1] = state.titleUiBox
end
end
return boxes
end
function TitleState:sgbPalettes(game) function TitleState:sgbPalettes(game)
local P = require("src.render.PaletteFX") local P = require("src.render.PaletteFX")
local z local z
@@ -65,9 +87,6 @@ function TitleState:sgbPalettes(game)
P.zone(P.pal(game.data, "MEWMON"), 0, 10, 19, 17), P.zone(P.pal(game.data, "MEWMON"), 0, 10, 19, 17),
} }
end end
local top = game.stack and game.stack:top()
local box = top and top.titleUiBox
if box then
-- A DMG-grays zone, not the trueColor opt-out: through the shade-remap -- A DMG-grays zone, not the trueColor opt-out: through the shade-remap
-- shader GRAYS is the identity for the box's four shades, so SGB / -- shader GRAYS is the identity for the box's four shades, so SGB /
-- ADVANCED / OG modes keep #133's white paper and black ink exactly, -- ADVANCED / OG modes keep #133's white paper and black ink exactly,
@@ -75,6 +94,7 @@ function TitleState:sgbPalettes(game)
-- modes -- a trueColor rect skipped the shader entirely, leaving the -- modes -- a trueColor rect skipped the shader entirely, leaving the
-- main menu and CONTINUE info box a raw white hole over a CLASSIC -- main menu and CONTINUE info box a raw white hole over a CLASSIC
-- pea-green title instead of matching it like the START menu does (#870). -- pea-green title instead of matching it like the START menu does (#870).
for _, box in ipairs(titleUiBoxes(game)) do
z[#z + 1] = P.zone(P.GRAYS, box[1], box[2], box[3], box[4]) z[#z + 1] = P.zone(P.GRAYS, box[1], box[2], box[3], box[4])
end end
return z[3] and z or nil return z[3] and z or nil
@@ -175,20 +195,21 @@ end
local function replayObjSprite(game, image, quad, x, y) local function replayObjSprite(game, image, quad, x, y)
local P = require("src.render.PaletteFX") local P = require("src.render.PaletteFX")
if not P.usesSpriteObp() then return end if not P.usesSpriteObp() then return end
local top = game.stack and game.stack:top() local boxes = titleUiBoxes(game)
local box = top and top.titleUiBox if boxes[1] then
if box then
local w, h local w, h
if quad then if quad then
w, h = select(3, quad:getViewport()) w, h = select(3, quad:getViewport())
else else
w, h = image:getDimensions() w, h = image:getDimensions()
end end
for _, box in ipairs(boxes) do
if x < (box[3] + 1) * 8 and x + w > box[1] * 8 if x < (box[3] + 1) * 8 and x + w > box[1] * 8
and y < (box[4] + 1) * 8 and y + h > box[2] * 8 then and y < (box[4] + 1) * 8 and y + h > box[2] * 8 then
return return
end end
end end
end
P.markUiSpriteRedraw(image, quad, x, y) P.markUiSpriteRedraw(image, quad, x, y)
end end
+26
View File
@@ -236,6 +236,32 @@ do
same(z[2].colors[3], BLUE_LOGO1[3], "Blue LOGO1's other inks stay put") same(z[2].colors[3], BLUE_LOGO1[3], "Blue LOGO1's other inks stay put")
end end
-- #133's grays overlay follows every box on screen, not just the topmost
-- state's: DisplayContinueGameInfo leaves the menu box up behind the info
-- window (main_menu.asm:36-39), and reading only the top left the menu box
-- on the raw LOGO2 / LOGO1 bands -- blue rows over a red EXIT GAME row.
do
PaletteFX.mode = "gbc"
GameVersion.set("red")
local stack = {
states = { { isOpaque = true },
{ titleUiBox = { 0, 0, 12, 9 } },
{ titleUiBox = { 4, 7, 19, 16 } } },
visibleBase = function() return 1 end,
top = function(self) return self.states[#self.states] end,
}
local z = title:sgbPalettes({ data = romPack(RED_LOGO1), stack = stack })
eq(#z, 5, "both open boxes get an overlay zone")
eq(z[4].x, 0, "the menu box keeps its overlay while the info window is up")
eq(z[4].y, 0, "at the menu box's own origin")
eq(z[5].x, 32, "and the info window's sits on top of it")
eq(z[5].y, 56, "at hlcoord 4,7")
stack.states[3] = nil
z = title:sgbPalettes({ data = romPack(RED_LOGO1), stack = stack })
eq(#z, 4, "the menu alone is still one overlay, as before")
end
PaletteFX.mode = savedMode PaletteFX.mode = savedMode
GameVersion.set(savedVersion) GameVersion.set(savedVersion)
+31
View File
@@ -67,6 +67,37 @@ T.eq(anchorsAfter({ centered = false, hold = true }), 0,
"a battle still holds the anchors while DYNAMIC is on") "a battle still holds the anchors while DYNAMIC is on")
T.eq(anchorsAfter({ centered = true, hold = true }), 0, "and with it off") T.eq(anchorsAfter({ centered = true, hold = true }), 0, "and with it off")
-- --------------------------------------------------------- the save panel
-- PrintSaveScreenText prints at hlcoord 4,0 over the kept-open START menu box
-- at 9,0 (start_sub_menus.asm:641-647); docking the menu alone split it (#1619).
do
local StartMenu = require("src.ui.StartMenu")
local DataFx = T.fixtures.load()
require("src.render.Font").load(DataFx)
local pushed = {}
local panelGame = {
data = DataFx, save = SaveData.newGame(),
stack = { states = pushed,
push = function(_, s) pushed[#pushed + 1] = s end,
pop = function() end,
top = function() return pushed[#pushed] end },
}
panelGame.save.player.name = "RED"
local menu = StartMenu.new(panelGame)
pushed[#pushed + 1] = menu
local saveRow
for _, item in ipairs(menu.items) do
if tostring(item.label):match("SAVE") then saveRow = item end
end
T.check(saveRow ~= nil, "the START menu carries a SAVE row")
T.eq(Game.uiAnchorsHeldInStack({ states = pushed }), false,
"the START menu alone still docks")
saveRow.onSelect()
T.eq(Game.uiAnchorsHeldInStack({ states = pushed }), true,
"the SAVE panel holds the anchors so it cannot be split from the menu")
end
-- ------------------------------------------------- the scale half of it -- ------------------------------------------------- the scale half of it
-- CENTERED is a FIXED letterbox, so the UI must not follow the survey zoom -- CENTERED is a FIXED letterbox, so the UI must not follow the survey zoom