Files
gen1recomp/tests/engine/gen2_caught_data_stamp_bug1886.lua

221 lines
8.0 KiB
Lua

-- engine/pokemon/caught_data.asm:72-81, :163-233
package.path = "./?.lua;./?/init.lua;" .. package.path
love = require("tests.love_stub")
local T = require("tests.harness")
local Breeding = require("src.core.gen2.Breeding")
local Catching = require("src.battle.gen2.Catching")
local Mon = require("src.battle.gen2.Mon")
local NpcTrade = require("src.core.gen2.NpcTrade")
local UI = require("src.ui.gen2.BattleState")
local World = require("src.world.gen2.World")
local NEW_BARK = 1
local ROUTE_29 = 2
local POKEMON = {
growthRates = {
GROWTH_MEDIUM_FAST = { numerator = 1, denominator = 1, squared = 0,
linear = 0, constant = 0 },
},
RATTATA = {
id = "RATTATA", index = 19, name = "RATTATA",
baseStats = { hp = 30, attack = 56, defense = 35, speed = 72,
specialAttack = 25, specialDefense = 35 },
types = { "NORMAL", "NORMAL" }, catchRate = 255, baseExp = 51,
growthRate = "GROWTH_MEDIUM_FAST", genderRatio = 127,
levelMoves = { { level = 1, move = "TACKLE" } }, evolutions = {},
},
DODRIO = {
id = "DODRIO", index = 85, name = "DODRIO",
baseStats = { hp = 60, attack = 110, defense = 70, speed = 100,
specialAttack = 60, specialDefense = 60 },
types = { "NORMAL", "FLYING" }, catchRate = 45, baseExp = 158,
growthRate = "GROWTH_MEDIUM_FAST", genderRatio = 127,
levelMoves = { { level = 1, move = "TACKLE" } }, evolutions = {},
},
}
local DATA = {
pokemon = POKEMON,
moves = { TACKLE = { id = "TACKLE", name = "TACKLE", power = 35,
type = "NORMAL", accuracy = 100, pp = 35, effect = "EFFECT_NORMAL_HIT" } },
type_chart = { types = {}, matchups = {} },
items = {},
}
local function newSave(version, gender)
return {
version = version, party = {},
player = { name = "KRIS", id = 4242, gender = gender or "female" },
pokedex = { seen = {}, caught = {} },
}
end
local function newWorld()
return {
tod = "NITE",
maps = {
ROUTE_29 = { id = "ROUTE_29", landmark = ROUTE_29 },
NEW_BARK_TOWN = { id = "NEW_BARK_TOWN", landmark = NEW_BARK },
},
map = { def = { id = "ROUTE_29", landmark = ROUTE_29 } },
timeOfDayId = World.timeOfDayId,
}
end
local function newState(save, world, opts)
opts = opts or {}
return setmetatable({
save = save, queue = {},
battle = { timeOfDay = opts.timeOfDay },
contest = opts.contest,
game = { save = save, data = DATA, world = world },
}, { __index = UI })
end
do
local save = newSave("crystal", "female")
local state = newState(save, newWorld(), { timeOfDay = 1 })
local enemy = { species = "RATTATA", level = 4 }
state:pushCaught(enemy, "POKE_BALL")
T.eq(save.party[1], enemy, "the catch joins the party")
T.eq(enemy.caughtTime, 2, "wTimeOfDay DAY stores as 2")
T.eq(enemy.caughtLevel, 4, "the level rides the same byte")
T.eq(enemy.caughtLocation, ROUTE_29, "the map header's landmark")
T.eq(enemy.caughtByGender, "girl", "wPlayerGender bit 0 on bit 7")
end
do
local save = newSave("crystal", "male")
for i = 1, 6 do save.party[i] = { species = "RATTATA", level = 5 } end
local state = newState(save, newWorld(), { timeOfDay = 0 })
local enemy = { species = "RATTATA", level = 7 }
state:pushCaught(enemy, "POKE_BALL")
T.eq(#save.party, 6, "a full party sends the catch to the PC")
T.eq(enemy.caughtTime, 1, "MORN stores as 1, so 0 stays 'unknown'")
T.eq(enemy.caughtByGender, "boy", "a male player stamps CAUGHT_BY_BOY")
T.eq(enemy.caughtLocation, ROUTE_29, "and the same landmark")
end
do
local save = newSave("crystal", "female")
local state = newState(save, newWorld())
local enemy = { species = "RATTATA", level = 4 }
state:pushCaught(enemy, "POKE_BALL")
T.eq(enemy.caughtTime, 3, "NITE stores as 3")
end
do
local save = newSave("gold", "male")
local state = newState(save, newWorld(), { timeOfDay = 1 })
local enemy = { species = "RATTATA", level = 4 }
state:pushCaught(enemy, "POKE_BALL")
T.eq(enemy.caughtTime, nil, "Gold stamps no caught time")
T.eq(enemy.caughtByGender, nil, "and no OT gender")
T.eq(enemy.caughtLocation, nil, "and no landmark")
end
do
local save = newSave("crystal", "female")
local state = newState(save, newWorld(), { timeOfDay = 1, contest = true })
local enemy = { species = "RATTATA", level = 9 }
state:pushCaught(enemy, "PARK_BALL")
T.eq(save.bugContest.caught, enemy, "the contest only HOLDS the catch")
T.eq(enemy.caughtLocation, Catching.LANDMARK_NATIONAL_PARK,
"the location is rewritten to the park")
T.eq(enemy.caughtByGender, "girl", "and the gender bit survives the rewrite")
T.eq(enemy.caughtTime, 2, "the time byte is the plain SetCaughtData one")
end
do
local world = newWorld()
world.map = { def = { id = "POKECENTER_2F", landmark = 0x7f } }
world.backupMapId = "NEW_BARK_TOWN"
local save = newSave("crystal", "male")
local state = newState(save, world, { timeOfDay = 1 })
local enemy = { species = "RATTATA", level = 4 }
state:pushCaught(enemy, "POKE_BALL")
T.eq(enemy.caughtLocation, NEW_BARK, "the backup map's landmark is used")
end
do
local world = newWorld()
local save = newSave("crystal", "female")
world.game = { save = save, data = DATA }
local opts = World.caughtDataOpts(world)
T.eq(opts.version, "crystal", "the save's version gates the stamp")
T.eq(opts.timeOfDay, 2, "NITE is wTimeOfDay 2")
T.eq(opts.landmark, ROUTE_29, "the landmark is resolved up front")
T.eq(opts.playerGender, "female", "and wPlayerGender comes along")
world.map = { def = { id = "POKECENTER_2F", landmark = 0x7f } }
world.backupMapId = "NEW_BARK_TOWN"
T.eq(World.caughtDataOpts(world).landmark, NEW_BARK,
"with the POKECENTER_2F backup swap")
end
do
local source = io.open("src/world/gen2/World.lua"):read("*a")
T.check(source:find("Mon.setGiftCaughtData(mon, opts.caughtBy", 1, true)
~= nil, "the trainer arm stamps LANDMARK_GIFT")
T.check(source:find("Catching.stampCaughtData(mon, self:caughtDataOpts())",
1, true) ~= nil, "the wild arm runs SetCaughtData")
end
do
local save = newSave("crystal", "female")
local egg = Mon.new(DATA, "RATTATA", Breeding.EGG_LEVEL, {})
egg.isEgg = true
egg.eggSteps = 0
save.party[1] = egg
local world = newWorld()
world.game = { save = save, data = DATA }
local hatched = Breeding.hatch(DATA, save, 1, nil, World.caughtDataOpts(world))
T.check(hatched ~= nil, "the egg hatches")
T.eq(hatched.caughtLevel, Mon.CAUGHT_EGG_LEVEL, "CAUGHT_EGG_LEVEL")
T.eq(hatched.caughtTime, 3, "NITE")
T.eq(hatched.caughtLocation, ROUTE_29, "the hatch site's landmark")
T.eq(hatched.caughtByGender, "girl", "and the player's gender")
end
do
local save = newSave("crystal", "male")
save.party[1] = Mon.new(DATA, "RATTATA", 20, {})
local row = { id = 3, dialog = "TRADE_DIALOGSET_GIRL", give = "RATTATA",
get = "DODRIO", nickname = "DORIS", dvs = { 0x77, 0x66 }, otName = "EMY",
otId = 283 }
local _, received = NpcTrade.perform(DATA, save, row, 1)
T.check(received ~= nil, "the trade completes")
T.eq(received.caughtTime, 0, "a gift has no caught time")
T.eq(received.caughtLevel, 0, "and no caught level")
T.eq(received.caughtLocation, Mon.LANDMARK_GIFT, "LANDMARK_GIFT")
T.eq(received.caughtByGender, "girl", "TRADE_DIALOGSET_GIRL is CAUGHT_BY_GIRL")
end
do
local save = newSave("crystal", "male")
save.party[1] = Mon.new(DATA, "RATTATA", 20, {})
local row = { id = 0, dialog = "TRADE_DIALOGSET_COLLECTOR", give = "RATTATA",
get = "DODRIO", nickname = "MUSCLE", dvs = { 0x37, 0x66 }, otName = "MIKE",
otId = 37460 }
local _, received = NpcTrade.perform(DATA, save, row, 1)
T.eq(received.caughtLocation, Mon.LANDMARK_GIFT, "still LANDMARK_GIFT")
T.eq(received.caughtByGender, "boy",
"CAUGHT_BY_UNKNOWN leaves the gender bit clear")
end
do
local save = newSave("gold", "male")
save.party[1] = Mon.new(DATA, "RATTATA", 20, {})
local row = { id = 3, dialog = "TRADE_DIALOGSET_GIRL", give = "RATTATA",
get = "DODRIO", nickname = "DORIS", dvs = { 0x77, 0x66 }, otName = "EMY",
otId = 283 }
local _, received = NpcTrade.perform(DATA, save, row, 1)
T.eq(received.caughtLocation, nil, "Gold trades stamp nothing")
end
T.finish("gen2 caught data stamp bug 1886")