From a12952dccbf447d53cf4d6a278efc87e824eb0a6 Mon Sep 17 00:00:00 2001 From: bryanthaboi Date: Fri, 9 Oct 2026 13:13:34 -0400 Subject: [PATCH] CLOSES #2814 --- src/core/game3/map.lua | 8 +- src/core/game3/time_events.lua | 5 +- src/ui/game3/rs/trainer_card_policy.lua | 20 +++-- .../game3_rs_trainer_card_continue_2814.lua | 78 +++++++++++++++++++ tests/game3_rs_trainer_card_flags_test.lua | 9 +++ tests/game3_time_events_store_test.lua | 43 ++++++++++ 6 files changed, 148 insertions(+), 15 deletions(-) create mode 100644 tests/drivers/game3_rs_trainer_card_continue_2814.lua create mode 100644 tests/game3_time_events_store_test.lua diff --git a/src/core/game3/map.lua b/src/core/game3/map.lua index 05675d02..3489ed14 100644 --- a/src/core/game3/map.lua +++ b/src/core/game3/map.lua @@ -726,15 +726,15 @@ function Map.load(mod, game, mapId, opts) -- pokeemerald/src/overworld.c:801 require("src.core.game3.rse.rematch").tryUpdateRandomTrainerRematchesForMap(session, mapId) end - -- pokeemerald/src/overworld.c:802 - if session and require("src.core.game3.rtc").enabled(session) then - require("src.core.game3.time_events").run(session) - end if opts.keepScript and Space and Space.retarget then Space.retarget(mod or Runtime._mod, mapId, game, world) elseif Space and Space.activate then Space.activate(mod or Runtime._mod, mapId, game, world) end + -- pokeemerald/src/overworld.c:802 + if session and require("src.core.game3.rtc").enabled(session) then + require("src.core.game3.time_events").run(session) + end -- pokefirered/src/overworld.c:805 local savedFlash = session and tonumber(session.flashLevel) diff --git a/src/core/game3/time_events.lua b/src/core/game3/time_events.lua index f764439d..b2366a58 100644 --- a/src/core/game3/time_events.lua +++ b/src/core/game3/time_events.lua @@ -57,13 +57,12 @@ local function storeOf(session, opts) local Runtime = package.loaded["src.core.game3.runtime"] local live = Runtime and Runtime.getSession and Runtime.getSession() or nil if Space and Space.store and (live == nil or live == session) then return Space.store end - if type(session) == "table" then - session.store = session.store or { flags = {}, vars = {} } + if type(session) == "table" and type(session.store) == "table" then session.store.flags = session.store.flags or {} session.store.vars = session.store.vars or {} return session.store end - return nil + return { flags = {}, vars = {} } end local function flags() diff --git a/src/ui/game3/rs/trainer_card_policy.lua b/src/ui/game3/rs/trainer_card_policy.lua index 0598a8f2..e5f0bf93 100644 --- a/src/ui/game3/rs/trainer_card_policy.lua +++ b/src/ui/game3/rs/trainer_card_policy.lua @@ -10,16 +10,20 @@ function P.generate(session, version) local Space = package.loaded["src.core.game3.scripting.space"] local Runtime = package.loaded["src.core.game3.runtime"] local current = Runtime and Runtime.getSession and Runtime.getSession() - local live = s.store == nil and (current == nil or current == s) and Space and Space.getStore and Space.getStore() or nil - local store, stats = s.store or live or s, s.gameStats or {} + local Flags = require("src.core.game3.scripting.flags") + local live = (current == nil or current == s) and Space and Space.getStore and Space.getStore() or nil + local sources = {} + for _, src in ipairs({live or false, s.store or false, s}) do + if src and type(src.flags) == "table" then sources[#sources + 1] = src end + end + local store, stats = sources[1] or s, s.gameStats or {} local tower = s.battleTower or {} local function flag(name) - local id, flags = C:require("flags", name), store.flags or {} - local v = flags[id] - if v == nil then v = flags[tostring(id)] end - if v == nil then v = flags[string.format("0x%X", id)] end - if v == nil then v = flags[name] end - return v == true or v == 1 + local id = C:require("flags", name) + for _, src in ipairs(sources) do + if Flags.getFlag(src, nil, id) then return true end + end + return false end -- save_menu_util.c:118 local _, caught = Policy.counts(s, Dex.nationalEnabled({version = version, dex = s.dex, flags = store.flags, vars = store.vars})) diff --git a/tests/drivers/game3_rs_trainer_card_continue_2814.lua b/tests/drivers/game3_rs_trainer_card_continue_2814.lua new file mode 100644 index 00000000..b7651e4e --- /dev/null +++ b/tests/drivers/game3_rs_trainer_card_continue_2814.lua @@ -0,0 +1,78 @@ +local U = require("tests.drivers.util") + +local MARKER = "drv2814_seeded" +local failures = 0 +local function check(ok, label) + print((ok and "PASS " or "FAIL ") .. "card2814 " .. label) + if not ok then failures = failures + 1 end + return ok +end +local function finish() + print((failures == 0 and "PASS " or "FAIL ") .. "card2814 failures=" .. failures) + love.event.quit(failures == 0 and 0 or 1) +end + +local function cardChecks(session, tag) + local Space = require("src.core.game3.scripting.space") + local Flags = require("src.core.game3.scripting.flags") + local C = require("src.core.game3.constants").of(session.version) + local dex, b1 = C:require("flags", "FLAG_SYS_POKEDEX_GET"), C:require("flags", "FLAG_BADGE01_GET") + check(session.store == nil, tag .. "_no_fabricated_session_store") + check(Flags.getFlag(Space.store, nil, dex) and Flags.getFlag(Space.store, nil, b1) and Flags.getFlag(Space.store, nil, b1 + 1), + tag .. "_live_store_has_dex_and_badges") + if session.version == "ruby" or session.version == "sapphire" then + local card = require("src.ui.game3.rs.trainer_card_policy").generate(session) + check(card.hasPokedex == true, tag .. "_card_hasPokedex") + check(card.badges[1] == true and card.badges[2] == true and card.badges[3] == false, tag .. "_card_badges_1_2") + end +end + +local function bootReady(game) + for _ = 1, 600 do + if game.phase == "boot" and game.boot then break end + U.wait(1) + end + return check(game.phase == "boot" and game.boot ~= nil, "boot_ready") +end + +local function seed(game) + game:_handleBootAction({ action = "new_game", name = "TAI" }) + U.wait(180) + local session = require("src.core.game3.runtime").getSession() + if not check(session ~= nil, "seed_field_session_ready") then return end + local Space = require("src.core.game3.scripting.space") + local Flags = require("src.core.game3.scripting.flags") + local C = require("src.core.game3.constants").of(session.version) + Flags.setFlag(Space.store, nil, C:require("flags", "FLAG_SYS_POKEDEX_GET"), true) + Flags.setFlag(Space.store, nil, C:require("flags", "FLAG_SYS_CLOCK_SET"), true) + for i = 0, 1 do Flags.setFlag(Space.store, nil, C:require("flags", "FLAG_BADGE01_GET") + i, true) end + cardChecks(session, "seed") + if check(game:saveGame() ~= false, "seed_save_written") then + love.filesystem.write(MARKER, "1") + print("card2814 seeded; run again to continue") + end +end + +local function continueAndOpen(game) + game:_handleBootAction({ action = "continue" }) + U.wait(180) + local session = require("src.core.game3.runtime").getSession() + if not check(session ~= nil, "continue_field_session_ready") then return end + cardChecks(session, "continue") + local Card = require("src.ui.game3.screens").get("trainer_card", session) + Card.show({ session = session }) + U.wait(120) + local shots = os.getenv("POKEPORT_SHOT_DIR") + if shots then U.still(game, shots .. "/2814_card_front_" .. tostring(session.version) .. ".png") end + love.filesystem.remove(MARKER) +end + +return function(game) + if not bootReady(game) then return finish() end + if love.filesystem.getInfo(MARKER) then + continueAndOpen(game) + else + seed(game) + end + finish() +end diff --git a/tests/game3_rs_trainer_card_flags_test.lua b/tests/game3_rs_trainer_card_flags_test.lua index 70fce494..a856283f 100644 --- a/tests/game3_rs_trainer_card_flags_test.lua +++ b/tests/game3_rs_trainer_card_flags_test.lua @@ -51,7 +51,16 @@ for _, version in ipairs({ "ruby", "sapphire" }) do card = Policy.generate(stale) check(card.hasPokedex == true, version .. " live script store: pokedex row shown") check(owned(card) == "1,2,3,4,5,6,7,8", version .. " live script store: all badges (" .. owned(card) .. ")") + + local withEmpty = { version = version, name = "MAY", flags = saved.flags, vars = saved.vars, store = { flags = {}, vars = {} } } + card = Policy.generate(withEmpty) + check(card.hasPokedex == true, version .. " empty session.store + live store: pokedex row shown") + check(owned(card) == "1,2,3,4,5,6,7,8", version .. " empty session.store + live store: live badges (" .. owned(card) .. ")") package.loaded["src.core.game3.scripting.space"] = nil + + card = Policy.generate(withEmpty) + check(card.hasPokedex == true, version .. " empty session.store, no live store: session.flags pokedex") + check(owned(card) == "1,4", version .. " empty session.store, no live store: session.flags badges 1,4 (" .. owned(card) .. ")") end if failed > 0 then diff --git a/tests/game3_time_events_store_test.lua b/tests/game3_time_events_store_test.lua new file mode 100644 index 00000000..d753b12f --- /dev/null +++ b/tests/game3_time_events_store_test.lua @@ -0,0 +1,43 @@ +#!/usr/bin/env luajit + +package.path = "./?.lua;./?/init.lua;" .. package.path + +local failed = 0 +local function check(cond, msg) + if cond then + print("[ok] " .. msg) + else + failed = failed + 1 + print("[FAIL] " .. msg) + end +end + +package.loaded["src.core.game3.scripting.space"] = { store = nil, getStore = function() return nil end } +local Flags = require("src.core.game3.scripting.flags") +local TimeEvents = require("src.core.game3.time_events") + +for _, version in ipairs({ "ruby", "sapphire", "emerald" }) do + local session = { version = version, name = "MAY", flags = {}, vars = {} } + TimeEvents.run(session) + check(session.store == nil, version .. " run without live store leaves session.store nil") + TimeEvents.init(session) + check(session.store == nil, version .. " init without live store leaves session.store nil") + + local live = Flags.newStore() + package.loaded["src.core.game3.scripting.space"] = { store = live, getStore = function() return live end } + local s2 = { version = version, name = "MAY", flags = {}, vars = {} } + TimeEvents.run(s2) + check(s2.store == nil, version .. " run with live store leaves session.store nil") + package.loaded["src.core.game3.scripting.space"] = { store = nil, getStore = function() return nil end } + + local own = { flags = {}, vars = {} } + local s3 = { version = version, name = "MAY", flags = {}, vars = {}, store = own } + TimeEvents.run(s3) + check(s3.store == own, version .. " existing session.store is kept") +end + +if failed > 0 then + print(string.format("%d failure(s)", failed)) + os.exit(1) +end +print("all ok")