mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
23617f43b4
CLOSES #2290, CLOSES #2338, CLOSES #2186, CLOSES #2305, CLOSES #2332, CLOSES #2320, CLOSES #2344, CLOSES #2291, CLOSES #2335, CLOSES #2340, CLOSES #2385, CLOSES #2352, CLOSES #2378, CLOSES #2403, CLOSES #2404, CLOSES #2405, CLOSES #2367, CLOSES #2037, CLOSES #2177, CLOSES #2368, CLOSES #2382, CLOSES #1951
183 lines
6.7 KiB
Lua
183 lines
6.7 KiB
Lua
-- ../pokecrystal/engine/battle/effect_commands.asm:2644-2654
|
|
-- ../pokecrystal/data/items/attributes.asm:149-150
|
|
-- ../pokegold/data/items/attributes.asm:149-150
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
love = require("tests.love_stub")
|
|
|
|
local T = require("tests.harness")
|
|
local Fingerprint = require("src.link.Fingerprint")
|
|
local Handshake = require("src.link.Handshake")
|
|
local Wire = require("src.link.Wire")
|
|
local GameVersion = require("src.core.GameVersion")
|
|
local Battle = require("src.battle.gen2.Battle")
|
|
local Damage = require("src.battle.gen2.Damage")
|
|
local Mon = require("src.battle.gen2.Mon")
|
|
|
|
local function deepCopy(v)
|
|
if type(v) ~= "table" then return v end
|
|
local out = {}
|
|
for k, x in pairs(v) do out[k] = deepCopy(x) end
|
|
return out
|
|
end
|
|
|
|
local function tmhmList(n)
|
|
local out = {}
|
|
for i = 1, n do out[i] = "MOVE_" .. i end
|
|
return out
|
|
end
|
|
|
|
local TYPES = {
|
|
NORMAL = { id = "NORMAL", index = 0, category = "physical" },
|
|
FIGHTING = { id = "FIGHTING", index = 1, category = "physical" },
|
|
}
|
|
|
|
local function goldData()
|
|
return {
|
|
pokemon = {
|
|
growthRates = {
|
|
GROWTH_MEDIUM_FAST = { numerator = 1, denominator = 1, squared = 0,
|
|
linear = 0, constant = 0 },
|
|
},
|
|
tmhmMoves = tmhmList(57),
|
|
MACHOP = {
|
|
id = "MACHOP", index = 66, name = "MACHOP",
|
|
baseStats = { hp = 70, attack = 80, defense = 50, speed = 35,
|
|
specialAttack = 35, specialDefense = 35 },
|
|
types = { "NORMAL", "NORMAL" }, catchRate = 180, baseExp = 75,
|
|
growthRate = "GROWTH_MEDIUM_FAST", genderRatio = 63,
|
|
levelMoves = { { level = 1, move = "TACKLE" } }, evolutions = {},
|
|
},
|
|
},
|
|
moves = {
|
|
TACKLE = { id = "TACKLE", name = "TACKLE", power = 35, type = "NORMAL",
|
|
accuracy = 100, pp = 35, effect = "EFFECT_NORMAL_HIT" },
|
|
},
|
|
type_chart = { generation = 2, types = deepCopy(TYPES), matchups = {} },
|
|
gen2HeldItems = {
|
|
ITEM_46 = { heldEffect = "HELD_NONE", heldParameter = 0 },
|
|
ITEM_73 = { heldEffect = "HELD_NONE", heldParameter = 0 },
|
|
LEFTOVERS = { heldEffect = "HELD_LEFTOVERS", heldParameter = 10 },
|
|
},
|
|
}
|
|
end
|
|
|
|
local function crystalData()
|
|
local data = goldData()
|
|
data.pokemon.tmhmMoves = tmhmList(60)
|
|
data.pokemon.tutorMoves = { "FLAMETHROWER", "THUNDERBOLT", "ICE_BEAM" }
|
|
data.gen2HeldItems.ITEM_46 = nil
|
|
data.gen2HeldItems.ITEM_73 = nil
|
|
data.gen2HeldItems.CLEAR_BELL = { heldEffect = "HELD_NONE", heldParameter = 0 }
|
|
data.gen2HeldItems.GS_BALL = { heldEffect = "HELD_NONE", heldParameter = 0 }
|
|
return data
|
|
end
|
|
|
|
do
|
|
local gold, crystal = goldData(), crystalData()
|
|
local g = Fingerprint.compute(gold, {}, 2)
|
|
local c = Fingerprint.compute(crystal, {}, 2)
|
|
T.eq(c, g, "Crystal's tutor list and renamed HELD_NONE slots do not split the digest")
|
|
|
|
local helloG = Handshake.hello({ data = gold })
|
|
local helloC = Handshake.hello({ data = crystal })
|
|
T.eq(helloG.generation, 2, "the gold hello is gen 2")
|
|
T.eq((Handshake.checkCompat(helloG, helloC)), "full",
|
|
"a Gold hello meeting a Crystal hello pairs as full")
|
|
T.eq((Handshake.checkCompat(helloC, helloG)), "full", "and in reverse")
|
|
end
|
|
|
|
do
|
|
local crystal = crystalData()
|
|
local base = Fingerprint.compute(crystal, {}, 2)
|
|
local armed = crystalData()
|
|
armed.gen2HeldItems.CLEAR_BELL = { heldEffect = "HELD_LEFTOVERS",
|
|
heldParameter = 10 }
|
|
T.check(Fingerprint.compute(armed, {}, 2) ~= base,
|
|
"a HELD_NONE slot given a real effect moves the digest")
|
|
local tuned = crystalData()
|
|
tuned.gen2HeldItems.LEFTOVERS.heldParameter = 20
|
|
T.check(Fingerprint.compute(tuned, {}, 2) ~= base,
|
|
"a real held item's parameter still moves the digest")
|
|
local species = crystalData()
|
|
species.pokemon.MACHOP.baseStats.attack = 81
|
|
T.check(Fingerprint.compute(species, {}, 2) ~= base,
|
|
"a species edit still moves the digest")
|
|
end
|
|
|
|
do
|
|
local gold, crystal = goldData(), crystalData()
|
|
local cmons = Fingerprint.records(crystal, "pokemon", 2)
|
|
T.eq(cmons.tutorMoves, nil, "tutorMoves is not a species record")
|
|
T.eq(cmons.tmhmMoves, nil, "tmhmMoves is not a species record")
|
|
T.eq(cmons.growthRates, nil, "growthRates is not a species record")
|
|
T.check(cmons.MACHOP ~= nil, "a real species keeps its record")
|
|
local gheld = Fingerprint.records(gold, "held_items", 2)
|
|
T.check(gheld.ITEM_46 ~= nil,
|
|
"the per-record held map keeps HELD_NONE ids for party eligibility")
|
|
local cheld = Fingerprint.records(crystal, "held_items", 2)
|
|
T.eq(cheld.ITEM_46, nil, "Crystal has no ITEM_46 record")
|
|
end
|
|
|
|
do
|
|
local detail = "dataset fingerprint differs: the room has 6f577c0127a1e94d, "
|
|
.. "you have c444a8971640c763"
|
|
local out = Wire.sanitize({ type = "join_error", reason = "profile_mismatch",
|
|
field = "fingerprint", detail = detail })
|
|
T.eq(out.detail, detail, "the relay's mismatch detail survives the wire whole")
|
|
local long = string.rep("x", 120)
|
|
out = Wire.sanitize({ type = "join_error", reason = "x", detail = long })
|
|
T.eq(out.detail, long, "a 120-byte detail survives")
|
|
end
|
|
|
|
do
|
|
local data = goldData()
|
|
data.items = {}
|
|
local perfect = { attack = 15, defense = 15, speed = 15, special = 15 }
|
|
perfect.hp = Mon.hpDV(perfect)
|
|
local function highRoll(n) return 99 % math.max(1, n or 1) end
|
|
|
|
local seen
|
|
local realCalc = Damage.calc
|
|
Damage.calc = function(opts)
|
|
seen = opts
|
|
return realCalc(opts)
|
|
end
|
|
|
|
local function reflectHit(version, link)
|
|
GameVersion.set(version)
|
|
local player = Mon.new(data, "MACHOP", 15, { dvs = perfect })
|
|
player.moves = { { id = "TACKLE", pp = 35, maxPp = 35 } }
|
|
local wild = Mon.new(data, "MACHOP", 15, { dvs = perfect })
|
|
wild.moves = { { id = "TACKLE", pp = 35, maxPp = 35 } }
|
|
local battle = Battle.new({ data = data, party = { player }, wild = wild,
|
|
random = highRoll })
|
|
player.stats.attack = 200
|
|
wild.stats.defense = 512
|
|
wild.maxHp, wild.hp = 999, 999
|
|
battle.linkBattle = link or nil
|
|
battle.screens.enemy.reflect = 5
|
|
seen = nil
|
|
battle:useMove(player, wild, "TACKLE")
|
|
battle:takeEvents()
|
|
return 999 - wild.hp, seen and seen.reflectOverflowFixed
|
|
end
|
|
|
|
local restore = GameVersion.get()
|
|
local gold = reflectHit("gold", false)
|
|
local crystalSolo, soloFlag = reflectHit("crystal", false)
|
|
local crystalLink, linkFlag = reflectHit("crystal", true)
|
|
local goldLink = reflectHit("gold", true)
|
|
GameVersion.set(restore)
|
|
Damage.calc = realCalc
|
|
|
|
T.check(gold > 0, "the Reflect hit lands")
|
|
T.eq(soloFlag, nil, "a single-player battle leaves the version's fix in charge")
|
|
T.check(crystalSolo < gold, "single-player Crystal keeps its Reflect fix")
|
|
T.eq(linkFlag, false, "a link battle forces the single truncation pass")
|
|
T.eq(crystalLink, gold, "a Crystal link battle computes Gold's Reflect damage")
|
|
T.eq(goldLink, gold, "and Gold's link battle is unchanged")
|
|
end
|
|
|
|
T.finish("gen2 link cross version bug 2382")
|