mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-28 14:59:27 -04:00
69 lines
2.0 KiB
Lua
69 lines
2.0 KiB
Lua
-- Game state stack. The top state updates; all states draw bottom-up
|
|
-- (so a text box can overlay the overworld, a battle replaces it, etc).
|
|
-- States are tables with optional enter/exit/update/draw/isOpaque.
|
|
|
|
local Runtime = require("src.mods.Runtime")
|
|
|
|
local StateStack = {}
|
|
|
|
function StateStack:init()
|
|
self.states = {}
|
|
end
|
|
|
|
-- screen.pushed/popped fire after enter/exit so listeners observe the
|
|
-- settled state; the wants guard keeps the no-listener path allocation-free
|
|
|
|
function StateStack:push(state, ...)
|
|
table.insert(self.states, state)
|
|
if state.enter then state:enter(...) end
|
|
if Runtime.wants("screen.pushed") then
|
|
Runtime.emit("screen.pushed", { state = state })
|
|
end
|
|
end
|
|
|
|
function StateStack:pop()
|
|
local state = table.remove(self.states)
|
|
if state and state.exit then state:exit() end
|
|
if state and Runtime.wants("screen.popped") then
|
|
Runtime.emit("screen.popped", { state = state })
|
|
end
|
|
return state
|
|
end
|
|
|
|
function StateStack:top()
|
|
return self.states[#self.states]
|
|
end
|
|
|
|
function StateStack:update(dt)
|
|
local top = self:top()
|
|
if top and top.update then top:update(dt) end
|
|
end
|
|
|
|
local function visibleByDefault() return true end
|
|
|
|
-- A mod may mirror a state elsewhere and hide only its main-screen render.
|
|
-- The state stays on the stack, so update and input ownership do not move.
|
|
function StateStack:renderVisible(state)
|
|
if not state then return false end
|
|
if not Runtime.wantsHook("screen.render_visible") then return true end
|
|
return Runtime.call("screen.render_visible", visibleByDefault, state) ~= false
|
|
end
|
|
|
|
-- index of the lowest state drawn this frame (highest opaque, else 1)
|
|
function StateStack:visibleBase()
|
|
for i = #self.states, 1, -1 do
|
|
local state = self.states[i]
|
|
if self:renderVisible(state) and state.isOpaque then return i end
|
|
end
|
|
return 1
|
|
end
|
|
|
|
function StateStack:draw()
|
|
for i = self:visibleBase(), #self.states do
|
|
local state = self.states[i]
|
|
if self:renderVisible(state) and state.draw then state:draw() end
|
|
end
|
|
end
|
|
|
|
return StateStack
|