Files
gen1recomp/tests/engine/game3_emerald_data_layouts_test.lua
T
bryanthaboi 690f0cd9a1 TOUCHDOWN
2026-09-27 16:07:31 -04:00

129 lines
5.6 KiB
Lua

package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.harness")
local check, eq = T.check, T.eq
local Layouts = require("src.import.gba.layouts.registry")
local Versions = require("src.import.gba.versions")
local Plans = require("src.import.gba.plans.registry")
local fr = Layouts.of("firered")
eq(fr.id, "frlg", "firered uses the frlg layout")
eq(Layouts.of("leafgreen"), fr, "leafgreen shares the frlg layout")
eq(fr.pokedexEntry.size, 36, "frlg PokedexEntry is 36 bytes")
eq(fr.pokedexEntry.desc2, 20, "frlg keeps the second description pointer")
eq(fr.pokedexEntry.pokemonScale, 26, "frlg pokemonScale at 26")
eq(fr.trainerNameLen, 12, "frlg trainer name 12 bytes")
eq(fr.trainerBackPicCount, 6, "frlg 6 back pics")
eq(fr.tutorLearnsetBytes, 2, "frlg tutor learnsets are u16")
eq(fr.trainerExtras, false, "frlg trainers.lua has no extra sections")
eq(fr.inlineTrainerDialogs, true, "frlg inlines dialogs")
eq(fr.regionalDex, nil, "frlg has no regional order file")
local em = Layouts.of("emerald")
eq(em.id, "emerald", "emerald layout")
eq(em.pokedexEntry.size, 32, "emerald PokedexEntry is 32 bytes")
eq(em.pokedexEntry.desc2, nil, "emerald has one description")
eq(em.pokedexEntry.pokemonScale, 22, "emerald pokemonScale at 22")
eq(em.pokedexEntry.trainerOffset, 28, "emerald trainerOffset at 28")
eq(em.trainerNameLen, 11, "emerald trainer name 11 bytes")
eq(em.tutorLearnsetBytes, 4, "emerald tutor learnsets are u32")
eq(em.regionalDex.name, "hoenn", "emerald regional dex")
eq(em.inlineTrainerDialogs, false, "emerald dialogs go to trainers/dialogs.lua")
local frp = Layouts.pockets(fr)
eq(frp[1], "ITEMS", "fr pocket 1")
eq(frp[2], "KEY_ITEMS", "fr pocket 2")
eq(frp[3], "POKE_BALLS", "fr pocket 3")
eq(frp[4], "TM_CASE", "fr pocket 4")
eq(frp[5], "BERRY_POUCH", "fr pocket 5")
local emp = Layouts.pockets(em)
eq(emp[1], "ITEMS", "em pocket 1")
eq(emp[2], "POKE_BALLS", "em pocket 2")
eq(emp[3], "TM_HM", "em pocket 3")
eq(emp[4], "BERRIES", "em pocket 4")
eq(emp[5], "KEY_ITEMS", "em pocket 5")
local ok = pcall(Layouts.of, "red")
eq(ok, false, "non gen 3 id raises")
local E = Versions.forGame("emerald")
eq(E.ITEMS_COUNT, 377, "377 items")
eq(E.ITEM_EFFECT_FIRST, 13, "item effects start at ITEM_POTION")
eq(E.ITEM_EFFECT_LAST, 175, "163 item effect pointers")
eq(E.TRAINERS_COUNT, 855, "855 trainers")
eq(E.TRAINER_BACK_PIC_COUNT, 8, "8 trainer back pics")
eq(E.TRAINER_MONEY_COUNT, 56, "56 money rows")
eq(E.REMATCH_COUNT, 78, "78 rematch rows")
eq(E.UNION_ROOM_FACILITY_CLASS_COUNT, 16, "16 union room classes")
eq(E.TUTOR_MOVE_COUNT, 30, "30 tutor moves")
eq(E.INGAME_TRADE_COUNT, 4, "4 in-game trades")
eq(E.INGAME_TRADE_MAIL_COUNT, 3, "3 trade mails")
eq(E.BERRY_COUNT, 43, "43 berries")
eq(E.POKEBLOCK_NAME_COUNT, 15, "15 pokeblock names")
eq(E.CONTEST_MOVES_COUNT, 355, "355 contest moves")
eq(E.CONTEST_EFFECTS_COUNT, 48, "48 contest effects")
eq(E.CONTEST_CATEGORY_COUNT, 5, "5 contest categories")
eq(E.FRONTIER.mons.count, 882, "882 frontier mons")
eq(E.FRONTIER.trainers.count, 300, "300 frontier trainers")
eq(E.FRONTIER.heldItems.count, 63, "63 frontier held items")
eq(E.FRONTIER.brainMons.count, 42, "7 brains x 2 symbols x 3 mons")
eq(E.FRONTIER.apprentices.count, 16, "16 apprentices")
eq(#E.FRONTIER.tents, 3, "3 battle tents")
eq(E.FRONTIER.tents[1].mons.count, 70, "Slateport tent 70 mons")
eq(E.FRONTIER.tents[2].trainers.count, 30, "Verdanturf tent 30 trainers")
local S = E.SYMS
for key, name in pairs({
medicine = "ItemUseOutOfBattle_Medicine", ether = "ItemUseOutOfBattle_PPRecovery",
repel = "ItemUseOutOfBattle_Repel", reduce_ev = "ItemUseOutOfBattle_ReduceEV",
}) do
eq(S.funcAt(E.FIELD_USE_FUNCS[key] + 0x08000001), name, "field use " .. key .. " resolves by name")
end
local FRV = Versions.forGame("firered")
eq(FRV.CONTEST_MOVES, nil, "firered has no contest move key")
eq(FRV.FRONTIER, nil, "firered has no frontier key")
eq(FRV.TUTOR_MOVE_COUNT, 15, "firered 15 tutors")
local plan = Plans.of("emerald")
local want = {
items_extract = true, battle_moves_extract = true, contest_moves_extract = true, tutor_extract = true,
ingame_trades_extract = true, berries_extract = true, pokedex_entries_extract = true,
frontier_data_extract = true, trainer_extract = true,
}
local seen = {}
for _, task in ipairs(plan.tasks) do
for _, step in ipairs(task.steps or {}) do
if want[step.name] then
seen[step.name] = true
local mod = require(Plans.moduleFor(step.name))
check(type(mod.run) == "function", step.name .. " has run")
check(type(mod.ready) == "function", step.name .. " has ready")
check(type(mod.REQUIRED) == "table" and #mod.REQUIRED > 0, step.name .. " exports REQUIRED")
end
end
end
for name in pairs(want) do check(seen[name], "rse plan runs " .. name) end
local frPlan = Plans.of("firered")
for _, task in ipairs(frPlan.tasks) do
for _, step in ipairs(task.steps or {}) do
check(not want[step.name], "frlg plan does not gain " .. tostring(step.name))
end
end
local required = Plans.required(plan, "data/generated/gba")
local have = {}
for _, p in ipairs(required) do have[p] = true end
for _, p in ipairs({
"data/generated/gba/items/pack.lua", "data/generated/gba/trainers.lua",
"data/generated/gba/pokemon/contest_moves.lua", "data/generated/gba/pokemon/tutor.lua",
"data/generated/gba/trades/ingame_trades.lua", "data/generated/gba/berries/berries.lua",
"data/generated/gba/pokemon/pokedex/entries.lua", "data/generated/gba/pokemon/pokedex/regional.lua",
"data/generated/gba/frontier/mons.lua", "data/generated/gba/frontier/trainers.lua",
}) do
check(have[p], "emerald contract requires " .. p)
end
T.finish("game3_emerald_data_layouts_test")