mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-16 00:02:23 +02:00
G2 support
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
-- Which games a mod is for. One derivation for the manifest's `games` key,
|
||||
-- the legacy `gen2compat` flag, and the labels both mod surfaces draw:
|
||||
-- src/mods/LauncherMods.lua and src/mods/ManagerState.lua read this rather
|
||||
-- than each keeping its own copy of the rule.
|
||||
local GameVersion = require("src.core.GameVersion")
|
||||
|
||||
local ModTargets = {}
|
||||
|
||||
-- every version of one generation, in launcher order (GameVersion.ORDER)
|
||||
function ModTargets.generationVersions(gen)
|
||||
local out = {}
|
||||
for _, id in ipairs(GameVersion.ORDER) do
|
||||
if GameVersion.generation(id) == gen then out[#out + 1] = id end
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
-- the generations this engine has games for, ascending
|
||||
local function generations()
|
||||
local seen, out = {}, {}
|
||||
for _, id in ipairs(GameVersion.ORDER) do
|
||||
local gen = GameVersion.generation(id)
|
||||
if not seen[gen] then
|
||||
seen[gen] = true
|
||||
out[#out + 1] = gen
|
||||
end
|
||||
end
|
||||
table.sort(out)
|
||||
return out
|
||||
end
|
||||
|
||||
-- one manifest token -> the version ids it covers, or nil when it names no
|
||||
-- game this engine knows: "red" | "gen1" | "all"
|
||||
function ModTargets.expand(token)
|
||||
if type(token) ~= "string" then return nil end
|
||||
local key = token:lower():match("^%s*(.-)%s*$")
|
||||
if key == "all" then return GameVersion.ORDER end
|
||||
if GameVersion.VERSIONS[key] then return { key } end
|
||||
local gen = key:match("^gen%s*(%d+)$")
|
||||
if gen then
|
||||
local list = ModTargets.generationVersions(tonumber(gen))
|
||||
if #list > 0 then return list end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- version-id lists are always ORDER-sorted and deduped, so two manifests that
|
||||
-- say the same thing different ways encode and compare the same
|
||||
local function fromSet(set)
|
||||
local out = {}
|
||||
for _, id in ipairs(GameVersion.ORDER) do
|
||||
if set[id] then out[#out + 1] = id end
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
-- normalize a manifest `games` array; second return is the tokens that named
|
||||
-- no game, which Manifest reports at its own api level
|
||||
function ModTargets.normalize(list)
|
||||
local set, unknown = {}, {}
|
||||
for _, token in ipairs(type(list) == "table" and list or {}) do
|
||||
local ids = ModTargets.expand(token)
|
||||
if ids then
|
||||
for _, id in ipairs(ids) do set[id] = true end
|
||||
else
|
||||
unknown[#unknown + 1] = tostring(token)
|
||||
end
|
||||
end
|
||||
return fromSet(set), unknown
|
||||
end
|
||||
|
||||
function ModTargets.union(a, b)
|
||||
local set = {}
|
||||
for _, list in ipairs({ a or {}, b or {} }) do
|
||||
for _, id in ipairs(list) do set[id] = true end
|
||||
end
|
||||
return fromSet(set)
|
||||
end
|
||||
|
||||
-- The pre-`games` reading of a manifest: Gen 1 always, Gen 2 only where the
|
||||
-- author claimed gen2compat (src/mods/Manifest.lua).
|
||||
function ModTargets.legacy(gen2compat)
|
||||
local out = ModTargets.generationVersions(1)
|
||||
if gen2compat then
|
||||
return ModTargets.union(out, ModTargets.generationVersions(2))
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
-- does a version-id list hold any game of that generation
|
||||
function ModTargets.covers(versions, gen)
|
||||
for _, id in ipairs(versions or {}) do
|
||||
if GameVersion.generation(id) == gen then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- the version ids a validated manifest targets; Manifest.validate resolves
|
||||
-- `games` at load, so this is the same answer everywhere
|
||||
function ModTargets.versions(manifest)
|
||||
local games = manifest and manifest.games
|
||||
if type(games) == "table" and #games > 0 then return games end
|
||||
return ModTargets.legacy(manifest and manifest.gen2compat)
|
||||
end
|
||||
|
||||
-- Does the mod target this game? `version` is a version id; pass nil with a
|
||||
-- generation to ask about a whole generation (the loader's injected seam).
|
||||
function ModTargets.supports(manifest, version, generation)
|
||||
local versions = ModTargets.versions(manifest)
|
||||
if version and GameVersion.VERSIONS[version] then
|
||||
for _, id in ipairs(versions) do
|
||||
if id == version then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
return ModTargets.covers(versions, generation or GameVersion.generation())
|
||||
end
|
||||
|
||||
-- What will actually happen here: the loader gates on this same answer, per
|
||||
-- version (Loader:_gateGeneration), and the player's override forces past it,
|
||||
-- so the two UIs report a run, not a claim.
|
||||
function ModTargets.runsHere(manifest, version, generation, forced)
|
||||
if forced then return true end
|
||||
return ModTargets.supports(manifest, version, generation)
|
||||
end
|
||||
|
||||
-- "Gen 1" / "Gen 1+2" while a mod takes whole generations, the version names
|
||||
-- ("Red/Gold") once it takes only some of one
|
||||
function ModTargets.label(manifest)
|
||||
local versions = ModTargets.versions(manifest)
|
||||
local set = {}
|
||||
for _, id in ipairs(versions) do set[id] = true end
|
||||
local whole, partial = {}, false
|
||||
for _, gen in ipairs(generations()) do
|
||||
local all, any = true, false
|
||||
for _, id in ipairs(ModTargets.generationVersions(gen)) do
|
||||
if set[id] then any = true else all = false end
|
||||
end
|
||||
if any and all then whole[#whole + 1] = tostring(gen)
|
||||
elseif any then partial = true end
|
||||
end
|
||||
if #whole > 0 and not partial then
|
||||
return "Gen " .. table.concat(whole, "+")
|
||||
end
|
||||
local names = {}
|
||||
for _, id in ipairs(versions) do
|
||||
names[#names + 1] = GameVersion.info(id).label or id
|
||||
end
|
||||
if #names == 0 then return "No game" end
|
||||
return table.concat(names, "/")
|
||||
end
|
||||
|
||||
-- the same label as an all-caps chip, for the launcher tag and the GB font
|
||||
function ModTargets.chip(manifest)
|
||||
return ModTargets.label(manifest):upper()
|
||||
end
|
||||
|
||||
-- one game's own name, for a line that has to say which one this is
|
||||
function ModTargets.gameLabel(version)
|
||||
local info = version and GameVersion.info(version)
|
||||
return (info and info.label) or tostring(version)
|
||||
end
|
||||
|
||||
-- One launcher-voice line for a mod that does not target `version`
|
||||
-- (src/mods/LauncherMods.lua statusFor).
|
||||
function ModTargets.detail(manifest, version)
|
||||
return ("For %s, not %s"):format(ModTargets.label(manifest),
|
||||
ModTargets.gameLabel(version))
|
||||
end
|
||||
|
||||
return ModTargets
|
||||
Reference in New Issue
Block a user