mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-20 04:31:09 +02:00
CLOSES #223, CLOSES #233, CLOSES #236, CLOSES #240, CLOSES #241, CLOSES #249, CLOSES #252, CLOSES #255, CLOSES #257, CLOSES #258, CLOSES #263, CLOSES #265, CLOSES #274, CLOSES #275, CLOSES #276, CLOSES #279, CLOSES #280, CLOSES #282, CLOSES #283, CLOSES #287, CLOSES #291, CLOSES #292, CLOSES #293, CLOSES #301, CLOSES #304, CLOSES #315, CLOSES #316, CLOSES #317, CLOSES #321, CLOSES #322, CLOSES #330
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
-- 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 } }
|
||||
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()
|
||||
Reference in New Issue
Block a user