mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-16 08:11:35 +02:00
147 lines
5.4 KiB
Lua
147 lines
5.4 KiB
Lua
-- Screen id -> factory resolution. The screens registry (Data.screens)
|
|
-- wins; engine screens are the require fallback, so a mod-free boot
|
|
-- resolves every id to the exact module it required before. One cache,
|
|
-- dropped with the rest of the asset caches on dev-mode hot reload.
|
|
|
|
local Assets = require("src.render.Assets")
|
|
local Logger = require("src.core.Logger")
|
|
|
|
local Screens = {}
|
|
|
|
-- ids whose builtin module is not under src/ui/
|
|
local BUILTIN = {
|
|
ManagerState = "src.mods.ManagerState",
|
|
}
|
|
|
|
-- The Gen 2 (Gold) screens, which live under src/ui/gen2/. Half of them share
|
|
-- a module name with a Gen 1 screen (PartyMenu, StartMenu, TitleState,
|
|
-- OakSpeech, NamingScreen, PokedexMenu, OptionsMenu, TrainerCard, BoxMenu,
|
|
-- SummaryMenu, BattleState, SlotMachine, Credits, HallOfFame), so the ids
|
|
-- carry a "Gen2" prefix: one registry serves both generations, and a mod that
|
|
-- replaces Gold's party menu must not also replace Red's. The prefix is the
|
|
-- same namespace the Gold data tables use for the same collision
|
|
-- (data.gen2Palettes, data.gen2Icons).
|
|
--
|
|
-- Everything listed is a stack state: `new(game, opts)`, pushed and popped.
|
|
-- The drawing helpers sitting next to them in src/ui/gen2/ (Chrome, TileSheet,
|
|
-- PackGfx, SpriteAnims, BattleAnimView, BattleHud) are not screens and get no
|
|
-- id -- a mod reskins those through the asset search path, not through here.
|
|
--
|
|
-- Gen2HallOfFame is the screen; the roster behind it is src/core/gen2/
|
|
-- HallOfFame.lua, which is a model and gets no id either.
|
|
--
|
|
-- The Game Corner's three PRIZE COUNTERS get no id for the same reason: on the
|
|
-- cart they are map script and nothing else (GoldenrodGameCornerTMVendorScript
|
|
-- and its Celadon twins are `loadmenu` / `verticalmenu` / `checkcoins` /
|
|
-- `giveitem` / `givepoke` / `takecoins`, all of which src/script/gen2/Vm.lua
|
|
-- runs), so a prize counter is reached by talking to the vendor and never by
|
|
-- pushing a screen. The slot machine and card flip next door ARE engine
|
|
-- screens and do have ids.
|
|
local GEN2 = {
|
|
"BankOfMom",
|
|
"BattleState", "BattleTransition", "BoxMenu", "CardFlip",
|
|
-- The Pokecenter PC's whose-PC top menu and the player's item PC behind it;
|
|
-- Gen2PcMenu below is the storage system both BILL's PC rows open.
|
|
"CenterPcMenu",
|
|
"ContestMenu",
|
|
"CopyrightSplash", "Credits", "DayCareMenu", "DecorationMenu", "Diploma",
|
|
"EggHatchAnim", "ElevatorMenu", "EvolutionAnim",
|
|
"GameFreakPresents", "GoldSilverIntro", "HallOfFame", "HeldItemMenu",
|
|
-- Gen2InitClock is both timeset.asm screens: the new-game hour/minute pair
|
|
-- OakSpeech opens with, and Mom's day-of-week wheel.
|
|
"InitClock",
|
|
"ItemPcMenu",
|
|
"MagnetTrainRide",
|
|
-- MAIL, four screens: the compose keyboard, the full-page reader, the
|
|
-- READ/TAKE/QUIT row the party submenu opens, and the PC's MAILBOX.
|
|
"MailCompose", "MailMenu", "MailRead", "MailboxMenu",
|
|
-- Gen2MapRadio is the in-house wall radio (`special MapRadio`), not a card.
|
|
"MapRadio",
|
|
"MainMenu", "MartMenu", "MoveDeleter", "NamePick", "NamingScreen", "OakSpeech",
|
|
"OptionsMenu", "PackMenu", "PartyMenu", "PcMenu", "PhotoStudio", "PokedexMenu",
|
|
"Pokegear", "SaveMenu", "ScriptMenu", "SlotMachine",
|
|
"StartMenu", "SummaryMenu", "TitleState", "TradeAnim", "TradeMenu",
|
|
"TrainerCard",
|
|
-- Gen2UnownPrinter is the ALPH RUINS STAMP viewer, not the print itself.
|
|
"UnownPrinter", "UnownPuzzle",
|
|
}
|
|
|
|
-- The full ids, in the same order, for tests and for the mod docs.
|
|
Screens.GEN2_IDS = {}
|
|
for _, name in ipairs(GEN2) do
|
|
local id = "Gen2" .. name
|
|
BUILTIN[id] = "src.ui.gen2." .. name
|
|
Screens.GEN2_IDS[#Screens.GEN2_IDS + 1] = id
|
|
end
|
|
|
|
local cache = {}
|
|
|
|
local function builtinFor(id)
|
|
return require(BUILTIN[id] or ("src.ui." .. id))
|
|
end
|
|
|
|
local function resolve(game, id)
|
|
local hit = cache[id]
|
|
if hit then return hit end
|
|
local screens = game and game.data and game.data.screens
|
|
local record = screens and screens[id]
|
|
local factory
|
|
if record then
|
|
-- registry record: { new = fn } or a bare function (05-registry-system)
|
|
factory = (type(record) == "function") and { new = record } or record
|
|
factory.__modOwned = true
|
|
else
|
|
factory = builtinFor(id)
|
|
end
|
|
cache[id] = factory
|
|
return factory
|
|
end
|
|
|
|
function Screens.get(game, id)
|
|
return resolve(game, id)
|
|
end
|
|
|
|
-- Resolve and construct, without touching the stack. Not every screen is
|
|
-- stacked the moment it is built: the Gen 1 battle queue defers its UI rows,
|
|
-- and Gold's mart holds a PACK instance for the whole sell flow
|
|
-- (src/ui/gen2/MartMenu.lua). Those composers need the registry lookup, the
|
|
-- screenId stamp and the same degrade a push gets, so both paths share this.
|
|
local function build(game, id, ...)
|
|
local factory = resolve(game, id)
|
|
local inst
|
|
if factory.__modOwned then
|
|
-- a broken mod screen degrades to the builtin, never a dead end
|
|
local ok, result = pcall(factory.new, game, ...)
|
|
if ok and result then
|
|
inst = result
|
|
else
|
|
Logger.error("mod screen '%s' failed: %s -- using builtin",
|
|
id, tostring(result))
|
|
cache[id] = nil
|
|
inst = builtinFor(id).new(game, ...)
|
|
end
|
|
else
|
|
inst = factory.new(game, ...)
|
|
end
|
|
inst.screenId = inst.screenId or id
|
|
return inst
|
|
end
|
|
|
|
function Screens.build(game, id, ...)
|
|
return build(game, id, ...)
|
|
end
|
|
|
|
function Screens.push(game, id, ...)
|
|
local inst = build(game, id, ...)
|
|
game.stack:push(inst)
|
|
return inst
|
|
end
|
|
|
|
function Screens.invalidate()
|
|
cache = {}
|
|
end
|
|
|
|
Assets.register(Screens.invalidate)
|
|
|
|
return Screens
|