mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-28 06:49:29 -04:00
Merge pull request #2207 from wild1walker/claude/gen2-cart-save-scope
This commit is contained in:
+39
-4
@@ -118,13 +118,34 @@ local function saveNames(version)
|
||||
-- no save and dropped CONTINUE (and a following SAVE wrote a second copy to
|
||||
-- the flat path the launcher no longer looks at). Reading through the same
|
||||
-- slot resolution keeps the in-game load/save and the launcher on one file.
|
||||
--
|
||||
-- Resolve the SCOPE the same way as well. A cart's saves are keyed by cart
|
||||
-- id rather than by version: SaveData resolves every path through
|
||||
-- `activeScopeKey`, which answers `cart_<id>` while one is active, and the
|
||||
-- launcher lists, creates and selects a cart's slots from the `cartSlots`
|
||||
-- registry (RomImporter._refreshSlots / _selectSlot / _newSlot). This
|
||||
-- module asked in the version's name alone, so a Gen 2 cart read and wrote
|
||||
-- the BASE GAME's playthrough. Gen 1 was unaffected because it saves
|
||||
-- through SaveData, which is already cart-scoped.
|
||||
local ok, SaveData = pcall(require, "src.core.SaveData")
|
||||
local slot = ok and SaveData.activeSlot and SaveData.activeSlot(version) or nil
|
||||
SaveData = ok and SaveData or nil
|
||||
local cart = SaveData and SaveData.getCart and SaveData.getCart() or nil
|
||||
if type(cart) ~= "string" or cart == "" then cart = nil end
|
||||
local slot
|
||||
if cart then
|
||||
slot = SaveData.activeCartSlot and SaveData.activeCartSlot(cart) or nil
|
||||
elseif SaveData then
|
||||
slot = SaveData.activeSlot and SaveData.activeSlot(version) or nil
|
||||
end
|
||||
if slot then
|
||||
local main = "saves/" .. version .. "/" .. slot .. ".lua"
|
||||
local scope = cart and ("cart_" .. cart) or version
|
||||
local main = "saves/" .. scope .. "/" .. slot .. ".lua"
|
||||
return main, main .. ".bak", main .. ".tmp"
|
||||
end
|
||||
local main = "save" .. GameVersion.saveSuffix(version) .. ".lua"
|
||||
-- SaveData.legacyNames names a cart "save_cart_<id>.lua" and a version by
|
||||
-- its own suffix; this is that, so the two ends agree before slots exist.
|
||||
local suffix = cart and ("_cart_" .. cart) or GameVersion.saveSuffix(version)
|
||||
local main = "save" .. suffix .. ".lua"
|
||||
return main, main .. ".bak", main .. ".tmp"
|
||||
end
|
||||
|
||||
@@ -911,7 +932,21 @@ function Save.save(save)
|
||||
local version = save.version
|
||||
do
|
||||
local ok, SaveData = pcall(require, "src.core.SaveData")
|
||||
if ok and SaveData.activeSlot and not SaveData.activeSlot(version) then
|
||||
-- In the CART's registry when one is active, for the same reason
|
||||
-- saveNames resolves the cart's scope: otherwise the first save inside a
|
||||
-- cart registers a slot against the base game and makes it active, so the
|
||||
-- cart's playthrough appears in the launcher's list for the base version
|
||||
-- and the player's own save there is what it overwrites.
|
||||
local cart = ok and SaveData.getCart and SaveData.getCart() or nil
|
||||
if type(cart) ~= "string" or cart == "" then cart = nil end
|
||||
if ok and cart then
|
||||
if SaveData.activeCartSlot and not SaveData.activeCartSlot(cart) then
|
||||
local id = SaveData.createCartSlot and SaveData.createCartSlot(cart)
|
||||
if id and SaveData.setActiveCartSlot then
|
||||
SaveData.setActiveCartSlot(cart, id)
|
||||
end
|
||||
end
|
||||
elseif 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)
|
||||
|
||||
@@ -59,6 +59,60 @@ check("silver suffix", GameVersion.saveSuffix("silver"), "_silver")
|
||||
-- Red keeps its historical un-suffixed name, so the two can never collide.
|
||||
check("red is unsuffixed", GameVersion.saveSuffix("red"), "")
|
||||
|
||||
-- --------------------------------------------------------------- cart scope
|
||||
--
|
||||
-- A cart's saves are keyed by cart id rather than by version. SaveData
|
||||
-- resolves every path that way through `activeScopeKey`, and the launcher
|
||||
-- lists, creates and selects a cart's slots from the `cartSlots` registry --
|
||||
-- so this module has to ask in the same scope, or a Gen 2 cart reads and
|
||||
-- writes the BASE GAME's playthrough. Gen 1 never showed it because Gen 1
|
||||
-- saves through SaveData itself.
|
||||
do
|
||||
local SaveData = require("src.core.SaveData")
|
||||
local CART = "wild_crystal_nightly"
|
||||
|
||||
SaveData.setCart(CART, "hash")
|
||||
-- Before the cart has a slot of its own: SaveData.legacyNames' cart shape.
|
||||
check("a cart's flat save", (Save.filenames("gold")),
|
||||
"save_cart_" .. CART .. ".lua")
|
||||
check("its backup", (select(2, Save.filenames("gold"))),
|
||||
"save_cart_" .. CART .. ".lua.bak")
|
||||
|
||||
-- Save.save registers a slot when the scope has none, and in a cart that
|
||||
-- has to be the CART's registry: otherwise the cart's playthrough turns up
|
||||
-- in the launcher's list for the base version, and the player's own save
|
||||
-- there is what the cart then overwrites.
|
||||
Save.save(Save.newGame({ playerName = "GOLD" }))
|
||||
local opts = SaveData.loadOptions()
|
||||
check("no phantom slot against the base game",
|
||||
opts.saveSlots and opts.saveSlots.gold, nil)
|
||||
local reg = opts.cartSlots and opts.cartSlots[CART]
|
||||
local slot = reg and reg.list and reg.list[1]
|
||||
check("one slot in the cart's own registry", reg and #reg.list, 1)
|
||||
|
||||
-- And it resolves to SaveData.slotDir's cart shape, which is exactly where
|
||||
-- the launcher's cart slot list looks for it.
|
||||
check("a cart's slot save", (Save.filenames("gold")),
|
||||
"saves/cart_" .. CART .. "/" .. slot .. ".lua")
|
||||
|
||||
-- A slot the base game has of its own does not win over the cart's, and the
|
||||
-- cart's does not follow the base game back out of the cart.
|
||||
local baseSlot = SaveData.createSlot("gold")
|
||||
SaveData.setActiveSlot("gold", baseSlot)
|
||||
check("the cart's scope still wins", (Save.filenames("gold")),
|
||||
"saves/cart_" .. CART .. "/" .. slot .. ".lua")
|
||||
SaveData.setCart(nil)
|
||||
check("and the base game keeps its own", (Save.filenames("gold")),
|
||||
"saves/gold/" .. baseSlot .. ".lua")
|
||||
|
||||
-- Leave no registry behind: the checks below expect the flat name, which is
|
||||
-- what a scope with no slot registered resolves to.
|
||||
SaveData.deleteCartSlot(CART, slot)
|
||||
SaveData.deleteSlot("gold", baseSlot)
|
||||
SaveData.resetSlotState()
|
||||
check("nothing is left registered", (Save.filenames("gold")), "save_gold.lua")
|
||||
end
|
||||
|
||||
-- ----------------------------------------------------------------- new game
|
||||
|
||||
local fresh = Save.newGame({ playerName = "GOLD", rivalName = "SILVER" })
|
||||
|
||||
Reference in New Issue
Block a user