mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-16 16:21:30 +02:00
175 lines
5.6 KiB
Lua
175 lines
5.6 KiB
Lua
-- HandlePoisonBurnLeechSeed runs once per side per round; a mod that
|
|
-- reads battle.ruleset.residualAfterMove twice (executeAction:3487 and
|
|
-- endOfTurn:2657) could otherwise fire both arms. #1181's b.residualDone
|
|
-- latch (residualFor ~2612, endOfTurn ~2670, cleared ~2685) closes that.
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local T = require("tests.modkit")
|
|
local Data = T.fixtures.fresh()
|
|
local Font = require("src.render.Font")
|
|
Font.load(Data)
|
|
local BattleState = require("src.battle.BattleState")
|
|
local Pokemon = require("src.pokemon.Pokemon")
|
|
local SaveData = require("src.core.SaveData")
|
|
local TypeChart = require("src.battle.TypeChart")
|
|
TypeChart.load(Data)
|
|
|
|
local function newBattle(opts)
|
|
opts = opts or {}
|
|
local save = SaveData.newGame()
|
|
save.party = { Pokemon.new(Data, "FIXMON_A", 30), Pokemon.new(Data, "FIXMON_A", 28) }
|
|
local game = { data = Data, save = save,
|
|
stack = { top = function() return nil end, push = function() end } }
|
|
local battle = BattleState.newWild(game, "FIXMON_C", 30)
|
|
battle.rng = function() return 0 end
|
|
battle.enemyAction = function() return { id = "FIX_SCRATCH", pp = 35 } end
|
|
if opts.playerFaster then
|
|
battle.player.curStats.speed = 200
|
|
battle.enemy.curStats.speed = 1
|
|
else
|
|
battle.enemy.curStats.speed = 200
|
|
battle.player.curStats.speed = 1
|
|
end
|
|
return battle
|
|
end
|
|
|
|
local function drain(battle)
|
|
local rows = {}
|
|
for _ = 1, 800 do
|
|
local item = table.remove(battle.queue, 1)
|
|
if not item then return rows end
|
|
if item.text then rows[#rows + 1] = { text = item.text } end
|
|
if item.fn then
|
|
battle.nextInsert = 0
|
|
item.fn()
|
|
end
|
|
end
|
|
error("the turn queue never drained")
|
|
end
|
|
|
|
local function countTicks(rows)
|
|
local player, enemy = 0, 0
|
|
for _, r in ipairs(rows) do
|
|
if r.text and r.text:find("hurt by poison", 1, true) then
|
|
if r.text:find("Enemy", 1, true) then enemy = enemy + 1
|
|
else player = player + 1 end
|
|
end
|
|
end
|
|
return player, enemy
|
|
end
|
|
|
|
local function assertCleared(b, label)
|
|
T.check(b.player.residualDone == nil, label .. ": player residualDone cleared")
|
|
T.check(b.enemy.residualDone == nil, label .. ": enemy residualDone cleared")
|
|
end
|
|
|
|
do
|
|
local b = newBattle({ playerFaster = true })
|
|
b.player.mon.status = "PSN"
|
|
b:resolveTurn({ id = "FIX_TACKLE", pp = 35 })
|
|
local pt, et = countTicks(drain(b))
|
|
T.eq(pt, 1, "faster attacker: poison ticks exactly once")
|
|
T.eq(et, 0, "faster attacker: no enemy tick")
|
|
assertCleared(b, "faster attacker")
|
|
end
|
|
|
|
do
|
|
local b = newBattle({ playerFaster = false })
|
|
b.player.mon.status = "PSN"
|
|
b:resolveTurn({ id = "FIX_TACKLE", pp = 35 })
|
|
local pt, et = countTicks(drain(b))
|
|
T.eq(pt, 1, "slower attacker: poison ticks exactly once")
|
|
T.eq(et, 0, "slower attacker: no enemy tick")
|
|
assertCleared(b, "slower attacker")
|
|
end
|
|
|
|
do
|
|
local b = newBattle({ playerFaster = false })
|
|
b.player.mon.status = "PSN"
|
|
b:itemUsed({})
|
|
local pt, et = countTicks(drain(b))
|
|
T.eq(pt, 1, "item round: poison ticks exactly once")
|
|
T.eq(et, 0, "item round: no enemy tick")
|
|
assertCleared(b, "item round")
|
|
end
|
|
|
|
do
|
|
local b = newBattle({ playerFaster = false })
|
|
b.player.mon.status = "PSN"
|
|
b.catchAttempt = function() return false, 0 end
|
|
local ballId
|
|
for id in pairs(Data.items or {}) do
|
|
if id:find("BALL") then ballId = id break end
|
|
end
|
|
if not ballId then
|
|
Data.items = Data.items or {}
|
|
Data.items.POKE_BALL = { name = "POKE BALL" }
|
|
ballId = "POKE_BALL"
|
|
end
|
|
b:throwBall(ballId)
|
|
local pt, et = countTicks(drain(b))
|
|
T.eq(pt, 1, "ball round: poison ticks exactly once")
|
|
T.eq(et, 0, "ball round: no enemy tick")
|
|
assertCleared(b, "ball round")
|
|
end
|
|
|
|
do
|
|
local b = newBattle({ playerFaster = false })
|
|
b.player.mon.status = "PSN"
|
|
b.runRoll = function() return false end
|
|
b:tryRun()
|
|
local pt, et = countTicks(drain(b))
|
|
T.eq(pt, 1, "failed run: poison ticks exactly once")
|
|
T.eq(et, 0, "failed run: no enemy tick")
|
|
assertCleared(b, "failed run")
|
|
end
|
|
|
|
do
|
|
local b = newBattle({ playerFaster = false })
|
|
b.player.mon.status = "PSN"
|
|
b:resolveSwitch(b.game.save.party[2])
|
|
local pt, et = countTicks(drain(b))
|
|
T.eq(pt, 0, "switch round: a fresh battler ticks zero")
|
|
T.eq(et, 0, "switch round: still no enemy tick")
|
|
assertCleared(b, "switch round")
|
|
end
|
|
|
|
do
|
|
local b = newBattle({ playerFaster = false })
|
|
b.player.mon.status = "PSN"
|
|
b.enemy.mon.status = "PSN"
|
|
local php0, ehp0 = b.player.mon.hp, b.enemy.mon.hp
|
|
b:resolveTurn({ id = "FIX_TACKLE", pp = 35 })
|
|
local rows = drain(b)
|
|
local pt, et = countTicks(rows)
|
|
T.eq(pt, 1, "both sides poisoned: player side ticks once")
|
|
T.eq(et, 1, "both sides poisoned: enemy side ticks once too")
|
|
T.check(b.player.mon.hp < php0, "both sides poisoned: player actually lost HP")
|
|
T.check(b.enemy.mon.hp < ehp0, "both sides poisoned: enemy actually lost HP")
|
|
assertCleared(b, "both sides poisoned")
|
|
end
|
|
|
|
do
|
|
local b = newBattle({ playerFaster = false })
|
|
b.player.mon.status = "PSN"
|
|
b.player.mon.hp = 999
|
|
b.player.mon.stats.hp = 999
|
|
local lastLoss
|
|
for round = 1, 5 do
|
|
local hp0 = b.player.mon.hp
|
|
b:resolveTurn({ id = "FIX_TACKLE", pp = 35 })
|
|
local pt, et = countTicks(drain(b))
|
|
T.eq(pt, 1, ("round %d of 5: poison ticks exactly once"):format(round))
|
|
T.eq(et, 0, ("round %d of 5: no enemy tick"):format(round))
|
|
assertCleared(b, ("round %d of 5"):format(round))
|
|
local loss = hp0 - b.player.mon.hp
|
|
T.check(loss > 0, ("round %d of 5: HP actually dropped"):format(round))
|
|
if lastLoss then
|
|
T.eq(loss, lastLoss, ("round %d of 5: same tick size as the round before"):format(round))
|
|
end
|
|
lastLoss = loss
|
|
end
|
|
end
|
|
|
|
T.finish("residual latch (#1181)")
|