mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 00:10:56 +02:00
201 lines
7.7 KiB
Lua
201 lines
7.7 KiB
Lua
-- Parity: SET_PAL_BATTLE_BLACK darkens the whole battle screen while the
|
|
-- blackout text is up (#292). HandlePlayerBlackOut (engine/battle/core.asm:
|
|
-- 1147-1159) runs the palette command before PrintText, and returns early in
|
|
-- OAKS_LAB. SetPal_BattleBlack (engine/gfx/palettes.asm:22-25) sends
|
|
-- PAL_BLACK into all four BlkPacket_Battle zones (sgb_packets.asm:220): both
|
|
-- HP bars and both mon regions.
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
if not _G.love then _G.love = require("tests.love_stub") end
|
|
local S = require("tests.harness").suite("parity battle blackout pals")
|
|
local check, eq = S.check, S.eq
|
|
|
|
local Data = require("src.core.Data")
|
|
if not Data.maps then Data:load() end
|
|
local Font = require("src.render.Font")
|
|
Font.load(Data)
|
|
|
|
local BattleState = require("src.battle.BattleState")
|
|
local PaletteFX = require("src.render.PaletteFX")
|
|
local Pokemon = require("src.pokemon.Pokemon")
|
|
local SaveData = require("src.core.SaveData")
|
|
local Sound = require("src.core.Sound")
|
|
local Music = require("src.core.Music")
|
|
|
|
Sound.playCry = function() end
|
|
Sound.play = function() end
|
|
Sound.playMove = function() end
|
|
Sound.playMoveCry = function() end
|
|
Sound.stopLoop = function() end
|
|
Music.playBattle = function() end
|
|
Music.play = function() end
|
|
|
|
local press = {}
|
|
local function makeGame(party)
|
|
local save = SaveData.newGame()
|
|
save.party = party
|
|
local stack = { states = {} }
|
|
function stack:push(state) self.states[#self.states + 1] = state end
|
|
function stack:pop() return table.remove(self.states) end
|
|
function stack:top() return self.states[#self.states] end
|
|
return { data = Data, save = save, stack = stack,
|
|
input = { wasPressed = function(_, b) return press[b] == true end,
|
|
isDown = function(_, b) return press[b] == true end } }
|
|
end
|
|
|
|
local function step(battle)
|
|
press.a = true
|
|
battle:update(1 / 60)
|
|
press.a = false
|
|
end
|
|
|
|
-- Lose for real: 0 HP everywhere, then run the faint through onFaint. Drain
|
|
-- to the onFinish callback, NOT to battle.result: playerMonFainted sets
|
|
-- result = "lose" in the same act that queues the blackout lines, so stopping
|
|
-- on result would miss every page under test.
|
|
local function wipeOut(battle)
|
|
local done = false
|
|
local prev = battle.onFinish
|
|
battle.onFinish = function(r) done = true if prev then prev(r) end end
|
|
battle.player.mon.hp = 0
|
|
for _, mon in ipairs(battle.game.save.party) do mon.hp = 0 end
|
|
battle.phase = "messages"
|
|
battle.nextInsert = 0
|
|
battle:onFaint(battle.player)
|
|
local pages, blackAt = {}, {}
|
|
for _ = 1, 1200 do
|
|
step(battle)
|
|
local cur = battle.current
|
|
local text = cur and cur.text
|
|
if text and pages[#pages] ~= text then
|
|
pages[#pages + 1] = text
|
|
blackAt[text] = battle.blackedOut and true or false
|
|
end
|
|
if done then break end
|
|
end
|
|
return pages, blackAt
|
|
end
|
|
|
|
local function indexOf(pages, fragment)
|
|
for i, p in ipairs(pages) do
|
|
if p:find(fragment, 1, true) then return i end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- ------------------------------------------------------------- the palette
|
|
local pack = PaletteFX.pack(Data)
|
|
check(pack ~= nil and pack.palettes ~= nil, "the active COLORS pack has palettes")
|
|
local BLACK = pack and pack.palettes and pack.palettes.BLACK
|
|
check(BLACK ~= nil,
|
|
"PAL_BLACK exists in the active pack (data/generated/palettes.lua:86, "
|
|
.. "data/palettes_gbc.lua:329)")
|
|
if BLACK then
|
|
-- sgb_palettes.asm:46 -- color 0 near-white, colors 1..3 near-black
|
|
check(BLACK[1][1] > 200 and BLACK[1][2] > 200,
|
|
"PAL_BLACK color 0 is the near-white paper")
|
|
for i = 2, 4 do
|
|
check(BLACK[i][1] < 90 and BLACK[i][2] < 90 and BLACK[i][3] < 90,
|
|
"PAL_BLACK color " .. (i - 1) .. " is near-black ink")
|
|
end
|
|
end
|
|
|
|
-- ------------------------------------------------------- a live wild wipe
|
|
local game = makeGame({ Pokemon.new(Data, "BULBASAUR", 5) })
|
|
local wild = BattleState.newWild(game, "RATTATA", 40)
|
|
wild.onFinish = function() end
|
|
wild:enter()
|
|
for _ = 1, 400 do
|
|
step(wild)
|
|
if wild.phase == "menu" then break end
|
|
end
|
|
eq(wild.phase, "menu", "the wild battle reaches its menu")
|
|
eq(wild.blackedOut, nil, "nothing is blacked out while the battle is live")
|
|
local before = wild:sgbBattlePals()
|
|
check(before ~= nil, "sgbBattlePals builds the four BlkPacket_Battle zones")
|
|
if before and BLACK then
|
|
check(before[0] ~= BLACK and before[1] ~= BLACK
|
|
and before[2] ~= BLACK and before[3] ~= BLACK,
|
|
"no zone is PAL_BLACK during normal play")
|
|
end
|
|
|
|
local pages, blackAt = wipeOut(wild)
|
|
eq(wild.result, "lose", "losing the last mon resolves the battle as a loss")
|
|
local outOf = indexOf(pages, "out of")
|
|
local blacked = indexOf(pages, "blacked")
|
|
check(outOf ~= nil, "\"<PLAYER> is out of useable POKeMON!\" prints")
|
|
check(blacked ~= nil, "\"<PLAYER> blacked out!\" prints")
|
|
if outOf then
|
|
eq(blackAt[pages[outOf]], true,
|
|
"the screen is ALREADY dark under the first blackout line "
|
|
.. "(RunPaletteCommand runs before PrintText, core.asm:1151-1156)")
|
|
end
|
|
if blacked then
|
|
eq(blackAt[pages[blacked]], true, "and stays dark under the second line")
|
|
end
|
|
|
|
local after = wild:sgbBattlePals()
|
|
check(after ~= nil, "sgbBattlePals still builds four zones once blacked out")
|
|
if after and BLACK then
|
|
eq(after[0], BLACK, "zone 0 (player HP bar) is PAL_BLACK")
|
|
eq(after[1], BLACK, "zone 1 (enemy HP bar) is PAL_BLACK")
|
|
eq(after[2], BLACK, "zone 2 (player mon region) is PAL_BLACK")
|
|
eq(after[3], BLACK, "zone 3 (enemy mon region) is PAL_BLACK")
|
|
end
|
|
-- zoneColorsAt reads the same table, so the shade shader cannot disagree with
|
|
-- the packet; sample the enemy HP bar corner and the enemy pic
|
|
if BLACK then
|
|
local barColors = wild:zoneColorsAt(24, 24)
|
|
local picColors = wild:zoneColorsAt(120, 24)
|
|
check(barColors == nil or barColors == BLACK,
|
|
"the enemy HP bar's zone reads PAL_BLACK")
|
|
check(picColors == nil or picColors == BLACK,
|
|
"the enemy pic's zone reads PAL_BLACK")
|
|
end
|
|
-- picImage is the funnel every battler pic is drawn through, so it still has
|
|
-- to resolve something for the darkened frame
|
|
check(wild:picImage(wild.playerBackPic) ~= nil or wild.playerBackPic == nil,
|
|
"picImage still resolves a pic while blacked out")
|
|
|
|
-- ---------------------------------------------- the Oak's Lab exception
|
|
-- core.asm:1147-1149 returns above the palette command when the starter rival
|
|
-- wins in OAKS_LAB, so that screen never darkens.
|
|
local game2 = makeGame({ Pokemon.new(Data, "BULBASAUR", 5) })
|
|
game2.save.player.map = "OAKS_LAB"
|
|
local lab = BattleState.newTrainer(game2, "OPP_RIVAL1", 1)
|
|
lab.onFinish = function() end
|
|
lab:enter()
|
|
for _ = 1, 500 do
|
|
step(lab)
|
|
if lab.phase == "menu" then break end
|
|
end
|
|
eq(BattleState.currentMapId(lab), "OAKS_LAB", "the battle knows it is in Oak's lab")
|
|
check(BattleState.isOaksLabStarterRival(lab), "and that this is the starter rival")
|
|
local labPages = wipeOut(lab)
|
|
eq(lab.result, "lose", "the lab rival still wins the battle")
|
|
eq(lab.blackedOut, nil,
|
|
"the Oak's Lab starter rival never darkens the screen (core.asm:1147-1149)")
|
|
check(indexOf(labPages, "blacked") == nil,
|
|
"and prints no blackout line either")
|
|
if BLACK then
|
|
local labPals = lab:sgbBattlePals()
|
|
check(labPals == nil or labPals[3] ~= BLACK,
|
|
"the lab screen keeps its live palettes")
|
|
end
|
|
|
|
-- ------------------------------------- Route 22 RIVAL1 still blacks out
|
|
-- Same OPP_RIVAL1 class, a different map: only the lab is excepted.
|
|
local game3 = makeGame({ Pokemon.new(Data, "BULBASAUR", 5) })
|
|
game3.save.player.map = "ROUTE_22"
|
|
local r22 = BattleState.newTrainer(game3, "OPP_RIVAL1", 1)
|
|
r22.onFinish = function() end
|
|
r22:enter()
|
|
for _ = 1, 500 do
|
|
step(r22)
|
|
if r22.phase == "menu" then break end
|
|
end
|
|
check(not BattleState.isOaksLabStarterRival(r22), "Route 22 is not the lab")
|
|
wipeOut(r22)
|
|
eq(r22.blackedOut, true, "a Route 22 RIVAL1 wipe darkens like any other")
|
|
|
|
S.finish()
|