Files
gen1recomp/tests/game3_national_dex_test.lua
bryanthaboi dee935a4ea CLOSES #2430
2026-09-23 11:58:32 -04:00

151 lines
7.6 KiB
Lua

-- Tests for 1:1 National Pokédex Gating, Systems, and Story Triggers matching pret pokefirered.
require("tests.game3_cache").requireData("game3_national_dex_test")
local Dex = require("src.core.game3.dex")
local PokedexData = require("src.core.game3.pokedex_data")
local Evolution = require("src.core.game3.evolution")
local ItemUse = require("src.core.game3.item_use")
local Std = require("src.core.game3.scripting.stdscripts")
local Natives = require("src.core.game3.scripting.natives")
local Flags = require("src.core.game3.scripting.flags")
print("=== [TEST 1] National Dex specials constants ===")
assert(Std.SPECIAL.EnableNationalPokedex == 0x16F, "EnableNationalPokedex special constant must be 0x16F")
assert(Std.SPECIAL.SetUnlockedPokedexFlags == 0x181, "SetUnlockedPokedexFlags special constant must be 0x181")
assert(Std.SPECIAL.IsNationalPokedexEnabled == 0x193, "IsNationalPokedexEnabled special constant must be 0x193")
print("[PASS] Special constants match pret specials.inc (0x16F, 0x181, 0x193)")
print("=== [TEST 2] Script Special Execution & State Machine ===")
local store = Flags.newStore()
local Space = { store = store }
function Space.ensureBundle()
if not Space.bundle then require("tests.game3_cache").bundle() end
return Space.bundle
end
package.loaded["src.core.game3.scripting.space"] = Space
local session = {
national_dex_unlocked = false,
dex = Dex.new(),
store = store,
}
local Runtime = {
getSession = function() return session end,
}
package.loaded["src.core.game3.runtime"] = Runtime
-- 1. Check IsNationalPokedexEnabled before unlock (should be 0)
local ctx = require("src.core.game3.scripting.ctx").new({})
Flags.setVar(store, ctx, 0x800D, 9)
local _, natVal = Natives.special(ctx, Std.SPECIAL.IsNationalPokedexEnabled)
assert(natVal == 0, "IsNationalPokedexEnabled should hand specialvar 0 before unlock")
assert(Flags.getVar(store, ctx, 0x800D) == 0, "IsNationalPokedexEnabled should set VAR_RESULT to 0 before unlock")
assert(not PokedexData.isNationalUnlocked(session, session.dex), "isNationalUnlocked must return false before unlock")
-- 2. Execute EnableNationalPokedex
Natives.special(ctx, Std.SPECIAL.EnableNationalPokedex)
assert(Flags.getFlag(store, nil, 0x840) == true, "EnableNationalPokedex must set FLAG_SYS_NATIONAL_DEX (0x840)")
assert(Flags.getVar(store, nil, 0x404E) == 0x6258, "EnableNationalPokedex must set VAR_NATIONAL_DEX (0x404E) to 0x6258")
assert(session.national_dex_unlocked == true, "session.national_dex_unlocked must be true")
assert(session.dex.nationalUnlocked == true, "dex.nationalUnlocked must be true")
-- 3. Check IsNationalPokedexEnabled after unlock (should be 1)
local _, natOn = Natives.special(ctx, Std.SPECIAL.IsNationalPokedexEnabled)
assert(natOn == 1, "IsNationalPokedexEnabled should hand specialvar 1 after unlock")
assert(Flags.getVar(store, ctx, 0x800D) == 1, "IsNationalPokedexEnabled should set VAR_RESULT to 1 after unlock")
assert(PokedexData.isNationalUnlocked(session, session.dex) == true, "isNationalUnlocked must return true after unlock")
print("[PASS] Script specials EnableNationalPokedex and IsNationalPokedexEnabled verified")
print("=== [TEST 3] Evolution Gating (pret evolution_scene.c:641) ===")
-- Reset national dex
session.national_dex_unlocked = false
session.dex.nationalUnlocked = false
Flags.setFlag(store, nil, 0x840, false)
Flags.setVar(store, nil, 0x404E, 0)
-- Golbat (42) evolving into Crobat (169) by friendship
local golbat = { species = 42, level = 50, friendship = 220 }
local crobatTarget = Evolution.levelTarget(golbat, session)
-- Should be blocked (nil) before National Dex
assert(crobatTarget == nil, "Golbat cannot evolve into Crobat (169 > 151) when National Dex is locked")
-- Onix (95) evolving into Steelix (208) with Metal Coat
local onix = { species = 95, level = 30 }
local steelixTarget = Evolution.itemTarget(onix, "ITEM_METAL_COAT", session)
assert(steelixTarget == nil, "Onix cannot evolve into Steelix (208 > 151) when National Dex is locked")
-- Kanto evolution (Bulbasaur 1 -> Ivysaur 2) is allowed
local bulbasaur = { species = 1, level = 16 }
local ivysaurTarget = Evolution.levelTarget(bulbasaur, session)
assert(ivysaurTarget == 2, "Kanto evolutions (1 -> 2) must remain allowed when National Dex is locked")
-- Now unlock National Dex: Golbat -> Crobat must be allowed
session.national_dex_unlocked = true
Flags.setFlag(store, nil, 0x840, true)
local crobatUnlocked = Evolution.levelTarget(golbat, session)
assert(crobatUnlocked == 169, "Golbat must evolve into Crobat (169) once National Dex is unlocked")
print("[PASS] Evolution gating before/after National Dex verified")
print("=== [TEST 4] Capture Registration Gating ===")
local lockedStore = Flags.newStore()
Space.store = lockedStore
local lockedDex = Dex.new()
local lockedSession = { national_dex_unlocked = false, dex = lockedDex, store = lockedStore }
Runtime.getSession = function() return lockedSession end
-- Try to register non-Kanto species (169 = Crobat, 252 = Treecko) before National Dex
Dex.registerEncounter(lockedDex, 169, lockedSession)
Dex.registerCapture(lockedDex, 169, lockedSession)
assert(not Dex.isSeen(lockedDex, 169), "Crobat should NOT be marked seen in locked Kanto Dex")
assert(not Dex.isCaught(lockedDex, 169), "Crobat should NOT be marked caught in locked Kanto Dex")
-- Kanto species (19 = Rattata) registers normally
Dex.registerEncounter(lockedDex, 19, lockedSession)
Dex.registerCapture(lockedDex, 19, lockedSession)
assert(Dex.isSeen(lockedDex, 19) == true, "Rattata must be marked seen in locked Kanto Dex")
assert(Dex.isCaught(lockedDex, 19) == true, "Rattata must be marked caught in locked Kanto Dex")
-- Unlock National Dex: Crobat now registers normally
local unlockedDex = Dex.new()
unlockedDex.nationalUnlocked = true
local unlockedSession = { national_dex_unlocked = true, dex = unlockedDex, store = Flags.newStore() }
Flags.setFlag(unlockedSession.store, nil, 0x840, true)
Runtime.getSession = function() return unlockedSession end
Dex.registerEncounter(unlockedDex, 169, unlockedSession)
Dex.registerCapture(unlockedDex, 169, unlockedSession)
assert(Dex.isSeen(unlockedDex, 169) == true, "Crobat MUST be marked seen in unlocked National Dex")
assert(Dex.isCaught(unlockedDex, 169) == true, "Crobat MUST be marked caught in unlocked National Dex")
print("=== [TEST 5] Pokédex Top Menu Mode Gating ===")
local Pokedex = require("src.ui.game3.pokedex")
Pokedex.show(lockedDex, { session = lockedSession })
local lockedModes = Pokedex.MODES
local hasNationalMode = false
local hasSearch = false
for _, m in ipairs(lockedModes) do
if m.id == "numerical_national" then hasNationalMode = true end
if m.id == "atoz" or m.id == "type" then hasSearch = true end
end
assert(not hasNationalMode, "Locked Pokédex must NOT have NUMERICAL MODE: NATIONAL")
-- pokefirered/src/pokedex_screen.c:333-337
assert(hasSearch, "Locked Pokédex keeps the SEARCH section of sListMenuItems_KantoDexModeSelect")
assert(Pokedex.maxSpecies() == 151, "Locked Pokédex maxSpecies must be 151")
-- Open with unlocked National Dex
Pokedex.show(unlockedDex, { session = unlockedSession })
local unlockedModes = Pokedex.MODES
local hasKantoMode = false
local hasNatMode = false
local hasAtoZ = false
for _, m in ipairs(unlockedModes) do
if m.id == "numerical_kanto" then hasKantoMode = true end
if m.id == "numerical_national" then hasNatMode = true end
if m.id == "atoz" then hasAtoZ = true end
end
assert(hasKantoMode, "Unlocked Pokédex must have NUMERICAL MODE: KANTO")
assert(hasNatMode, "Unlocked Pokédex must have NUMERICAL MODE: NATIONAL")
assert(hasAtoZ, "Unlocked Pokédex must have SEARCH section with A TO Z MODE")
print("[PASS] Pokédex top menu modes before/after National Dex unlock verified")
print("=== ALL NATIONAL DEX GATING TESTS PASSED! ===")