mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
420 lines
18 KiB
Lua
420 lines
18 KiB
Lua
#!/usr/bin/env luajit
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
require("tests.fixture_data.game3_items").install()
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local Ctx = require("src.core.game3.scripting.ctx")
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
local Std = require("src.core.game3.scripting.stdscripts")
|
|
local Natives = require("src.core.game3.scripting.natives")
|
|
local Ops = require("src.core.game3.scripting.ops_a")
|
|
local Dex = require("src.core.game3.dex")
|
|
local Storage = require("src.core.game3.storage")
|
|
|
|
local store = Flags.newStore()
|
|
local keyText = setmetatable({}, {
|
|
__index = function(_, key) return require("src.core.game3.scripting.text_ir").fromAscii(key) end,
|
|
})
|
|
package.loaded["src.core.game3.scripting.space"] = {
|
|
store = store,
|
|
ensureBundle = function() return { text = keyText } end,
|
|
}
|
|
|
|
local function newCtx()
|
|
local ctx = Ctx.new({})
|
|
ctx.mode = "bytecode"
|
|
ctx.status = "running"
|
|
return ctx
|
|
end
|
|
|
|
local function session(tbl)
|
|
package.loaded["src.core.game3.runtime"] = {
|
|
getSession = function() return tbl end,
|
|
isActive = function() return true end,
|
|
}
|
|
return tbl
|
|
end
|
|
|
|
local a = { log = function() end }
|
|
local function exec(ctx, row)
|
|
return Ops.dispatch({ ctx = ctx, store = store, adapters = a, setPc = function() end }, row)
|
|
end
|
|
local function specialvar(ctx, dest, id)
|
|
exec(ctx, { op = "specialvar", [1] = dest, [2] = id })
|
|
return Flags.getVar(store, ctx, dest)
|
|
end
|
|
local function getVar(ctx, id) return Flags.getVar(store, ctx, id) end
|
|
local function setVar(ctx, id, v) Flags.setVar(store, ctx, id, v) end
|
|
|
|
local function newDex(caught)
|
|
local dex = Dex.new()
|
|
for _, sp in ipairs(caught or {}) do Dex.setCaught(dex, sp) end
|
|
return dex
|
|
end
|
|
|
|
print("[test] 1. GetPokedexCount fills VAR_0x8005 (seen) and VAR_0x8006 (caught)")
|
|
local s = session({
|
|
name = "RED",
|
|
gender = 0,
|
|
money = 3000,
|
|
trainerId = 4242,
|
|
party = {},
|
|
bag = require("src.core.game3.bag").new(),
|
|
dex = newDex({ 1, 4, 7, 10, 13, 16, 19, 21, 25, 29, 32 }),
|
|
map = "FR_ROUTE_2_EAST_BUILDING",
|
|
x = 4,
|
|
y = 7,
|
|
})
|
|
Dex.setSeen(s.dex, 41)
|
|
Dex.setSeen(s.dex, 43)
|
|
local ctx = newCtx()
|
|
setVar(ctx, 0x8004, 0) -- pokefirered/data/maps/Route2_EastBuilding/scripts.inc:13
|
|
local nat = specialvar(ctx, 0x800D, Std.SPECIAL.GetPokedexCount)
|
|
check(getVar(ctx, 0x8005) == 13, "VAR_0x8005 = 13 seen (got " .. tostring(getVar(ctx, 0x8005)) .. ")")
|
|
check(getVar(ctx, 0x8006) == 11, "VAR_0x8006 = 11 caught (got " .. tostring(getVar(ctx, 0x8006)) .. ")")
|
|
check(nat == 0, "VAR_RESULT = IsNationalPokedexEnabled = FALSE (got " .. tostring(nat) .. ")")
|
|
|
|
-- pokefirered/data/maps/Route2_EastBuilding/scripts.inc:12
|
|
local function aideBranch(dexTable)
|
|
s.dex = dexTable
|
|
local c = newCtx()
|
|
local jumped = nil
|
|
local vm = { ctx = c, store = store, adapters = a,
|
|
setPc = function(_, key) jumped = key end }
|
|
Ops.dispatch(vm, { op = "setvar", var = 0x8004, value = 0 })
|
|
Ops.dispatch(vm, { op = "specialvar", [1] = 0x800D, [2] = Std.SPECIAL.GetPokedexCount })
|
|
Ops.dispatch(vm, { op = "compare_var_to_value", var = 0x8006, value = 10 })
|
|
Ops.dispatch(vm, { op = "goto_if", cond = 0, target = "Aide_HaventCaughtEnough" })
|
|
return jumped, Flags.getVar(store, c, 0x8006)
|
|
end
|
|
|
|
print("[test] 2. the Route 2 aide branch clears REQUIRED_SEEN_MONS with 11 caught")
|
|
local jumped, caught = aideBranch(newDex({ 1, 4, 7, 10, 13, 16, 19, 21, 25, 29, 32 }))
|
|
check(caught == 11, "VAR_0x8006 = 11 at the gate (got " .. tostring(caught) .. ")")
|
|
check(jumped == nil, "no jump to Aide_HaventCaughtEnough, so HM05 is handed over")
|
|
|
|
print("[test] 3. only 9 caught keeps the aide's gift locked")
|
|
local jumped3, caught3 = aideBranch(newDex({ 1, 4, 7, 10, 13, 16, 19, 21, 25 }))
|
|
check(caught3 == 9, "VAR_0x8006 = 9 at the gate (got " .. tostring(caught3) .. ")")
|
|
check(jumped3 == "Aide_HaventCaughtEnough", "9 caught jumps to the refusal branch")
|
|
|
|
print("[test] 4. national mode counts the whole national range")
|
|
s.dex = newDex({ 1, 4, 7 })
|
|
Dex.setCaught(s.dex, 300)
|
|
local ctx4 = newCtx()
|
|
setVar(ctx4, 0x8004, 1)
|
|
specialvar(ctx4, 0x800D, Std.SPECIAL.GetPokedexCount)
|
|
check(getVar(ctx4, 0x8006) == 4, "national caught = 4 (got " .. tostring(getVar(ctx4, 0x8006)) .. ")")
|
|
local ctx4b = newCtx()
|
|
setVar(ctx4b, 0x8004, 0)
|
|
specialvar(ctx4b, 0x800D, Std.SPECIAL.GetPokedexCount)
|
|
check(getVar(ctx4b, 0x8006) == 3, "kanto caught skips species 300 (got "
|
|
.. tostring(getVar(ctx4b, 0x8006)) .. ")")
|
|
|
|
print("[test] 5. SetSeenMon registers the species in VAR_0x8004")
|
|
s.dex = newDex({})
|
|
local ctx5 = newCtx()
|
|
setVar(ctx5, 0x8004, 138) -- pokefirered/include/constants/species.h:142
|
|
Natives.special(ctx5, Std.SPECIAL.SetSeenMon, a)
|
|
check(Dex.isSeen(s.dex, 138), "species 138 is seen")
|
|
check(not Dex.isCaught(s.dex, 138), "SetSeenMon does not mark it caught")
|
|
|
|
print("[test] 6. SetHiddenItemFlag sets the flag id in VAR_0x8004")
|
|
local ctx6 = newCtx()
|
|
setVar(ctx6, 0x8004, 0x3E9)
|
|
Natives.special(ctx6, Std.SPECIAL.SetHiddenItemFlag, a)
|
|
check(Flags.getFlag(store, ctx6, 0x3E9) == true, "flag 0x3E9 is set")
|
|
|
|
print("[test] 7. party counts")
|
|
s.party = {
|
|
{ species = 1, hp = 20, otId = 4242, nickname = "BULBA", otName = "RED" },
|
|
{ species = 4, hp = 0, otId = 4242 },
|
|
{ species = 7, hp = 11, otId = 999, otName = "BLUE" },
|
|
{ species = 0, isEgg = true, hp = 5 },
|
|
}
|
|
s.party[4].species = 1
|
|
local ctx7 = newCtx()
|
|
check(specialvar(ctx7, 0x800D, Std.SPECIAL.CalculatePlayerPartyCount) == 4,
|
|
"CalculatePlayerPartyCount = 4")
|
|
check(specialvar(ctx7, 0x800D, Std.SPECIAL.CountPartyNonEggMons) == 3,
|
|
"CountPartyNonEggMons = 3")
|
|
setVar(ctx7, 0x8004, 0)
|
|
check(specialvar(ctx7, 0x800D, Std.SPECIAL.CountPartyAliveNonEggMons_IgnoreVar0x8004Slot) == 1,
|
|
"alive non-egg mons ignoring slot 1 = 1")
|
|
setVar(ctx7, 0x8004, 2)
|
|
check(specialvar(ctx7, 0x800D, Std.SPECIAL.CountPartyAliveNonEggMons_IgnoreVar0x8004Slot) == 1,
|
|
"alive non-egg mons ignoring slot 3 = 1")
|
|
|
|
print("[test] 8. species / OT / egg queries on the VAR_0x8004 slot")
|
|
local ctx8 = newCtx()
|
|
setVar(ctx8, 0x8004, 0)
|
|
check(specialvar(ctx8, 0x800D, Std.SPECIAL.GetPartyMonSpecies) == 1, "slot 1 species = 1")
|
|
setVar(ctx8, 0x8004, 3)
|
|
check(specialvar(ctx8, 0x800D, Std.SPECIAL.GetPartyMonSpecies) == 412,
|
|
"the egg slot reads back SPECIES_EGG")
|
|
Natives.special(ctx8, Std.SPECIAL.IsSelectedMonEgg, a)
|
|
check(getVar(ctx8, 0x800D) == 1, "IsSelectedMonEgg = TRUE for the egg")
|
|
setVar(ctx8, 0x8004, 0)
|
|
Natives.special(ctx8, Std.SPECIAL.IsSelectedMonEgg, a)
|
|
check(getVar(ctx8, 0x800D) == 0, "IsSelectedMonEgg = FALSE for BULBASAUR")
|
|
check(specialvar(ctx8, 0x800D, Std.SPECIAL.IsMonOTNameNotPlayers) == 0,
|
|
"own-OT mon: IsMonOTNameNotPlayers = FALSE")
|
|
setVar(ctx8, 0x8004, 2)
|
|
check(specialvar(ctx8, 0x800D, Std.SPECIAL.IsMonOTNameNotPlayers) == 1,
|
|
"traded mon: IsMonOTNameNotPlayers = TRUE")
|
|
check(ctx8.stringVars[1] == "BLUE", "the OT name landed in STR_VAR_1")
|
|
|
|
print("[test] 9. species-in-party queries")
|
|
local ctx9 = newCtx()
|
|
setVar(ctx9, 0x8004, 7)
|
|
check(specialvar(ctx9, 0x800D, Std.SPECIAL.DoesPlayerPartyContainSpecies) == 1,
|
|
"DoesPlayerPartyContainSpecies = TRUE for SQUIRTLE")
|
|
check(specialvar(ctx9, 0x800D, Std.SPECIAL.PlayerPartyContainsSpeciesWithPlayerID) == 0,
|
|
"the SQUIRTLE is traded, so the player-ID form is FALSE")
|
|
setVar(ctx9, 0x8004, 1)
|
|
check(specialvar(ctx9, 0x800D, Std.SPECIAL.PlayerPartyContainsSpeciesWithPlayerID) == 1,
|
|
"the own-OT BULBASAUR answers the player-ID form")
|
|
setVar(ctx9, 0x8004, 25)
|
|
check(specialvar(ctx9, 0x800D, Std.SPECIAL.DoesPlayerPartyContainSpecies) == 0,
|
|
"no PIKACHU in the party")
|
|
|
|
print("[test] 10. money")
|
|
local ctx10 = newCtx()
|
|
setVar(ctx10, 0x8005, 3000)
|
|
check(specialvar(ctx10, 0x800D, Std.SPECIAL.IsEnoughForCostInVar0x8005) == 1,
|
|
"3000 covers a 3000 cost")
|
|
setVar(ctx10, 0x8005, 3001)
|
|
check(specialvar(ctx10, 0x800D, Std.SPECIAL.IsEnoughForCostInVar0x8005) == 0,
|
|
"3000 does not cover 3001")
|
|
setVar(ctx10, 0x8005, 1200)
|
|
Natives.special(ctx10, Std.SPECIAL.SubtractMoneyFromVar0x8005, a)
|
|
check(s.money == 1800, "money is 1800 after the 1200 charge (got " .. tostring(s.money) .. ")")
|
|
|
|
print("[test] 11. HasAllKantoMons / HasAllMons exclude Mew")
|
|
local full = Dex.new()
|
|
for sp = 1, 150 do Dex.setCaught(full, sp) end
|
|
s.dex = full
|
|
local ctx11 = newCtx()
|
|
check(specialvar(ctx11, 0x800D, Std.SPECIAL.HasAllKantoMons) == 1,
|
|
"1..150 caught is HasAllKantoMons = TRUE without Mew")
|
|
check(specialvar(ctx11, 0x800D, Std.SPECIAL.HasAllMons) == 0,
|
|
"HasAllMons still wants the Johto and Hoenn ranges")
|
|
Dex.setCaught(full, 149)
|
|
full.caught[150] = nil
|
|
full.owned[150] = nil
|
|
check(specialvar(ctx11, 0x800D, Std.SPECIAL.HasAllKantoMons) == 0,
|
|
"one missing Kanto mon makes it FALSE")
|
|
|
|
print("[test] 12. GetStarterSpecies maps VAR_STARTER_MON")
|
|
local ctx12 = newCtx()
|
|
Flags.setVar(store, ctx12, 0x4031, 0)
|
|
check(specialvar(ctx12, 0x800D, Std.SPECIAL.GetStarterSpecies) == 1, "starter 0 = BULBASAUR")
|
|
Flags.setVar(store, ctx12, 0x4031, 1)
|
|
check(specialvar(ctx12, 0x800D, Std.SPECIAL.GetStarterSpecies) == 7, "starter 1 = SQUIRTLE")
|
|
Flags.setVar(store, ctx12, 0x4031, 2)
|
|
check(specialvar(ctx12, 0x800D, Std.SPECIAL.GetStarterSpecies) == 4, "starter 2 = CHARMANDER")
|
|
Flags.setVar(store, ctx12, 0x4031, 9)
|
|
check(specialvar(ctx12, 0x800D, Std.SPECIAL.GetStarterSpecies) == 1,
|
|
"an out-of-range index falls back to index 0")
|
|
|
|
print("[test] 13. GetRandomSlotMachineId stays inside the cart table")
|
|
local Rng = require("src.core.game3.rng")
|
|
Rng.SeedRng(0x1234)
|
|
local ctx13 = newCtx()
|
|
local seen = {}
|
|
for _ = 1, 200 do
|
|
local id = specialvar(ctx13, 0x800D, Std.SPECIAL.GetRandomSlotMachineId)
|
|
seen[id] = (seen[id] or 0) + 1
|
|
if id < 0 or id > 5 then
|
|
check(false, "slot machine id out of range: " .. tostring(id))
|
|
break
|
|
end
|
|
end
|
|
check(seen[0] and seen[0] > 0, "id 0 is the most common draw (11 of 22 table slots)")
|
|
check((seen[5] or 0) < (seen[0] or 0), "id 5 is rarer than id 0")
|
|
|
|
print("[test] 14. BufferBigGuyOrBigGirlString follows the player's gender")
|
|
local ctx14 = newCtx()
|
|
s.gender = 0
|
|
Natives.special(ctx14, Std.SPECIAL.BufferBigGuyOrBigGirlString, a)
|
|
check(ctx14.stringVars[1] == "gText_BigGuy", "boy: STR_VAR_1 = gText_BigGuy (got "
|
|
.. tostring(ctx14.stringVars[1]) .. ")")
|
|
s.gender = 1
|
|
Natives.special(ctx14, Std.SPECIAL.BufferBigGuyOrBigGirlString, a)
|
|
check(ctx14.stringVars[1] == "gText_BigGirl", "girl: STR_VAR_1 = gText_BigGirl (got "
|
|
.. tostring(ctx14.stringVars[1]) .. ")")
|
|
s.gender = 0
|
|
|
|
print("[test] 15. position queries")
|
|
local ctx15 = newCtx()
|
|
s.map, s.x = "FR_VERMILION_CITY", 23
|
|
check(specialvar(ctx15, 0x800D, Std.SPECIAL.IsPlayerLeftOfVermilionSailor) == 1,
|
|
"x = 23 in Vermilion is left of the sailor")
|
|
s.x = 24
|
|
check(specialvar(ctx15, 0x800D, Std.SPECIAL.IsPlayerLeftOfVermilionSailor) == 0,
|
|
"x = 24 is not")
|
|
s.map = "FR_ONE_ISLAND_HARBOR"
|
|
check(specialvar(ctx15, 0x800D, Std.SPECIAL.IsPlayerLeftOfVermilionSailor) == 0,
|
|
"another harbour is not Vermilion")
|
|
check(specialvar(ctx15, 0x800D, Std.SPECIAL.IsPlayerNotInTrainerTowerLobby) == 1,
|
|
"outside the tower lobby = TRUE")
|
|
s.map = "FR_TRAINER_TOWER_LOBBY"
|
|
check(specialvar(ctx15, 0x800D, Std.SPECIAL.IsPlayerNotInTrainerTowerLobby) == 0,
|
|
"inside the tower lobby = FALSE")
|
|
s.map = "FR_ROUTE_2_EAST_BUILDING"
|
|
|
|
print("[test] 16. IsThereRoomInAnyBoxForMorePokemon walks all 14 boxes")
|
|
s.storage = Storage.new()
|
|
local ctx16 = newCtx()
|
|
check(specialvar(ctx16, 0x800D, Std.SPECIAL.IsThereRoomInAnyBoxForMorePokemon) == 1,
|
|
"an empty PC has room")
|
|
for b = 1, Storage.TOTAL_BOXES_COUNT do
|
|
for slot = 1, Storage.IN_BOX_COUNT do
|
|
s.storage.boxes[b].mons[slot] = { species = 16, level = 5 }
|
|
end
|
|
end
|
|
check(specialvar(ctx16, 0x800D, Std.SPECIAL.IsThereRoomInAnyBoxForMorePokemon) == 0,
|
|
"420 boxed mons leaves no room")
|
|
s.storage.boxes[14].mons[30] = nil
|
|
check(specialvar(ctx16, 0x800D, Std.SPECIAL.IsThereRoomInAnyBoxForMorePokemon) == 1,
|
|
"one free slot in the last box is enough")
|
|
|
|
print("[test] 17. berry queries")
|
|
local Bag = require("src.core.game3.bag")
|
|
local ctx17 = newCtx()
|
|
check(specialvar(ctx17, 0x800D, Std.SPECIAL.HasAtLeastOneBerry) == 0,
|
|
"no Berry Pouch means no berries")
|
|
Bag.add(s.bag, 365, 1) -- pokefirered/include/constants/items.h:437
|
|
check(specialvar(ctx17, 0x800D, Std.SPECIAL.HasAtLeastOneBerry) == 0,
|
|
"an empty Berry Pouch is still FALSE")
|
|
Bag.add(s.bag, 133, 1) -- pokefirered/include/constants/items.h:137
|
|
check(specialvar(ctx17, 0x800D, Std.SPECIAL.HasAtLeastOneBerry) == 1,
|
|
"a CHERI BERRY answers TRUE")
|
|
check(specialvar(ctx17, 0x800D, Std.SPECIAL.DoesPartyHaveEnigmaBerry) == 0,
|
|
"nobody is holding an ENIGMA BERRY")
|
|
s.party[1].heldItem = 175
|
|
check(specialvar(ctx17, 0x800D, Std.SPECIAL.DoesPartyHaveEnigmaBerry) == 1,
|
|
"a held ENIGMA BERRY answers TRUE")
|
|
s.party[1].heldItem = nil
|
|
|
|
print("[test] 18. IsDodrioInParty and IsBadEggInParty")
|
|
local ctx18 = newCtx()
|
|
check(specialvar(ctx18, 0x800D, Std.SPECIAL.IsDodrioInParty) == 0, "no DODRIO in the party")
|
|
s.party[2].species = 85
|
|
check(specialvar(ctx18, 0x800D, Std.SPECIAL.IsDodrioInParty) == 1, "a DODRIO answers TRUE")
|
|
s.party[2].species = 4
|
|
check(specialvar(ctx18, 0x800D, Std.SPECIAL.IsBadEggInParty) == 0, "no bad egg")
|
|
|
|
print("[test] 19. ShouldShowBoxWasFullMessage only fires on a box change")
|
|
local ctx19 = newCtx()
|
|
s.storage.currentBox = 1
|
|
Flags.setVar(store, ctx19, 0x4037, 0) -- pokefirered/include/constants/vars.h:105
|
|
check(specialvar(ctx19, 0x800D, Std.SPECIAL.ShouldShowBoxWasFullMessage) == 0,
|
|
"same box: no box-was-full message")
|
|
s.storage.currentBox = 3
|
|
check(specialvar(ctx19, 0x800D, Std.SPECIAL.ShouldShowBoxWasFullMessage) == 1,
|
|
"the mon spilled into another box: message shown once")
|
|
check(Flags.getFlag(store, ctx19, 0x843) == true, "FLAG_SHOWN_BOX_WAS_FULL_MESSAGE is set")
|
|
check(specialvar(ctx19, 0x800D, Std.SPECIAL.ShouldShowBoxWasFullMessage) == 0,
|
|
"the flag keeps it from firing twice")
|
|
|
|
print("[test] 20. every new query is bound and nothing logs as unknown")
|
|
local unknown = {}
|
|
Natives.resetLog()
|
|
local logAdapter = { log = function(msg) unknown[#unknown + 1] = msg end }
|
|
local ids = {
|
|
"GetPokedexCount", "SetSeenMon", "SetHiddenItemFlag", "CalculatePlayerPartyCount",
|
|
"CountPartyNonEggMons", "CountPartyAliveNonEggMons_IgnoreVar0x8004Slot",
|
|
"DoesPlayerPartyContainSpecies", "PlayerPartyContainsSpeciesWithPlayerID",
|
|
"GetPartyMonSpecies", "IsSelectedMonEgg", "IsMonOTNameNotPlayers",
|
|
"NameRaterWasNicknameChanged", "GetSelectedMonNicknameAndSpecies",
|
|
"IsEnoughForCostInVar0x8005", "SubtractMoneyFromVar0x8005", "HasAllKantoMons",
|
|
"HasAllMons", "GetStarterSpecies", "GetRandomSlotMachineId",
|
|
"BufferBigGuyOrBigGirlString", "GetPlayerFacingDirection",
|
|
"IsPlayerLeftOfVermilionSailor", "IsPlayerNotInTrainerTowerLobby",
|
|
"IsBadEggInParty", "IsThereRoomInAnyBoxForMorePokemon", "IsDodrioInParty",
|
|
"HasAtLeastOneBerry", "DoesPartyHaveEnigmaBerry", "ShouldShowBoxWasFullMessage",
|
|
"GetPCBoxToSendMon", "BufferUnionRoomPlayerName",
|
|
}
|
|
for _, name in ipairs(ids) do
|
|
local id = Std.SPECIAL[name]
|
|
if not id then
|
|
check(false, name .. " has no Std.SPECIAL id")
|
|
else
|
|
Natives.special(newCtx(), id, logAdapter)
|
|
end
|
|
end
|
|
check(#unknown == 0, "no handler logged as unknown (got " .. tostring(#unknown) .. ")")
|
|
check(Std.SPECIAL.GetPokedexCount == 0xD4, "GetPokedexCount is special 0xD4")
|
|
|
|
print("[test] 21. a specialvar to another destination leaves VAR_RESULT alone")
|
|
-- pokefirered/src/scrcmd.c:109
|
|
local ctx21 = newCtx()
|
|
setVar(ctx21, 0x800D, 5)
|
|
setVar(ctx21, 0x8004, 25)
|
|
check(specialvar(ctx21, 0x8008, Std.SPECIAL.DoesPlayerPartyContainSpecies) == 0,
|
|
"the answer lands in VAR_0x8008")
|
|
check(getVar(ctx21, 0x800D) == 5, "VAR_RESULT is untouched (got "
|
|
.. tostring(getVar(ctx21, 0x800D)) .. ")")
|
|
-- pokefirered/src/party_menu_specials.c:102
|
|
setVar(ctx21, 0x8004, 3)
|
|
Natives.special(ctx21, Std.SPECIAL.IsSelectedMonEgg, a)
|
|
check(getVar(ctx21, 0x800D) == 1, "IsSelectedMonEgg still writes VAR_RESULT on its own")
|
|
|
|
-- pokefirered/data/scripts/pkmn_center_nurse.inc:31
|
|
print("[test] 22. the nurse rows after the heal stay out of the union-room branch")
|
|
local function nurseTail(mapId)
|
|
s.map = mapId
|
|
local c = newCtx()
|
|
local jumped = nil
|
|
local vm = { ctx = c, store = store, adapters = a,
|
|
setPc = function(_, key) jumped = key end }
|
|
Flags.setVar(store, c, 0x800D, 1)
|
|
-- pokefirered/data/scripts/pkmn_center_nurse.inc:32
|
|
Ops.dispatch(vm, { op = "specialvar", [1] = 0x800D,
|
|
[2] = Std.SPECIAL.IsPlayerNotInTrainerTowerLobby })
|
|
Ops.dispatch(vm, { op = "compare_var_to_value", var = 0x800D, value = 0 })
|
|
Ops.dispatch(vm, { op = "goto_if", cond = 1, target = "ReturnPkmn" })
|
|
if jumped then return jumped, Flags.getVar(store, c, 0x8008) end
|
|
-- pokefirered/data/scripts/pkmn_center_nurse.inc:34
|
|
Ops.dispatch(vm, { op = "specialvar", [1] = 0x800D,
|
|
[2] = Std.SPECIAL.BufferUnionRoomPlayerName })
|
|
Ops.dispatch(vm, { op = "copyvar", [1] = 0x8008, [2] = 0x800D })
|
|
Ops.dispatch(vm, { op = "compare_var_to_value", var = 0x8008, value = 0 })
|
|
Ops.dispatch(vm, { op = "goto_if", cond = 1, target = "ReturnPkmn" })
|
|
Ops.dispatch(vm, { op = "compare_var_to_value", var = 0x8008, value = 1 })
|
|
Ops.dispatch(vm, { op = "goto_if", cond = 1, target = "PlayerWaitingInUnionRoom" })
|
|
return jumped, Flags.getVar(store, c, 0x8008)
|
|
end
|
|
local nurseJump, nurseVar = nurseTail("FR_VIRIDIAN_CITY_POKEMON_CENTER_1F")
|
|
check(nurseVar == 0, "VAR_0x8008 = FALSE with no union-room name buffered (got "
|
|
.. tostring(nurseVar) .. ")")
|
|
check(nurseJump == "ReturnPkmn", "the nurse goes to ReturnPkmn (got "
|
|
.. tostring(nurseJump) .. ")")
|
|
local lobbyJump = nurseTail("FR_TRAINER_TOWER_LOBBY")
|
|
check(lobbyJump == "ReturnPkmn", "the Trainer Tower lobby nurse also returns the mons (got "
|
|
.. tostring(lobbyJump) .. ")")
|
|
s.map = "FR_ROUTE_2_EAST_BUILDING"
|
|
|
|
print("[test] 23. an unbound specialvar writes 0 instead of leaving the old value")
|
|
local ctx23 = newCtx()
|
|
setVar(ctx23, 0x800D, 1)
|
|
check(specialvar(ctx23, 0x800D, 0x182) == 0,
|
|
"unbound special 0x182 leaves VAR_RESULT at 0 (got " .. tostring(getVar(ctx23, 0x800D)) .. ")")
|
|
|
|
if failed > 0 then
|
|
print("[test] FAILED " .. failed)
|
|
os.exit(1)
|
|
end
|
|
print("[test] all passed")
|