mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-29 07:00:55 -04:00
174 lines
6.9 KiB
Lua
174 lines
6.9 KiB
Lua
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local T = require("tests.harness")
|
|
local check, eq = T.check, T.eq
|
|
|
|
local function cacheRoot()
|
|
local explicit = os.getenv("POKEPORT_EMERALD_CACHE")
|
|
if explicit and explicit ~= "" then return explicit end
|
|
local identity = os.getenv("POKEPORT_IDENTITY")
|
|
local home = os.getenv("HOME")
|
|
if not (identity and identity ~= "" and home) then return nil end
|
|
for _, base in ipairs({ home .. "/Library/Application Support/LOVE/", home .. "/.local/share/love/" }) do
|
|
local root = base .. identity .. "/emerald"
|
|
local f = io.open(root .. "/data/generated/gba/scripts/scripts.lua", "rb")
|
|
if f then
|
|
f:close()
|
|
return root
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local ROOT = cacheRoot()
|
|
if not ROOT then
|
|
print("emerald_story_scripts_test: skipped (set POKEPORT_IDENTITY to an identity with an Emerald cache)")
|
|
os.exit(0)
|
|
end
|
|
|
|
local function loadLua(rel)
|
|
local f = io.open(ROOT .. "/" .. rel, "rb")
|
|
if not f then return nil end
|
|
local src = f:read("*a")
|
|
f:close()
|
|
local chunk = load(src, "@" .. rel, "t", {})
|
|
return chunk and chunk() or nil
|
|
end
|
|
|
|
local GameVersion = require("src.core.GameVersion")
|
|
local prevVersion = GameVersion.get()
|
|
GameVersion.set("emerald")
|
|
|
|
local Opcodes = require("src.core.game3.scripting.opcodes")
|
|
local Natives = require("src.core.game3.scripting.natives")
|
|
local Movement = require("src.core.game3.scripting.movement")
|
|
local Constants = require("src.core.game3.constants")
|
|
local C = Constants.of("emerald")
|
|
|
|
local S = "data/generated/gba/scripts/"
|
|
local scripts = assert(loadLua(S .. "scripts.lua"), "scripts.lua")
|
|
local events = assert(loadLua(S .. "events.lua"), "events.lua")
|
|
local labels = assert(loadLua(S .. "labels.lua"), "labels.lua")
|
|
local movements = assert(loadLua(S .. "movements.lua"), "movements.lua")
|
|
|
|
local MAPS = {
|
|
"EM_INSIDE_OF_TRUCK", "EM_LITTLEROOT_TOWN", "EM_LITTLEROOT_TOWN_BRENDANS_HOUSE_1F",
|
|
"EM_LITTLEROOT_TOWN_BRENDANS_HOUSE_2F", "EM_LITTLEROOT_TOWN_MAYS_HOUSE_1F", "EM_LITTLEROOT_TOWN_MAYS_HOUSE_2F",
|
|
"EM_ROUTE101", "EM_LITTLEROOT_TOWN_PROFESSOR_BIRCHS_LAB",
|
|
}
|
|
|
|
local seeds, seen = {}, {}
|
|
local function add(k)
|
|
if type(k) == "string" and not seen[k] then
|
|
seen[k] = true
|
|
seeds[#seeds + 1] = k
|
|
end
|
|
end
|
|
for _, m in ipairs(MAPS) do
|
|
local e = events[m]
|
|
check(e ~= nil, m .. " has events")
|
|
for _, o in ipairs(e and e.objects or {}) do add(o.scriptKey) end
|
|
for _, o in ipairs(e and e.bgEvents or {}) do add(o.scriptKey) end
|
|
for _, o in ipairs(e and e.coordEvents or {}) do add(o.scriptKey) end
|
|
for _, v in pairs(e and e.mapScripts or {}) do
|
|
if type(v) == "string" then add(v) else for _, r in ipairs(v) do add(r.script) end end
|
|
end
|
|
end
|
|
add(labels.EventScript_TV)
|
|
add("EventScript_ResetAllMapFlags")
|
|
|
|
local opNames = {}
|
|
local set = Opcodes.forGame("emerald")
|
|
for byte = 0, set.MAX do
|
|
local r = set:get(byte)
|
|
if r then opNames[r.name] = true end
|
|
end
|
|
for _, alias in ipairs({ "goto_if", "call_if", "callstd_if", "gotostd_if", "vgoto_if", "vcall_if" }) do opNames[alias] = true end
|
|
|
|
local specials, unknownOps, moves = {}, {}, {}
|
|
local i = 1
|
|
while i <= #seeds do
|
|
local key = seeds[i]
|
|
i = i + 1
|
|
for _, r in ipairs(scripts[key] or {}) do
|
|
if not opNames[r.op] then unknownOps[r.op] = true end
|
|
if r.op == "special" then specials[tonumber(r.id or r[1])] = true end
|
|
if r.op == "specialvar" then specials[tonumber(r.id or r[2])] = true end
|
|
if r.op == "callstd" or r.op == "gotostd" then add("std:" .. tostring(r.std or r[1])) end
|
|
if r.op == "applymovement" then moves[#moves + 1] = r.movement or r[2] end
|
|
for _, v in pairs(r) do
|
|
if type(v) == "string" and v:match("^g3:") and scripts[v] then add(v) end
|
|
end
|
|
end
|
|
end
|
|
print(string.format("emerald_story_scripts_test: %d scripts reachable from the opening maps", #seeds))
|
|
check(#seeds > 300, "the opening maps reach more than 300 scripts")
|
|
local unk = {}
|
|
for k in pairs(unknownOps) do unk[#unk + 1] = k end
|
|
table.sort(unk)
|
|
eq(#unk, 0, "every op on the opening path is an Emerald opcode (" .. table.concat(unk, ",") .. ")")
|
|
|
|
Natives.bind("emerald")
|
|
local OPENING = {
|
|
"ChooseStarter", "GetPlayerBigGuyGirlString", "GetRivalSonDaughterString", "ResetTVShowState",
|
|
"CheckForPlayersHouseNews", "IsGabbyAndTyShowOnTheAir", "GetRandomActiveShowIdx", "GetNextActiveShowIfMassOutbreak",
|
|
"GetSelectedTVShow", "GetMomOrDadStringForTVMessage", "TurnOffTVScreen", "TurnOnTVScreen", "DoTVShow", "DoPokeNews",
|
|
"DoTVShowInSearchOfTrainers", "InitSecretBaseDecorationSprites", "StartWallClock", "Special_ViewWallClock",
|
|
"HealPlayerParty", "ChangePokemonNickname", "ChangeBoxPokemonNickname", "EnableNationalPokedex",
|
|
}
|
|
local LATER = {
|
|
BedroomPC = "W3 player PC",
|
|
DoPCTurnOnEffect = "W3 PC metatile effect",
|
|
GetPCBoxToSendMon = "W3 storage (party full path)",
|
|
ShouldShowBoxWasFullMessage = "W3 storage (party full path)",
|
|
HasAllHoennMons = "W3 dex (post-game lab)",
|
|
ScriptGetPokedexInfo = "W3 dex rating",
|
|
ShowPokedexRatingMessage = "W3 dex rating",
|
|
SetUnlockedPokedexFlags = "W3 dex",
|
|
InitRoamer = "E21 roamers (post-game)",
|
|
}
|
|
local opening = {}
|
|
for _, n in ipairs(OPENING) do opening[n] = true end
|
|
local unbound = {}
|
|
for id in pairs(specials) do
|
|
local name = C.specials.byId[id]
|
|
check(name ~= nil, string.format("special 0x%X has a pret name", id))
|
|
local bound = Natives.ALLOW["special:" .. id] ~= nil
|
|
if opening[name] then
|
|
check(bound, "opening special " .. tostring(name) .. " is bound")
|
|
elseif not bound then
|
|
unbound[#unbound + 1] = name
|
|
check(LATER[name] ~= nil, "unbound special " .. tostring(name) .. " is a documented later-wave item")
|
|
end
|
|
end
|
|
table.sort(unbound)
|
|
for _, n in ipairs(unbound) do print(" later: " .. n .. " (" .. tostring(LATER[n]) .. ")") end
|
|
|
|
local nops = 0
|
|
for _, key in ipairs(moves) do
|
|
local stream = movements[key]
|
|
for _, b in ipairs(stream or {}) do
|
|
if b >= 0x100 and Movement.decodeAction(b).kind == "nop" then nops = nops + 1 end
|
|
end
|
|
end
|
|
eq(nops, 0, "no canonical RSE movement action on the opening path decodes to nop")
|
|
|
|
local man = loadLua("data/generated/gba/starter_choose/manifest.lua")
|
|
if check(man ~= nil, "starter_choose manifest in the cache") then
|
|
-- pokeemerald/src/starter_choose.c:113
|
|
eq(man.species[1], C.species.byName.SPECIES_TREECKO, "starter 0 is Treecko")
|
|
eq(man.species[2], C.species.byName.SPECIES_TORCHIC, "starter 1 is Torchic")
|
|
eq(man.species[3], C.species.byName.SPECIES_MUDKIP, "starter 2 is Mudkip")
|
|
eq(man.pokeballCoords[2][1], 120, "middle ball x (starter_choose.c:99)")
|
|
eq(man.pokeballCoords[2][2], 88, "middle ball y")
|
|
eq(man.cursorCoords[3][1], 180, "right cursor x (starter_choose.c:204)")
|
|
eq(man.windows.confirm.tilemapLeft, 24, "YES/NO window left (starter_choose.c:77)")
|
|
eq(man.windows.message.width, 24, "message window width (starter_choose.c:63)")
|
|
eq(man.affine.circle[1].xScale, 20, "circle affine starts at 20 (starter_choose.c:274)")
|
|
eq(man.sprites.pokeball.frames, 3, "pokeball sheet has the still + two wobble frames")
|
|
end
|
|
|
|
Natives.bind("firered")
|
|
GameVersion.set(prevVersion)
|
|
T.finish()
|