mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-15 07:41:21 +02:00
160 lines
6.2 KiB
Lua
160 lines
6.2 KiB
Lua
-- Gold's world-pipeline seam (World:drawPipeline), the Gen 2 peer of the
|
|
-- render_pipelines path src/world/OverworldController.lua:4867 gives Gen 1.
|
|
--
|
|
-- POKEPORT_IDENTITY=gold-dev POKEPORT_GAME=gold \
|
|
-- POKEPORT_DRIVER=tests/drivers/gold_pipeline_shots.lua love .
|
|
-- POKEPORT_SHOT_DIR=/tmp/gold-pipeline (default)
|
|
--
|
|
-- Registers a pipeline that paints an unmistakable magenta field, switches it
|
|
-- on, and asserts what the seam is supposed to guarantee: drawWorld owns the
|
|
-- frame, ctx carries the Gen 1 keys, ctx.drawFx anchors the standing FX,
|
|
-- worldPresent folds over the result, tilt is forced off, and a declined
|
|
-- frame falls back to the vanilla 2D draw instead of a blank screen.
|
|
local U = require("tests.drivers.util")
|
|
|
|
local Pipelines = require("src.render.Pipelines")
|
|
local Tilt = require("src.render.Tilt")
|
|
|
|
return function(game)
|
|
local out = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/gold-pipeline"
|
|
local failures = 0
|
|
|
|
local function ok(label, condition, detail)
|
|
if condition then
|
|
print("[pipeline] ok " .. label)
|
|
else
|
|
failures = failures + 1
|
|
print("[pipeline] FAIL " .. label .. " " .. tostring(detail))
|
|
end
|
|
end
|
|
|
|
U.wait(45)
|
|
local world = game.world
|
|
assert(world and world.map, "gold world did not boot")
|
|
|
|
world:setMap("ROUTE_30", 10, 10, "down")
|
|
U.wait(10)
|
|
U.shot(game, out .. "/00-vanilla.png")
|
|
|
|
-- ---------------------------------------------------------------- record
|
|
local seen, canvas = {}, nil
|
|
local decline = false
|
|
local pipeline = {
|
|
label = "TESTPIPE",
|
|
levels = { "OFF", "ON" },
|
|
drawWorld = function(ctx)
|
|
seen.ctx = ctx
|
|
seen.drawWorld = (seen.drawWorld or 0) + 1
|
|
if decline then return nil end
|
|
local G = love.graphics
|
|
local w, h = ctx.width, ctx.height
|
|
if not canvas or canvas:getWidth() ~= w or canvas:getHeight() ~= h then
|
|
canvas = G.newCanvas(w, h)
|
|
end
|
|
local previous = G.getCanvas()
|
|
G.push("all")
|
|
G.origin()
|
|
G.setCanvas(canvas)
|
|
G.clear(0.8, 0.1, 0.6, 1)
|
|
G.setColor(1, 1, 1, 1)
|
|
for x = 0, w, 32 do G.rectangle("fill", x, 0, 1, h) end
|
|
for y = 0, h, 32 do G.rectangle("fill", 0, y, w, 1) end
|
|
-- the standing FX, anchored under this pipeline's own (identity) camera
|
|
ctx.drawFx(function(wx, wy)
|
|
return (wx - ctx.cam.x) * ctx.scale, (wy - ctx.cam.y) * ctx.scale
|
|
end, ctx.scale)
|
|
G.setCanvas(previous)
|
|
G.pop()
|
|
seen.drew = true
|
|
return canvas
|
|
end,
|
|
worldPresent = function(image, ctx)
|
|
seen.worldPresent = (seen.worldPresent or 0) + 1
|
|
seen.presentCtx = ctx
|
|
return image
|
|
end,
|
|
}
|
|
|
|
-- A fresh table so Pipelines.list()'s identity-keyed memo re-sorts; the
|
|
-- mod merge hands it a new one for the same reason.
|
|
game.data.render_pipelines = { testpipe = pipeline }
|
|
Pipelines.install(game.data)
|
|
ok("registered", Pipelines.get("testpipe") ~= nil, "not in the registry")
|
|
|
|
-- ------------------------------------------------------------ switched on
|
|
Tilt.setLevel(1)
|
|
Pipelines.setLevel("testpipe", 1)
|
|
ok("tilt forced off", Tilt.level == 0, "tilt still " .. tostring(Tilt.level))
|
|
ok("world pipeline claimed", Pipelines.worldPipeline() == "testpipe",
|
|
tostring(Pipelines.worldPipeline()))
|
|
U.wait(5)
|
|
U.shot(game, out .. "/01-pipeline-on.png")
|
|
|
|
ok("drawWorld ran", (seen.drawWorld or 0) > 0, "never called")
|
|
ok("drawWorld drew", seen.drew == true, "declined every frame")
|
|
ok("worldPresent ran", (seen.worldPresent or 0) > 0, "never called")
|
|
|
|
local ctx = seen.ctx
|
|
ok("ctx.state is the world", ctx and ctx.state == world, "wrong state")
|
|
ok("ctx.cam is the camera", ctx and ctx.cam == world.camera, "wrong camera")
|
|
ok("ctx.scale is zoomScale", ctx and ctx.scale == world:zoomScale(),
|
|
ctx and tostring(ctx.scale))
|
|
ok("ctx.bgY is the camera row", ctx and ctx.bgY == world.camera.y,
|
|
ctx and tostring(ctx.bgY))
|
|
ok("ctx.vw/vh are the view", ctx and ctx.vw == world.viewW
|
|
and ctx.vh == world.viewH, ctx and tostring(ctx.vw))
|
|
ok("ctx.level is the ladder", ctx and ctx.level == 1, ctx and tostring(ctx.level))
|
|
ok("ctx.width/height are the window",
|
|
ctx and ctx.width == love.graphics.getWidth()
|
|
and ctx.height == love.graphics.getHeight(), "mismatch")
|
|
ok("ctx.paletteFor is nil-valued (art is baked)",
|
|
ctx and ctx.paletteFor and ctx.paletteFor(world.map) == nil, "returned colours")
|
|
ok("ctx.spriteColors is nil-valued",
|
|
ctx and ctx.spriteColors and ctx.spriteColors() == nil, "returned colours")
|
|
ok("ctx.fx has Gold's two effects",
|
|
ctx and ctx.fx and type(ctx.fx.emote) == "function"
|
|
and type(ctx.fx.heal) == "function", "missing fx")
|
|
ok("ctx.drawFx is callable", ctx and type(ctx.drawFx) == "function", "missing")
|
|
ok("worldPresent got the same ctx", seen.presentCtx == seen.ctx, "different ctx")
|
|
|
|
-- ------------------------------------------------- the FX composite path
|
|
-- An emote over the player exercises ctx.drawFx end to end: it must be the
|
|
-- pipeline that composites it, and the vanilla drawPeople must not also.
|
|
local sheet
|
|
for _, img in pairs(world.emoteImages or {}) do sheet = img break end
|
|
if sheet then
|
|
world.emote = { image = sheet, entity = world.player, left = 240 }
|
|
end
|
|
U.wait(4)
|
|
ok("emote is up", world.emote ~= nil, "no emote sheet loaded")
|
|
local fxOk = pcall(function()
|
|
-- the same call the pipeline made, run again outside the guard so a throw
|
|
-- surfaces here rather than only retiring the pipeline
|
|
seen.ctx.drawFx(function(wx, wy) return wx, wy end, 1)
|
|
end)
|
|
ok("drawFx composites without throwing", fxOk, "threw")
|
|
U.shot(game, out .. "/02-pipeline-emote.png")
|
|
|
|
-- ----------------------------------------------------- a declined frame
|
|
decline = true
|
|
U.wait(5)
|
|
U.shot(game, out .. "/03-pipeline-declined.png")
|
|
ok("declined frames still call drawWorld", (seen.drawWorld or 0) > 1, "stopped")
|
|
decline = false
|
|
|
|
-- ------------------------------------------------------------ switched off
|
|
Pipelines.setLevel("testpipe", 0)
|
|
local before = seen.drawWorld
|
|
U.wait(5)
|
|
ok("off means not called", seen.drawWorld == before,
|
|
"still drawing at level 0")
|
|
U.shot(game, out .. "/04-pipeline-off.png")
|
|
|
|
if failures == 0 then
|
|
print("[pipeline] PASS")
|
|
else
|
|
print("[pipeline] FAILURES: " .. failures)
|
|
end
|
|
love.event.quit(failures == 0 and 0 or 1)
|
|
end
|