mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
99 lines
3.4 KiB
Lua
99 lines
3.4 KiB
Lua
-- Gallery #6 (Tool builder): a read-mostly overlay. Everything it knows
|
|
-- comes from the merged view through the public mod API -- no private
|
|
-- require, no engine table reached behind the loader's back -- and what it
|
|
-- knows is published as a stable export other mods can call.
|
|
local SCREEN = "ExampleDexNav"
|
|
|
|
return function(mod)
|
|
mod.options:define({
|
|
{ key = "sort", label = "SORT BY", type = "choice", default = "dex",
|
|
choices = { { "DEX NO.", "dex" }, { "NAME", "name" } } },
|
|
{ key = "unseen", label = "SHOW UNSEEN", type = "toggle", default = true },
|
|
})
|
|
|
|
-- ------- the merged view, read once per open
|
|
|
|
-- content.pokemon:each() yields the engine's species AND every mod's,
|
|
-- which is the whole point: a tool that hard-codes 151 breaks the moment
|
|
-- someone adds a species.
|
|
local function species()
|
|
local rows = {}
|
|
for id, mon in mod.content.pokemon:each() do
|
|
rows[#rows + 1] = { id = id, name = mon.name or id, dex = mon.dex or 9999 }
|
|
end
|
|
return rows
|
|
end
|
|
|
|
local function dexOf(game)
|
|
return (game and game.save and game.save.pokedex) or { seen = {}, owned = {} }
|
|
end
|
|
|
|
local function counts(game)
|
|
local dex = dexOf(game)
|
|
local seen, owned = 0, 0
|
|
for _, row in ipairs(species()) do
|
|
if dex.seen[row.id] then seen = seen + 1 end
|
|
if dex.owned[row.id] then owned = owned + 1 end
|
|
end
|
|
return seen, owned
|
|
end
|
|
|
|
-- ------- the inter-mod API
|
|
-- Another mod reads this with mod.find("example_dexnav").exports; it is
|
|
-- the supported way to depend on this one, and the reason nothing here
|
|
-- reaches into a private module.
|
|
|
|
mod.exports.countSeen = function(game) return (counts(game)) end
|
|
mod.exports.countOwned = function(game) return select(2, counts(game)) end
|
|
mod.exports.species = species
|
|
|
|
-- ------- the screen
|
|
|
|
mod.content.screens:register(SCREEN, {
|
|
new = function(game)
|
|
local dex = dexOf(game)
|
|
local showUnseen = mod.options:get("unseen")
|
|
local rows = species()
|
|
if mod.options:get("sort") == "name" then
|
|
table.sort(rows, function(a, b) return a.name < b.name end)
|
|
else
|
|
table.sort(rows, function(a, b)
|
|
if a.dex ~= b.dex then return a.dex < b.dex end
|
|
return a.id < b.id
|
|
end)
|
|
end
|
|
|
|
local items = {}
|
|
for _, row in ipairs(rows) do
|
|
local state = dex.owned[row.id] and "OWN"
|
|
or (dex.seen[row.id] and "SEEN" or "----")
|
|
if showUnseen or state ~= "----" then
|
|
items[#items + 1] = { label = row.name, right = state, value = row.id }
|
|
end
|
|
end
|
|
|
|
local seen, owned = counts(game)
|
|
-- ListMenu draws "Nothing here." for an empty set, so a brand new
|
|
-- save with SHOW UNSEEN off reads as a sentence, not a blank frame
|
|
return mod.ui.ListMenu.new(game,
|
|
("DEXNAV %d/%d"):format(owned, seen), items, {
|
|
pageJump = true,
|
|
onChoose = function(_, menu) menu:close() end,
|
|
})
|
|
end,
|
|
})
|
|
|
|
-- ------- reaching it
|
|
-- Call next() first, then decorate the list it returns: another mod's
|
|
-- row survives, and the vanilla rows are never rebuilt by hand.
|
|
|
|
mod.hooks:wrap("ui.start_menu.items", function(next, game, items)
|
|
local out = next(game, items)
|
|
if type(out) ~= "table" then return out end
|
|
return mod.ui.insertBefore(out, "SAVE", {
|
|
label = "DEXNAV",
|
|
onSelect = function() mod.ui.push(game, SCREEN) end,
|
|
})
|
|
end)
|
|
end
|