-- engine/battle/move_effects/pay_day.asm:13, engine/battle/core.asm:8014-8042 package.path = "./?.lua;./?/init.lua;" .. package.path love = require("tests.love_stub") local T = require("tests.harness") local Battle = require("src.battle.gen2.Battle") local BattleState = require("src.ui.gen2.BattleState") local Effects = require("src.battle.gen2.Effects") local Mon = require("src.battle.gen2.Mon") local Prize = require("src.battle.gen2.Prize") local LEVEL = 15 local TYPES = { NORMAL = { id = "NORMAL", index = 0, category = "physical" }, } local MOVES = { TACKLE = { id = "TACKLE", name = "TACKLE", power = 35, type = "NORMAL", accuracy = 100, pp = 35, effect = "EFFECT_NORMAL_HIT" }, PAY_DAY = { id = "PAY_DAY", name = "PAY DAY", power = 40, type = "NORMAL", accuracy = 100, pp = 20, effect = "EFFECT_PAY_DAY" }, } local POKEMON = { growthRates = { GROWTH_MEDIUM_FAST = { numerator = 1, denominator = 1, squared = 0, linear = 0, constant = 0 }, }, MEOWTH = { id = "MEOWTH", index = 52, name = "MEOWTH", baseStats = { hp = 40, attack = 45, defense = 35, speed = 90, specialAttack = 40, specialDefense = 40 }, types = { "NORMAL", "NORMAL" }, catchRate = 255, baseExp = 69, growthRate = "GROWTH_MEDIUM_FAST", genderRatio = 127, levelMoves = { { level = 1, move = "PAY_DAY" } }, evolutions = {}, }, 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 = {}, }, } local DATA = { pokemon = POKEMON, moves = MOVES, type_chart = { types = TYPES, matchups = {} }, 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 function newSave() return { player = { name = "GOLD", money = 1000, id = 4242 }, mom = { savedMoney = 500 }, party = {} } end local function newBattle(save) local player = Mon.new(DATA, "MEOWTH", LEVEL, { dvs = perfect }) player.moves = { { id = "PAY_DAY", pp = 20, maxPp = 20 }, { id = "TACKLE", pp = 35, maxPp = 35 }, } local wild = Mon.new(DATA, "RATTATA", LEVEL, { dvs = perfect }) wild.moves = { { id = "TACKLE", pp = 35, maxPp = 35 } } wild.maxHp = 999 wild.hp = 999 local battle = Battle.new({ data = DATA, party = { player }, wild = wild, random = highRoll, save = save }) return battle, player, wild end local function eventWithText(events, text) for _, event in ipairs(events or {}) do if event.text == text then return event end end return nil end local function findText(events, text) return eventWithText(events, text) ~= nil end do local battle, player, wild = newBattle(newSave()) battle:useMove(player, wild, "PAY_DAY") T.eq(battle.payDay, 2 * LEVEL, "one connected hit is 2 x the user's level") T.check(findText(battle:takeEvents(), "Coins scattered\neverywhere!"), "CoinsScatteredText rides the hit") battle:useMove(player, wild, "PAY_DAY") T.eq(battle.payDay, 4 * LEVEL, "a second hit adds the same again") battle:useMove(player, wild, "TACKLE") T.eq(battle.payDay, 4 * LEVEL, "another move adds nothing") end do local battle, player, wild = newBattle(newSave()) battle.stages.enemy.evasion = Effects.MAX_STAGE battle:useMove(player, wild, "PAY_DAY") T.eq(battle.payDay, nil, "a miss accumulates nothing") end do local battle, player, wild = newBattle(newSave()) battle.amuletCoin = true battle:useMove(player, wild, "PAY_DAY") battle:useMove(player, wild, "PAY_DAY") T.eq(battle.payDay, 4 * LEVEL, "the Amulet Coin does not double the running counter") end do local battle, player, wild = newBattle(newSave()) local enemy = battle.enemy enemy.level = 40 battle:useMove(enemy, player, "PAY_DAY") T.eq(battle.payDay, 80, "an enemy's PAY DAY pays the player, at ITS level") T.check(wild == battle.enemy, "the enemy is the wild mon") end do local save = newSave() T.eq(Prize.payDay(save, 30, false), 30, "the payout returns what it paid") T.eq(save.player.money, 1030, "and writes the wallet directly") T.eq(save.mom.savedMoney, 500, "with no Mom split") end do local save = newSave() T.eq(Prize.payDay(save, 30, true), 60, "the Amulet Coin doubles the total") T.eq(save.player.money, 1060, "once, at payout") end do local save = newSave() T.eq(Prize.payDay(save, 0, true), nil, "an empty counter pays nothing") T.eq(Prize.payDay(save, nil, false), nil, "and neither does an unset one") T.eq(save.player.money, 1000, "the wallet is untouched") T.eq(Prize.payDay(nil, 30, false), nil, "a save-less battle pays nothing") end do local save = newSave() save.player.money = Prize.MAX_MONEY - 10 Prize.payDay(save, 500, true) T.eq(save.player.money, Prize.MAX_MONEY, "AddBattleMoneyToAccount clamps") end do local save = newSave() local battle, player, wild = newBattle(save) battle:useMove(player, wild, "PAY_DAY") wild.hp = 0 T.check(battle:resolveFaints(), "the enemy faint ends the battle") T.eq(battle.outcome, "win", "on the win arm") T.eq(save.player.money, 1000 + 2 * LEVEL, "which is where CheckPayDay runs") T.eq(battle.payDay, nil, "and the counter is cleared") local paid = eventWithText(battle:takeEvents(), "GOLD picked up ¥30!") T.check(paid, "BattleText_PlayerPickedUpPayDayMoney") T.eq(paid and paid.kind, "money", "on the same event kind the prize uses") end do local save = newSave() local battle, player, wild = newBattle(save) battle.amuletCoin = true battle:useMove(player, wild, "PAY_DAY") wild.hp = 0 battle:resolveFaints() T.eq(save.player.money, 1000 + 4 * LEVEL, "the Amulet Coin doubles once on the way out") end do local save = newSave() local battle, player, wild = newBattle(save) battle:useMove(player, wild, "PAY_DAY") player.hp = 0 T.check(battle:resolveFaints(), "a whiteout ends the battle") T.eq(battle.outcome, "lose", "on the lose arm") T.eq(save.player.money, 1000, "which pays nothing") T.eq(battle.payDay, 2 * LEVEL, "the counter is dropped, not banked") end do local save = newSave() local battle, player, wild = newBattle(save) battle:useMove(player, wild, "PAY_DAY") battle:endBattle("run") T.eq(save.player.money, 1000, "running away pays nothing") end local function newScreen(save, battle, opts) opts = opts or {} local pushed = {} local screen = setmetatable({ save = save, battle = battle, picHidden = {}, contest = opts.contest, tutorial = opts.tutorial, contestCaught = false, push = function(self, event) pushed[#pushed + 1] = event end, name = function(_, mon) return mon.species end, hasPokedex = function() return false end, currentBox = function() return 1 end, contestCatch = function(self) self.contestCaught = true end, }, { __index = BattleState }) return screen, pushed end local function caughtEnemy(battle) local enemy = battle.enemy enemy.hp = 1 return enemy end do local save = newSave() local battle, player, wild = newBattle(save) battle:useMove(player, wild, "PAY_DAY") local screen, pushed = newScreen(save, battle) screen:pushCaught(caughtEnemy(battle), "POKE_BALL") T.eq(save.player.money, 1000 + 2 * LEVEL, "a capture pays out") T.eq(battle.payDay, nil, "and clears the counter") T.check(findText(pushed, "GOLD picked up ¥30!"), "with the payout line") end do local save = newSave() local battle, player, wild = newBattle(save) battle:useMove(player, wild, "PAY_DAY") local screen = newScreen(save, battle, { contest = true }) screen:pushCaught(caughtEnemy(battle), "PARK_BALL") T.check(screen.contestCaught, "the contest arm still holds the mon") T.eq(save.player.money, 1000 + 2 * LEVEL, "and a contest catch pays too") T.eq(battle.payDay, nil, "clearing the counter with it") end do local save = newSave() local battle, player, wild = newBattle(save) battle:useMove(player, wild, "PAY_DAY") local screen = newScreen(save, battle, { tutorial = true }) screen:pushCaught(caughtEnemy(battle), "POKE_BALL") T.eq(save.player.money, 1000, "the catching tutorial pays nothing") T.eq(battle.payDay, 2 * LEVEL, "and leaves the counter alone") end do local save = newSave() local battle, player, wild = newBattle(save) battle:useMove(player, wild, "PAY_DAY") wild.hp = 0 battle:resolveFaints() local screen = newScreen(save, battle, { contest = true }) screen:pushPayDay() T.eq(save.player.money, 1000 + 2 * LEVEL, "a contest KO that already paid does not pay a second time") end T.finish("gen2 pay day bug 1212")