mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
159 lines
6.0 KiB
Lua
159 lines
6.0 KiB
Lua
#!/usr/bin/env luajit
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
local GameCache = require("tests.game3_cache")
|
|
local root = GameCache.mountOrSkip("game3_ball_sheets_test")
|
|
require("tests.fixture_data.game3_items").install()
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local function slurp(path)
|
|
local f = io.open(path, "rb")
|
|
if not f then return nil end
|
|
local d = f:read("*a")
|
|
f:close()
|
|
return d
|
|
end
|
|
|
|
local NAMES = { [0] = "poke", "great", "safari", "ultra", "master", "net",
|
|
"dive", "nest", "repeat", "timer", "luxury", "premier" }
|
|
local W, H = 16 * 12, 48
|
|
|
|
local rgba = slurp(root .. "/pokemon/battle/ball_open/balls.rgba")
|
|
print("[test] baked ball sheet strip")
|
|
check(rgba ~= nil and #rgba == W * H * 4, "balls.rgba is 192x48 RGBA")
|
|
|
|
local function alpha(ball, x, y)
|
|
return rgba:byte(((y * W) + ball * 16 + x) * 4 + 4)
|
|
end
|
|
|
|
if rgba and #rgba == W * H * 4 then
|
|
for ball = 0, 11 do
|
|
local n = 0
|
|
for y = 32, 47 do
|
|
for x = 0, 15 do
|
|
if alpha(ball, x, y) ~= 0 then n = n + 1 end
|
|
end
|
|
end
|
|
check(n > 0, "ball " .. NAMES[ball] .. " open frame 2 is not blank")
|
|
end
|
|
|
|
local pret = "../pokefirered/graphics/interface/"
|
|
local openGfx = slurp(pret .. "ball_open.4bpp")
|
|
if not openGfx then
|
|
print("[skip] pret pokefirered graphics not found; pixel parity not checked")
|
|
else
|
|
print("[test] pixel parity vs pret graphics/interface/ball/*.4bpp + ball_open.4bpp")
|
|
local NO_SPLICE = { [6] = true, [10] = true, [11] = true }
|
|
for ball = 0, 11 do
|
|
local gfx = slurp(pret .. "ball/" .. NAMES[ball] .. ".4bpp")
|
|
local pal = slurp(pret .. "ball/" .. NAMES[ball] .. ".gbapal")
|
|
local bad = 0
|
|
for ti = 0, 11 do
|
|
local src, off = gfx, ti * 32
|
|
if ti >= 8 and not NO_SPLICE[ball] then src, off = openGfx, (ti - 8) * 32 end
|
|
local frame, sub = math.floor(ti / 4), ti % 4
|
|
for py = 0, 7 do
|
|
for px = 0, 7 do
|
|
local byte = src:byte(off + py * 4 + math.floor(px / 2) + 1)
|
|
local idx = (px % 2 == 0) and (byte % 16) or math.floor(byte / 16)
|
|
local x = (sub % 2) * 8 + px
|
|
local y = frame * 16 + math.floor(sub / 2) * 8 + py
|
|
local o = ((y * W) + ball * 16 + x) * 4
|
|
local r, g, b, a = rgba:byte(o + 1, o + 4)
|
|
if idx == 0 then
|
|
if a ~= 0 then bad = bad + 1 end
|
|
else
|
|
local c = pal:byte(idx * 2 + 1) + pal:byte(idx * 2 + 2) * 256
|
|
local er, eg, eb = c % 32, math.floor(c / 32) % 32, math.floor(c / 1024) % 32
|
|
local function to8(v) return math.floor(v * 255 / 31 + 0.5) end
|
|
if a ~= 255 or r ~= to8(er) or g ~= to8(eg) or b ~= to8(eb) then bad = bad + 1 end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
check(bad == 0, NAMES[ball] .. " ball sheet matches pret (" .. bad .. " px differ)")
|
|
end
|
|
end
|
|
end
|
|
|
|
local BallOpen = require("src.core.game3.battle.ball_open")
|
|
local Anim = require("src.core.game3.battle.anim")
|
|
local CatchSeq = require("src.core.game3.battle.catch_seq")
|
|
local Catching = require("src.core.game3.battle.catching")
|
|
local Audio = require("src.core.game3.audio")
|
|
local Ui = require("src.core.game3.battle.ui")
|
|
local SummaryMenu = require("src.ui.game3.summary_menu")
|
|
|
|
print("[test] manifest names the ball strip")
|
|
local d = BallOpen.data()
|
|
check(d and d.ballSheet == "balls.rgba" and d.ballSheetW == W and d.ballSheetH == H, "manifest ballSheet/ballSheetW/ballSheetH")
|
|
|
|
print("[test] battle renderer picks the per-ball column")
|
|
local realLove = rawget(_G, "love")
|
|
love = {
|
|
image = { newImageData = function(w, h) return { w = w, h = h } end },
|
|
graphics = {
|
|
newImage = function(id) return { getDimensions = function() return id.w, id.h end, setFilter = function() end } end,
|
|
newQuad = function(x, y, w, h) return { x = x, y = y, w = w, h = h } end,
|
|
},
|
|
}
|
|
local okQ = type(Ui.ballQuad) == "function"
|
|
check(okQ, "Ui.ballQuad exists")
|
|
if okQ then
|
|
local img, q = Ui.ballQuad(11, 2)
|
|
check(img ~= nil and q and q.x == 176 and q.y == 32, "premier open frame quad at (176,32)")
|
|
local _, q3 = Ui.ballQuad(3, 0)
|
|
check(q3 and q3.x == 48 and q3.y == 0, "ultra closed frame quad at (48,0)")
|
|
local _, qn = Ui.ballQuad(nil, 1)
|
|
check(qn and qn.x == 0 and qn.y == 16, "missing ball id draws the poke ball")
|
|
end
|
|
love = realLove
|
|
|
|
print("[test] thrown ball is tagged with the used item's ball")
|
|
Audio.playSe = function() return true end
|
|
Audio.stopAll = function() end
|
|
Audio.waitSe = function() end
|
|
Audio.playSong = function() return true end
|
|
Catching.storeCaught = function() return { firstTimeCaught = false } end
|
|
Ui.battlerSpriteCenter = function(_, _, base) return base.x, base.y end
|
|
for _, case in ipairs({ { 12, 11 }, { 2, 3 }, { 3, 1 }, { 1, 4 }, { 4, 0 }, { 11, 10 }, { 7, 6 } }) do
|
|
Anim.reset({ headless = false })
|
|
Anim.present("enemy").visible = true
|
|
local st = { enemy = { species = 16, mon = { species = 16, name = "PIDGEY" } } }
|
|
CatchSeq.begin(st, case[1], false, 1, {
|
|
pushMsg = function() end, headless = false, session = { name = "RED" },
|
|
})
|
|
CatchSeq.update()
|
|
CatchSeq._waitingMsg = false
|
|
CatchSeq.update()
|
|
local seen
|
|
for _ = 1, 120 do
|
|
Anim.update(1 / 60)
|
|
local s = Anim.stage().ball
|
|
if s.visible then seen = s.ballId break end
|
|
end
|
|
check(seen == case[2], ("item %d throws ball sheet %d (got %s)"):format(case[1], case[2], tostring(seen)))
|
|
end
|
|
|
|
print("[test] summary ball icon id")
|
|
check(type(SummaryMenu.ballIdOf) == "function", "SummaryMenu.ballIdOf exists")
|
|
if type(SummaryMenu.ballIdOf) == "function" then
|
|
check(SummaryMenu.ballIdOf({ species = 25, pokeball = 12 }) == 11, "premier-caught mon shows premier icon")
|
|
check(SummaryMenu.ballIdOf({ species = 25, pokeball = 1 }) == 4, "master-caught mon shows master icon")
|
|
check(SummaryMenu.ballIdOf({ species = 25, pokeball = 12, isEgg = true }) == 0, "egg shows poke ball icon")
|
|
end
|
|
|
|
if failed > 0 then
|
|
print(("[FAIL] %d check(s) failed"):format(failed))
|
|
os.exit(1)
|
|
end
|
|
print("[ok] game3_ball_sheets_test")
|