mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
23617f43b4
CLOSES #2290, CLOSES #2338, CLOSES #2186, CLOSES #2305, CLOSES #2332, CLOSES #2320, CLOSES #2344, CLOSES #2291, CLOSES #2335, CLOSES #2340, CLOSES #2385, CLOSES #2352, CLOSES #2378, CLOSES #2403, CLOSES #2404, CLOSES #2405, CLOSES #2367, CLOSES #2037, CLOSES #2177, CLOSES #2368, CLOSES #2382, CLOSES #1951
205 lines
7.5 KiB
Lua
205 lines
7.5 KiB
Lua
-- POKEPORT_IDENTITY=red-sep04 POKEPORT_DRIVER=tests/drivers/intro_og_obj_palette_bug2264_test.lua POKEPORT_SHOT_DIR=/tmp/shots love .
|
|
return function(game)
|
|
local U = dofile("tests/drivers/util.lua")
|
|
local P = require("src.render.PaletteFX")
|
|
local GameVersion = require("src.core.GameVersion")
|
|
local IntroMovie = require("src.ui.IntroMovie")
|
|
local SHOT_DIR = os.getenv("POKEPORT_SHOT_DIR") or os.getenv("SHOT_DIR") or "/tmp/shots"
|
|
local version = GameVersion.get()
|
|
local tag = "2264_" .. tostring(version)
|
|
|
|
local fails = 0
|
|
local function check(label, ok, detail)
|
|
U.log(ok and "PASS" or "FAIL", label, detail or "")
|
|
if not ok then fails = fails + 1 end
|
|
return ok
|
|
end
|
|
|
|
local function finish()
|
|
P.applyOptions({ colors = "ogred" })
|
|
if fails > 0 then
|
|
U.log("FAIL " .. tag .. ": " .. fails .. " check(s), shots in " .. SHOT_DIR)
|
|
love.event.quit(1)
|
|
else
|
|
U.log("PASS " .. tag .. ": all checks, shots in " .. SHOT_DIR)
|
|
love.event.quit(0)
|
|
end
|
|
while true do coroutine.yield() end
|
|
end
|
|
|
|
local rendered = 0
|
|
local hostDraw = love.draw
|
|
love.draw = function(...)
|
|
local r = hostDraw(...)
|
|
rendered = rendered + 1
|
|
return r
|
|
end
|
|
|
|
local function waitRenderedFrames(frames)
|
|
local target = rendered + (frames or 2)
|
|
for _ = 1, 2400 do
|
|
if rendered >= target then return true end
|
|
U.wait(1)
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function waitFor(pred, limit)
|
|
for _ = 1, limit or 3000 do
|
|
if pred() then return true end
|
|
U.wait(1)
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function near(R, G, B, c)
|
|
return math.abs(R - c[1]) <= 12 and math.abs(G - c[2]) <= 12
|
|
and math.abs(B - c[3]) <= 12
|
|
end
|
|
|
|
local objRamp, bgRamp
|
|
|
|
local function letterbox(img)
|
|
local W, H = img:getWidth(), img:getHeight()
|
|
local x1, y1, x2, y2 = W, H, -1, -1
|
|
for y = 0, H - 1 do
|
|
for x = 0, W - 1 do
|
|
local r, g, b = img:getPixel(x, y)
|
|
if r > 0.02 or g > 0.02 or b > 0.02 then
|
|
if x < x1 then x1 = x end
|
|
if x > x2 then x2 = x end
|
|
if y < y1 then y1 = y end
|
|
if y > y2 then y2 = y end
|
|
end
|
|
end
|
|
end
|
|
local bw, bh = x2 - x1 + 1, y2 - y1 + 1
|
|
if x2 >= x1 and math.abs(bw / 160 - bh / 144) < 0.05 then
|
|
return x1, y1, bh / 144
|
|
end
|
|
local s = math.min(W / 160, H / 144)
|
|
return math.floor((W - 160 * s) / 2), math.floor((H - 144 * s) / 2), s
|
|
end
|
|
|
|
local shotImg = {}
|
|
local function load(path)
|
|
if shotImg[path] ~= nil then return shotImg[path] end
|
|
local f = io.open(path, "rb")
|
|
if not f then shotImg[path] = false return false end
|
|
local bytes = f:read("*a")
|
|
f:close()
|
|
local ok, img = pcall(function()
|
|
return love.image.newImageData(love.filesystem.newFileData(bytes, "shot.png"))
|
|
end)
|
|
shotImg[path] = ok and img or false
|
|
return shotImg[path]
|
|
end
|
|
|
|
local function census(path, bx1, by1, bx2, by2)
|
|
local img = load(path)
|
|
if not img then return nil end
|
|
local W, H = img:getWidth(), img:getHeight()
|
|
local ox, oy, scale = letterbox(img)
|
|
local x1 = ox + math.floor(bx1 * scale + 0.5) + 1
|
|
local y1 = oy + math.floor(by1 * scale + 0.5) + 1
|
|
local x2 = ox + math.floor(bx2 * scale + 0.5) - 2
|
|
local y2 = oy + math.floor(by2 * scale + 0.5) - 2
|
|
local c = { obj = 0, bg = 0, black = 0, total = 0 }
|
|
for y = math.max(0, y1), math.min(H - 1, y2) do
|
|
for x = math.max(0, x1), math.min(W - 1, x2) do
|
|
local r, g, b = img:getPixel(x, y)
|
|
local R = math.floor(r * 255 + 0.5)
|
|
local G = math.floor(g * 255 + 0.5)
|
|
local B = math.floor(b * 255 + 0.5)
|
|
c.total = c.total + 1
|
|
if R < 20 and G < 20 and B < 20 then c.black = c.black + 1 end
|
|
if near(R, G, B, objRamp[1]) or near(R, G, B, objRamp[2]) then c.obj = c.obj + 1 end
|
|
if near(R, G, B, bgRamp[1]) or near(R, G, B, bgRamp[2]) then c.bg = c.bg + 1 end
|
|
end
|
|
end
|
|
local d = scale * scale
|
|
c.obj = math.floor(c.obj / d + 0.5)
|
|
c.bg = math.floor(c.bg / d + 0.5)
|
|
return c
|
|
end
|
|
|
|
local movie
|
|
check(tag .. " intro is on the stack", waitFor(function()
|
|
movie = game.stack:top()
|
|
return getmetatable(movie) == IntroMovie
|
|
end, 600))
|
|
if getmetatable(movie) ~= IntroMovie then finish() end
|
|
|
|
game.save.options.colors = "ogred"
|
|
P.applyOptions(game.save.options)
|
|
check(tag .. " COLORS is ogred", P.mode == "ogred", P.mode)
|
|
local blue = GameVersion.isBlue()
|
|
local obj = blue and P.GBC_OBJ_BLUE or P.GBC_OBJ
|
|
local bg = P.ogBg()
|
|
objRamp = { obj[2], obj[3] }
|
|
bgRamp = { bg[2], bg[3] }
|
|
|
|
check(tag .. " scrollIn finished", waitFor(function()
|
|
return movie.phase == 3 and movie.opIndex > 1 and movie.nidoX == 72
|
|
end, 3000), tostring(movie.nidoX))
|
|
waitRenderedFrames(3)
|
|
local nidoX, nidoY, gengarX = movie.nidoX, movie.nidoY, movie.gengarX
|
|
local shot1 = SHOT_DIR .. "/" .. tag .. "_01_fight_after_scroll_in.png"
|
|
check(tag .. " replay recorded", #P.uiSpriteRedraws() >= 2, "#" .. #P.uiSpriteRedraws())
|
|
if check(tag .. " shot 01", U.shot(game, shot1) and load(shot1)) then
|
|
local nido = census(shot1, math.max(nidoX, gengarX + 56), nidoY, nidoX + 48, 112)
|
|
local gengar = census(shot1, gengarX, 56, math.min(gengarX + 56, nidoX), 112)
|
|
local topBar = census(shot1, 0, 0, 160, 32)
|
|
local botBar = census(shot1, 0, 112, 160, 144)
|
|
U.log(string.format("nido band obj=%d bg=%d | gengar band obj=%d bg=%d",
|
|
nido.obj, nido.bg, gengar.obj, gengar.bg))
|
|
check(tag .. " front mon wears the boot-ROM OBJ ramp", nido.obj > 150, nido.obj)
|
|
check(tag .. " front mon carries no BG ramp", nido.bg < 20, nido.bg)
|
|
check(tag .. " Gengar keeps the BG ramp", gengar.bg > 150, gengar.bg)
|
|
check(tag .. " Gengar carries no OBJ ramp", gengar.obj < 20, gengar.obj)
|
|
check(tag .. " top bar stays solid black", topBar.black == topBar.total,
|
|
topBar.black .. "/" .. topBar.total)
|
|
check(tag .. " bottom bar covers the OAM_PRIO sprite", botBar.black == botBar.total,
|
|
botBar.black .. "/" .. botBar.total)
|
|
end
|
|
|
|
local function near1(path, c, bx1, by1, bx2, by2)
|
|
local img = load(path)
|
|
if not img then return 0, 1 end
|
|
local ox, oy, scale = letterbox(img)
|
|
local hit, total = 0, 0
|
|
for y = oy + math.floor(by1 * scale) + 1, oy + math.floor(by2 * scale) - 2 do
|
|
for x = ox + math.floor(bx1 * scale) + 1, ox + math.floor(bx2 * scale) - 2 do
|
|
local r, g, b = img:getPixel(x, y)
|
|
total = total + 1
|
|
if near(math.floor(r * 255 + 0.5), math.floor(g * 255 + 0.5),
|
|
math.floor(b * 255 + 0.5), c) then hit = hit + 1 end
|
|
end
|
|
end
|
|
return hit, total
|
|
end
|
|
|
|
for step, want in ipairs({ { name = "fadepal6_bars_bg_shade2", c = bg[3] },
|
|
{ name = "fadepal7_bars_bg_shade1", c = bg[2] } }) do
|
|
check(tag .. " reached fade step " .. step, waitFor(function()
|
|
return movie.fadeStep == step or movie.phase == 4
|
|
end, 3000), tostring(movie.fadeStep))
|
|
if movie.phase ~= 3 then break end
|
|
local upd = movie.update
|
|
movie.update = function() end
|
|
waitRenderedFrames(2)
|
|
local shot = SHOT_DIR .. "/" .. tag .. "_0" .. (step + 1) .. "_" .. want.name .. ".png"
|
|
if check(tag .. " shot fade step " .. step, U.shot(game, shot) and load(shot)) then
|
|
local hit, total = near1(shot, want.c, 0, 112, 160, 144)
|
|
check(tag .. " fade step " .. step .. " bottom bar is BG shade " .. (3 - step),
|
|
hit == total, hit .. "/" .. total)
|
|
hit, total = near1(shot, want.c, 0, 0, 160, 32)
|
|
check(tag .. " fade step " .. step .. " top bar is BG shade " .. (3 - step),
|
|
hit == total, hit .. "/" .. total)
|
|
end
|
|
movie.update = upd
|
|
end
|
|
|
|
finish()
|
|
end
|