mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-21 05:00:43 +02:00
Pokemon Silver as a full launcher version, plus launcher mods-list and title-tempo fixes
Silver: derived import manifest (tools/make_silver_manifest.py re-resolves the Gold manifest's symbols from pokesilver.sym), silver GameVersion row, generation-keyed extractor routing, required-files override, edition save stamping (a Silver playthrough no longer writes into the Gold save), checkver-driven edition data, SILVER/KAMON/OSCAR/MAX presets, GOLD rival default, edition credits banner, Lugia title screen (OAM layouts, bob, trail, palettes as title.lua data keys with Gold defaults so old caches need no re-import), packaging for every build target, docs, and tests. Launcher: the installed-mods list is one continuous scroll (rows culled to the viewport) instead of a pager with an inner scroll viewport; the pad cursor's edge-scroll no longer runs it to the bottom. The game dropdown shows just the initial and caret. Find-tab behavior unchanged. Title tempo: a sprite-anim frame shows duration+1 ticks (engine/sprite_anims/core.asm GetSpriteAnimFrame), which locks both editions' 64-tick wing beat to the 64-tick sine bob; the title screens no longer run fast and out of phase.
This commit is contained in:
+2
-2
@@ -3,7 +3,7 @@
|
||||
-- everything under src/*/gen2 reaches shared services through here. Gen 1
|
||||
-- Game:load cannot consume a Gen 2 cache -- different generated tables, save
|
||||
-- shape and screen registry -- so main.lua's bootGame picks this owner when
|
||||
-- GameVersion.isGold(), and the two never branch into each other.
|
||||
-- GameVersion.generation() == 2, and the two never branch into each other.
|
||||
--
|
||||
-- Boot: copyright → GameFreak Presents → GS intro stub → title
|
||||
-- (tilemap + Ho-Oh flap / clouds / trails) → Oak speech (Marill + shrink)
|
||||
@@ -1702,7 +1702,7 @@ function Game2:hotkey(key)
|
||||
self:writeSave()
|
||||
return true
|
||||
elseif key == "f2" then
|
||||
local loaded = Save.load("gold")
|
||||
local loaded = Save.load()
|
||||
if loaded then self:continueGame(loaded) end
|
||||
return true
|
||||
elseif key == "1" then
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
-- Which game this process is running: Red (the historical default), Blue,
|
||||
-- Yellow, or Gold. One source of truth for everything that differs by
|
||||
-- Yellow, Gold, or Silver. One source of truth for everything that differs by
|
||||
-- version -- the accepted ROM hash, the import manifest, where the
|
||||
-- extracted cache lives, and the save-file suffix -- so the importer,
|
||||
-- cache mount, SaveData, title screen and palette all agree.
|
||||
@@ -8,7 +8,8 @@
|
||||
-- saves are untouched, but its extracted cache lives under red/ like Blue,
|
||||
-- Yellow, and Gold (issue #899); a legacy root cache is moved into red/ once
|
||||
-- by CacheFs.migrateLegacyRedCache. All supported versions can be imported
|
||||
-- and selected side by side. Gold is Gen 2 (see docs/gold-phase1.md).
|
||||
-- and selected side by side. Gold and Silver are Gen 2 (see
|
||||
-- docs/gold-phase1.md).
|
||||
--
|
||||
-- Zero requires, so it loads during love.conf and under plain Lua for tools
|
||||
-- and tests. The active version is a process-global set once at boot from
|
||||
@@ -61,13 +62,26 @@ GameVersion.VERSIONS = {
|
||||
manifest = "tools/rom_manifest_gold.json",
|
||||
cachePrefix = "gold/", -- gold/data/generated, gold/assets/generated
|
||||
saveSuffix = "_gold", -- save_gold.lua / .bak / .tmp
|
||||
-- The only row that carries one; absent reads as 1 (GameVersion.generation)
|
||||
-- Absent reads as 1 (GameVersion.generation)
|
||||
generation = 2,
|
||||
},
|
||||
-- Gold's engine with edition-selected data; the manifest is derived from
|
||||
-- Gold's by tools/make_silver_manifest.py.
|
||||
silver = {
|
||||
id = "silver",
|
||||
label = "Silver",
|
||||
displayName = "Pokemon Silver",
|
||||
launcherName = "Silver (Beta)",
|
||||
sha1 = "49b163f7e57702bc939d642a18f591de55d92dae",
|
||||
manifest = "tools/rom_manifest_silver.json",
|
||||
cachePrefix = "silver/", -- silver/data/generated, silver/assets/generated
|
||||
saveSuffix = "_silver", -- save_silver.lua / .bak / .tmp
|
||||
generation = 2,
|
||||
},
|
||||
}
|
||||
|
||||
-- Launcher column order.
|
||||
GameVersion.ORDER = { "red", "blue", "yellow", "gold" }
|
||||
GameVersion.ORDER = { "red", "blue", "yellow", "gold", "silver" }
|
||||
|
||||
GameVersion.current = "red"
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ local function normalizeVersion(v)
|
||||
b = "blue", blue = "blue",
|
||||
y = "yellow", yellow = "yellow",
|
||||
g = "gold", gold = "gold",
|
||||
s = "silver", silver = "silver",
|
||||
}
|
||||
v = alias[v] or v
|
||||
if GameVersion.VERSIONS and not GameVersion.VERSIONS[v] then return nil end
|
||||
|
||||
@@ -218,7 +218,7 @@ function TouchControls.defaultLayout(ww, wh, ox, oy, scale)
|
||||
local ssW = dpadW * 0.30
|
||||
local margin = dpadW * 0.12
|
||||
local ok, GameVersion = pcall(require, "src.core.GameVersion")
|
||||
if ok and GameVersion.isGold and GameVersion.isGold() then
|
||||
if ok and GameVersion.generation and GameVersion.generation() == 2 then
|
||||
margin = math.max(margin, math.min(ww * 0.10, 72))
|
||||
end
|
||||
return {
|
||||
|
||||
+24
-12
@@ -103,7 +103,7 @@ Save.PLAYER_STATES = {
|
||||
}
|
||||
|
||||
local function saveNames(version)
|
||||
version = version or "gold"
|
||||
version = version or GameVersion.get()
|
||||
-- Resolve the ACTIVE SLOT the same way SaveData does, and only fall back to
|
||||
-- the flat save_<version>.lua when no slot is registered.
|
||||
--
|
||||
@@ -133,16 +133,22 @@ local function fs()
|
||||
return love.filesystem
|
||||
end
|
||||
|
||||
-- A fresh Gold save. `opts` carries what the intro collected: player name,
|
||||
-- The blank-name fallback is the first PlayerNameArray row, which differs
|
||||
-- per edition -- data/player_names.asm:12-23.
|
||||
function Save.defaultPlayerName(version)
|
||||
return (version or GameVersion.get()) == "silver" and "SILVER" or "GOLD"
|
||||
end
|
||||
|
||||
-- A fresh Gen 2 save. `opts` carries what the intro collected: player name,
|
||||
-- rival name, and the options the OPTION screen was left on.
|
||||
function Save.newGame(opts)
|
||||
opts = opts or {}
|
||||
local save = {
|
||||
format = Save.FORMAT,
|
||||
version = "gold",
|
||||
version = GameVersion.get(),
|
||||
generation = 2,
|
||||
player = {
|
||||
name = opts.playerName or "GOLD",
|
||||
name = opts.playerName or Save.defaultPlayerName(),
|
||||
-- _ResetWRAM rolls wPlayerID out of hRandomSub/hRandomAdd
|
||||
-- (engine/menus/intro_menu.asm:41-49).
|
||||
id = opts.trainerId or rand(0, 65535),
|
||||
@@ -374,10 +380,13 @@ end
|
||||
function Save.normalize(save)
|
||||
if type(save) ~= "table" then return nil end
|
||||
save.format = save.format or Save.FORMAT
|
||||
save.version = "gold"
|
||||
if not (GameVersion.VERSIONS[save.version]
|
||||
and GameVersion.generation(save.version) == 2) then
|
||||
save.version = GameVersion.get()
|
||||
end
|
||||
save.generation = 2
|
||||
save.player = save.player or {}
|
||||
save.player.name = save.player.name or "GOLD"
|
||||
save.player.name = save.player.name or Save.defaultPlayerName(save.version)
|
||||
save.player.id = save.player.id or rand(0, 65535)
|
||||
save.player.money = math.max(0, math.min(save.player.money or 0, Save.MAX_MONEY))
|
||||
save.player.coins = math.max(0, math.min(save.player.coins or 0, Save.MAX_COINS))
|
||||
@@ -753,21 +762,24 @@ end
|
||||
-- copy is the witness that survives a crash mid-replace.
|
||||
function Save.save(save)
|
||||
if type(save) ~= "table" then return false, "no save" end
|
||||
if (save.version or "gold") == "gold" then
|
||||
Save.normalize(save)
|
||||
local version = save.version
|
||||
do
|
||||
local ok, SaveData = pcall(require, "src.core.SaveData")
|
||||
if ok and SaveData.activeSlot and not SaveData.activeSlot("gold") then
|
||||
local id = SaveData.createSlot and SaveData.createSlot("gold")
|
||||
if id and SaveData.setActiveSlot then SaveData.setActiveSlot("gold", id) end
|
||||
if ok and SaveData.activeSlot and not SaveData.activeSlot(version) then
|
||||
local id = SaveData.createSlot and SaveData.createSlot(version)
|
||||
if id and SaveData.setActiveSlot then
|
||||
SaveData.setActiveSlot(version, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
local main, backup, tmp = saveNames(save.version)
|
||||
local main, backup, tmp = saveNames(version)
|
||||
local f = fs()
|
||||
if not f then return false, "no filesystem" end
|
||||
-- saveNames may now return a saves/<version>/<slot>.lua path, and
|
||||
-- love.filesystem.write does not create missing parent directories.
|
||||
local dir = main:match("^(.*)/[^/]+$")
|
||||
if dir and f.createDirectory then f.createDirectory(dir) end
|
||||
Save.normalize(save)
|
||||
save.savedAt = os.time()
|
||||
local encoded = SaveSerializer.encode(save)
|
||||
if f.getInfo(main) then
|
||||
|
||||
Reference in New Issue
Block a user