mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 00:10:56 +02:00
217 lines
7.9 KiB
Lua
217 lines
7.9 KiB
Lua
-- GiveExperiencePoints' three boosts and the EXP.SHARE double pass
|
|
-- (engine/battle/core.asm:6747, dispatch at :2099-2130).
|
|
--
|
|
-- luajit tests/gen2_exp_share_test.lua
|
|
--
|
|
-- ROM-free. Traded mons (OT id differs from the player's) earn x1.5 with
|
|
-- BoostedExpPointsText; a held LUCKY_EGG is another x1.5, checked by item
|
|
-- id; any live EXP.SHARE holder halves the pool up front, participants
|
|
-- split the first pass and every holder is paid a second pass -- stat exp
|
|
-- included, from the same halved base stats.
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local S = require("tests.harness").suite("gen2 exp share")
|
|
local check, eq = S.check, S.eq
|
|
|
|
local Battle = require("src.battle.gen2.Battle")
|
|
local Mon = require("src.battle.gen2.Mon")
|
|
|
|
-- ---------------------------------------------------------------- fixtures
|
|
|
|
local TYPES = {
|
|
NORMAL = { id = "NORMAL", index = 0, category = "physical" },
|
|
}
|
|
|
|
local MOVES = {
|
|
TACKLE = { id = "TACKLE", name = "TACKLE", power = 35, type = "NORMAL",
|
|
accuracy = 95, pp = 35, effect = "EFFECT_NORMAL_HIT" },
|
|
}
|
|
|
|
local GROWTH = {
|
|
GROWTH_SLOW = { numerator = 5, denominator = 4, squared = 0, linear = 0,
|
|
constant = 0 },
|
|
}
|
|
|
|
local POKEMON = {
|
|
growthRates = GROWTH,
|
|
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_SLOW", genderRatio = 63,
|
|
levelMoves = { { level = 1, move = "TACKLE" } }, evolutions = {},
|
|
},
|
|
PIDGEY = {
|
|
id = "PIDGEY", index = 16, name = "PIDGEY",
|
|
baseStats = { hp = 40, attack = 45, defense = 40, speed = 56,
|
|
specialAttack = 35, specialDefense = 35 },
|
|
types = { "NORMAL", "NORMAL" }, catchRate = 255, baseExp = 55,
|
|
growthRate = "GROWTH_SLOW", genderRatio = 127,
|
|
levelMoves = { { level = 1, move = "TACKLE" } }, evolutions = {},
|
|
},
|
|
}
|
|
|
|
local ITEMS = {
|
|
LUCKY_EGG = { id = "LUCKY_EGG", name = "LUCKY EGG",
|
|
heldEffect = "HELD_NONE", heldParameter = 0 },
|
|
EXP_SHARE = { id = "EXP_SHARE", name = "EXP.SHARE",
|
|
heldEffect = "HELD_NONE", heldParameter = 0 },
|
|
}
|
|
|
|
local DATA = {
|
|
pokemon = POKEMON,
|
|
moves = MOVES,
|
|
type_chart = { types = TYPES, matchups = {} },
|
|
items = ITEMS,
|
|
}
|
|
|
|
local perfect = { attack = 15, defense = 15, speed = 15, special = 15 }
|
|
perfect.hp = Mon.hpDV(perfect)
|
|
|
|
local PLAYER_ID = 31337
|
|
|
|
-- One KO's worth of exp, replayed against a fresh battle each time.
|
|
-- `partySpec` rows: { otId =, item =, participant =, hp = }.
|
|
local function award(partySpec)
|
|
local party, participants = {}, {}
|
|
for index, spec in ipairs(partySpec) do
|
|
local mon = Mon.new(DATA, "MACHOP", 20, { dvs = perfect })
|
|
mon.otId = spec.otId
|
|
mon.item = spec.item
|
|
if spec.hp then mon.hp = spec.hp end
|
|
party[index] = mon
|
|
if spec.participant then participants[index] = true end
|
|
end
|
|
local wild = Mon.new(DATA, "PIDGEY", 14, { dvs = perfect })
|
|
local battle = Battle.new({ data = DATA, party = party, wild = wild,
|
|
save = { player = { id = PLAYER_ID, badges = {} } },
|
|
random = function(n) return (n or 1) > 1 and 1 or 0 end })
|
|
battle.participants = participants
|
|
local before = {}
|
|
for index, mon in ipairs(party) do before[index] = mon.experience end
|
|
battle:awardExperience(wild)
|
|
local gained = {}
|
|
for index, mon in ipairs(party) do
|
|
gained[index] = mon.experience - before[index]
|
|
end
|
|
return gained, battle:takeEvents(), party
|
|
end
|
|
|
|
-- The wild PIDGEY: baseExp 55, level 14 -> floor(55 * 14 / 7) = 110.
|
|
local BASE = 110
|
|
|
|
-- ---- the native baseline --------------------------------------------------
|
|
do
|
|
local gained, events = award({ { otId = PLAYER_ID, participant = true } })
|
|
eq(gained[1], BASE, "a native solo participant earns baseExp * level / 7")
|
|
local boosted = false
|
|
for _, event in ipairs(events) do
|
|
if event.kind == "experience"
|
|
and event.text:find("boosted", 1, true) then
|
|
boosted = true
|
|
end
|
|
end
|
|
eq(boosted, false, "and its line is the plain ExpPointsText")
|
|
end
|
|
|
|
-- ---- the traded 1.5x ------------------------------------------------------
|
|
do
|
|
local gained, events = award({ { otId = 48926, participant = true } })
|
|
eq(gained[1], math.floor(BASE * 3 / 2),
|
|
"an outsider mon (ROCKY the Onix's OT, say) earns x1.5")
|
|
local line
|
|
for _, event in ipairs(events) do
|
|
if event.kind == "experience" then line = event.text end
|
|
end
|
|
eq(line, "MACHOP gained a boosted 165 EXP. Points!",
|
|
"with BoostedExpPointsText's own wording")
|
|
end
|
|
|
|
-- ---- the Lucky Egg 1.5x and the stack -------------------------------------
|
|
do
|
|
local gained = award({
|
|
{ otId = PLAYER_ID, item = "LUCKY_EGG", participant = true } })
|
|
eq(gained[1], math.floor(BASE * 3 / 2), "a held LUCKY EGG is x1.5")
|
|
|
|
gained = award({ { otId = 48926, item = "LUCKY_EGG", participant = true } })
|
|
eq(gained[1], math.floor(math.floor(BASE * 3 / 2) * 3 / 2),
|
|
"traded and egg stack to x2.25, floored in the cart's order")
|
|
end
|
|
|
|
-- ---- EXP.SHARE ------------------------------------------------------------
|
|
do
|
|
-- Holder on the bench: the pool halves (baseExp 55 -> 27), the fighter
|
|
-- takes the first pass, the holder the second.
|
|
local halved = math.floor(math.floor(55 / 2) * 14 / 7) -- 54
|
|
local gained = award({
|
|
{ otId = PLAYER_ID, participant = true },
|
|
{ otId = PLAYER_ID, item = "EXP_SHARE" },
|
|
})
|
|
eq(gained[1], halved, "the participant's share is halved")
|
|
eq(gained[2], halved, "the benched holder is paid the second pass")
|
|
|
|
-- A holder that fought collects BOTH passes.
|
|
gained = award({
|
|
{ otId = PLAYER_ID, item = "EXP_SHARE", participant = true } })
|
|
eq(gained[1], halved * 2, "a fighting holder is paid twice")
|
|
|
|
-- Two participants split pass one; the one holder still takes a full
|
|
-- second-pass share.
|
|
gained = award({
|
|
{ otId = PLAYER_ID, participant = true },
|
|
{ otId = PLAYER_ID, participant = true },
|
|
{ otId = PLAYER_ID, item = "EXP_SHARE" },
|
|
})
|
|
local split = math.floor(halved / 2)
|
|
eq(gained[1], split, "two participants split the halved pool")
|
|
eq(gained[2], split, "both of them")
|
|
eq(gained[3], halved, "the lone holder's pass divides by one")
|
|
|
|
-- A fainted holder is skipped by the pass loop, and with no live holder
|
|
-- the pool is never halved.
|
|
gained = award({
|
|
{ otId = PLAYER_ID, participant = true },
|
|
{ otId = PLAYER_ID, item = "EXP_SHARE", hp = 0 },
|
|
})
|
|
eq(gained[1], BASE, "a fainted holder does not tax the pool")
|
|
eq(gained[2], 0, "and earns nothing")
|
|
end
|
|
|
|
-- ---- stat exp rides the same halving --------------------------------------
|
|
do
|
|
local _, _, party = award({
|
|
{ otId = PLAYER_ID, participant = true },
|
|
{ otId = PLAYER_ID, item = "EXP_SHARE" },
|
|
})
|
|
-- PIDGEY base attack 45: halved to 22 for each pass.
|
|
eq(party[1].statExp.attack, 22, "the participant's stat exp is halved")
|
|
eq(party[2].statExp.attack, 22, "the holder earns stat exp too")
|
|
-- And the special word takes the loser's Special ATTACK, halved.
|
|
eq(party[2].statExp.special, math.floor(35 / 2),
|
|
"the special stat exp word follows")
|
|
|
|
_, _, party = award({ { otId = PLAYER_ID, participant = true } })
|
|
eq(party[1].statExp.attack, 45, "no holder, no halving")
|
|
end
|
|
|
|
-- ---- Mon.experienceGain's arms stay honest --------------------------------
|
|
do
|
|
local def = POKEMON.PIDGEY
|
|
eq(Mon.experienceGain(def, 14, 1, false), BASE, "bare")
|
|
eq(Mon.experienceGain(def, 14, 1, true), math.floor(BASE * 3 / 2),
|
|
"trainer battles boost x1.5, unchanged")
|
|
eq(Mon.experienceGain(def, 14, 1, false, { traded = true, luckyEgg = true }),
|
|
math.floor(math.floor(BASE * 3 / 2) * 3 / 2), "traded + egg")
|
|
eq(Mon.experienceGain(def, 14, 1, false, { halved = true }),
|
|
math.floor(math.floor(55 / 2) * 14 / 7), "the share tax halves baseExp")
|
|
eq(Mon.experienceGain(def, 14, 1, true,
|
|
{ halved = true, traded = true, luckyEgg = true }),
|
|
math.floor(math.floor(math.floor(
|
|
math.floor(math.floor(55 / 2) * 14 / 7) * 3 / 2) * 3 / 2) * 3 / 2),
|
|
"all four arms compose in the cart's order")
|
|
end
|
|
|
|
S.finish()
|