Files
gen1recomp/tests/parity_ai_switch_exp.lua
T

83 lines
3.1 KiB
Lua

-- Parity test: an AI trainer switch clears the exp participant flags.
--
-- pokered's AI switch path calls EnemySendOut, which zeroes
-- wPartyGainExpFlags and re-flags only wPlayerMonNumber before falling
-- into EnemySendOutFirstMon (engine/battle/core.asm:1276-1292). The port
-- kept the old participants, so a mon that had fought the withdrawn foe
-- still halved the exp for the newly sent-out one (#1826).
--
-- Self-contained; run via `luajit tests/parity_ai_switch_exp.lua`.
-- Also picked up by tests/run_tests.lua's parity_* glob.
package.path = "./?.lua;./?/init.lua;" .. package.path
if not _G.love then _G.love = require("tests.love_stub") end
local Data = require("src.core.Data")
if not (Data.pokemon and Data.pokemon.RATTATA) then Data:load() end
local TypeChart = require("src.battle.TypeChart")
TypeChart.load(Data)
local Pokemon = require("src.pokemon.Pokemon")
local BattleState = require("src.battle.BattleState")
local S = require("tests.harness").suite("parity ai switch exp")
local check, eq = S.check, S.eq
local function freshGame()
return {
data = Data,
save = {
party = { Pokemon.new(Data, "BULBASAUR", 50), Pokemon.new(Data, "CHARMANDER", 50) },
player = { name = "RED", id = 1234 },
inventory = {},
options = { battleStyle = "set" },
pokedex = { seen = {}, owned = {} },
flags = {},
money = 0,
},
stack = { push = function() end, pop = function() end, top = function() end },
}
end
-- Both party mons fought the first foe; the AI then withdraws it.
local function battleAfterAiSwitch()
local Game = freshGame()
local b = BattleState.newTrainer(Game, "OPP_AGATHA", 1)
check(#b.enemyParty >= 2, "the trainer has a reserve to switch to")
b.participants = { [Game.save.party[1]] = true, [Game.save.party[2]] = true }
b:executeAction(b.enemy, b.player, { special = "aiSwitch", index = 2 })
return Game, b
end
do
local Game, b = battleAfterAiSwitch()
eq(b.participants[Game.save.party[1]], true,
"the mon on the field is the one participant after the switch")
eq(b.participants[Game.save.party[2]], nil,
"the benched mon lost its gain-exp flag (core.asm:1276-1289)")
end
-- The divisor follows: the on-field mon takes the whole share, and the
-- benched one earns nothing off the new foe's KO.
do
local Game, b = battleAfterAiSwitch()
b.enemy.mon.hp = 0
local before1 = Game.save.party[1].exp
local before2 = Game.save.party[2].exp
b:awardExp()
local gainedSwitched = Game.save.party[1].exp - before1
check(gainedSwitched > 0, "the mon on the field is paid for the KO")
eq(Game.save.party[2].exp - before2, 0, "the benched mon is paid nothing")
-- Reference: the same KO with a single flagged participant from the start.
local Game2 = freshGame()
local b2 = BattleState.newTrainer(Game2, "OPP_AGATHA", 1)
b2:executeAction(b2.enemy, b2.player, { special = "aiSwitch", index = 2 })
b2.participants = { [Game2.save.party[1]] = true }
b2.enemy.mon.hp = 0
local ref = Game2.save.party[1].exp
b2:awardExp()
eq(gainedSwitched, Game2.save.party[1].exp - ref,
"the share is undivided, not halved by the stale participant")
end
S.finish()