Files
gen1recomp/tests/engine/gen2_treemon_extract_bug2043.lua

155 lines
5.6 KiB
Lua

-- ../pokecrystal/data/wild/treemons.asm:1 TreeMons
-- ../pokecrystal/data/wild/treemons_asleep.asm:3 AsleepTreeMonsNite
package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.harness")
local check, eq = T.check, T.eq
love = love or require("tests.love_stub")
local Extractor = require("src.import.RomExtractorGen2")
local Encounter = require("src.battle.gen2.Encounter")
local SPEAROW, AIPOM, HERACROSS = 21, 190, 214
local KRABBY, SHUCKLE = 98, 213
local CATERPIE, HOOTHOOT = 10, 163
local SPECIES = {
[SPEAROW] = "SPEAROW", [AIPOM] = "AIPOM", [HERACROSS] = "HERACROSS",
[KRABBY] = "KRABBY", [SHUCKLE] = "SHUCKLE",
[CATERPIE] = "CATERPIE", [HOOTHOOT] = "HOOTHOOT",
}
local function fakeRom(banks)
local rom = {}
function rom:byte(bank, address)
return (banks[bank] or {})[address] or 0
end
function rom:word(bank, address)
return self:byte(bank, address) + self:byte(bank, address + 1) * 0x100
end
return rom
end
local function put(bytes, at, ...)
for index, b in ipairs({ ... }) do bytes[at + index - 1] = b end
return at + select("#", ...)
end
do
local bank = {}
local TABLE, CANYON, ROCK = 0x42e8, 0x4300, 0x43de
put(bank, TABLE,
CANYON % 256, math.floor(CANYON / 256),
CANYON % 256, math.floor(CANYON / 256),
ROCK % 256, math.floor(ROCK / 256))
local at = put(bank, CANYON, 50, SPEAROW, 10, 50, AIPOM, 10, 0xff)
put(bank, at, 50, SPEAROW, 10, 50, HERACROSS, 10, 0xff)
at = put(bank, ROCK, 90, KRABBY, 15, 10, SHUCKLE, 15, 0xff)
-- ../pokecrystal/engine/events/treemons.asm:126 GetTreeMon
put(bank, at, 0xe5, 0xcd, 0x99, 0x43, 0xe1, 0xa7, 0x28, 0x08, 0xfe, 0x01,
0x28, 0x0e, 0xfe, 0x02, 0x28, 0x16, 0xc9, 0x3e, 0x0a, 0xcd)
local extractor = setmetatable({
rom = fakeRom({ [0x2e] = bank }),
edition = "crystal",
symbols = { TreeMons = { 0x2e, TABLE } },
manifest = { constants = {
treeMonSetOrder = { "TREEMON_SET_NONE", "TREEMON_SET_CANYON",
"TREEMON_SET_ROCK" },
speciesOrder = SPECIES,
} },
}, Extractor)
local sets = extractor:readTreeMons()
local canyon = sets.TREEMON_SET_CANYON
eq(#canyon.common, 2, "a headbutt set reads its common list")
eq(canyon.common[1].species, "SPEAROW", "first common row")
eq(canyon.common[2].level, 10, "with its level")
eq(#canyon.rare, 2, "and its rare list")
eq(canyon.rare[2].species, "HERACROSS", "the rare row past the -1")
local rock = sets.TREEMON_SET_ROCK
eq(#rock.common, 2, "TREEMON_SET_ROCK is the 90/10 list")
eq(rock.common[1].species, "KRABBY", "KRABBY")
eq(rock.common[1].chance, 90, "at 90")
eq(rock.common[2].species, "SHUCKLE", "SHUCKLE")
eq(rock.rare, nil,
"and no second list: the bytes after its -1 are GetTreeMon's code")
end
do
local encounters = {
trees = { ROCKY = "TREEMON_SET_ROCK" },
treeSets = { TREEMON_SET_ROCK = {
common = { { chance = 100, species = "KRABBY", level = 15 } } } },
}
eq(Encounter.treeScore(0, 0, 4), Encounter.TREEMON_SCORE_RARE,
"coords (0,0) with OT id 4 score RARE")
eq(Encounter.treeSlot(encounters, "ROCKY", 0, 0, function() return 0 end,
{ otId = 4, engine = "crystal" }), nil,
"a RARE roll against a one-list set answers nothing rather than erroring")
end
do
local bank = {}
local NITE, DAY, MORN = 0x6b5d, 0x6b69, 0x6b6f
put(bank, NITE, CATERPIE, SPEAROW, 0xff)
put(bank, DAY, HOOTHOOT, 0xff)
put(bank, MORN, HOOTHOOT, HERACROSS, 0xff)
local symbols = {
AsleepTreeMonsNite = { 0x0f, NITE },
AsleepTreeMonsDay = { 0x0f, DAY },
AsleepTreeMonsMorn = { 0x0f, MORN },
}
local extractor = setmetatable({
rom = fakeRom({ [0x0f] = bank }),
edition = "crystal",
symbols = symbols,
manifest = { constants = { speciesOrder = SPECIES } },
}, Extractor)
local asleep = extractor:readAsleepTreeMons()
eq(#asleep.NITE, 2, "Nite list length")
eq(asleep.NITE[1], "CATERPIE", "Nite[1]")
eq(asleep.NITE[2], "SPEAROW", "Nite[2]")
eq(asleep.DAY[1], "HOOTHOOT", "Day[1]")
eq(#asleep.DAY, 1, "Day list length")
eq(asleep.MORN[2], "HERACROSS", "Morn[2]")
local gold = setmetatable({
rom = fakeRom({}), edition = "gold",
symbols = { AsleepTreeMonsNite = { 0x0f, NITE } },
manifest = { constants = { speciesOrder = SPECIES } },
}, Extractor)
eq(gold:readAsleepTreeMons(), nil,
"a ROM without all three labels (pokegold) has no list")
end
-- ../pokecrystal/engine/battle/core.asm:6422 CheckSleepingTreeMon
do
local encounters = { treeMonsAsleep = {
NITE = { "SPEAROW" }, DAY = { "HOOTHOOT" }, MORN = { "AIPOM" } } }
eq(Encounter.treeMonAsleep("SPEAROW", "NITE", "crystal", encounters), true,
"the extracted Nite list is read")
eq(Encounter.treeMonAsleep("SPEAROW", "DARK", "crystal", encounters), true,
"DARKNESS_F falls through to Nite")
eq(Encounter.treeMonAsleep("SPEAROW", "DAY", "crystal", encounters), false,
"and SPEAROW is awake by day")
eq(Encounter.treeMonAsleep("AIPOM", "MORN", "crystal", encounters), true,
"the Morn list is its own")
eq(Encounter.treeMonAsleep("AIPOM", "DAY", "crystal", encounters), false,
"and not the Day list")
eq(Encounter.treeMonAsleep("HOOTHOOT", "DAY", "gs", encounters), false,
"pokegold never sleeps a tree mon")
local empty = { treeMonsAsleep = { NITE = {}, DAY = {}, MORN = {} } }
eq(Encounter.treeMonAsleep("SPEAROW", "NITE", "crystal", empty), false,
"an extracted list wins over the transcribed constant")
eq(Encounter.treeMonAsleep("SPEAROW", "NITE", "crystal", nil), true,
"which still answers for a cache without the table")
eq(Encounter.treeMonAsleep("SPEAROW", "NITE", "crystal", {}), true,
"or with it missing")
end
T.finish("gen2 treemon extract bug2043")