mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-22 13:36:14 +02:00
Fix Gen 1/2 battle, menu, PC and audio parity gaps; wire luacheck into CI
CLOSES #1484, CLOSES #1486, CLOSES #1513, CLOSES #1517, CLOSES #1556, CLOSES #1564, CLOSES #1567
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
-- #1556: the bump sound, which the Gen 2 port never wired.
|
||||
--
|
||||
-- POKEPORT_IDENTITY=gold-dev POKEPORT_GAME=gold POKEPORT_TOUCH=0 \
|
||||
-- POKEPORT_DRIVER=tests/drivers/gold_bug1556_bump.lua \
|
||||
-- perl -e 'alarm 420; exec @ARGV' \
|
||||
-- python3 -c "import pty; pty.spawn(['love','.'])"
|
||||
-- POKEPORT_SHOT_DIR=/tmp/gold-bug1556-bump (default)
|
||||
--
|
||||
-- Nothing here can be asserted by a unit test: the deliverable is the sound.
|
||||
-- What the log gives a reader is the RATE, which is the half that is easy to
|
||||
-- get wrong -- .BumpSound is `call CheckSFX / ret c`
|
||||
-- (engine/overworld/player_movement.asm:771), a busy-channel test rather than
|
||||
-- a frame counter, so a held direction re-rings only once the previous Sfx_Bump
|
||||
-- has stopped. A per-frame count means Sound.sfxBusy() is not seeing it.
|
||||
--
|
||||
-- Five moments, in the cart's own terms:
|
||||
-- 1. a wall .CheckLandPerms carry -> .bump (:264-265)
|
||||
-- 2. an NPC .CheckNPC = 0 -> .bump (:267-269)
|
||||
-- 3. a ledge hop .TryJump's carry returns ABOVE .NotMoving (:80-81),
|
||||
-- so the hop is Sfx_JumpOverLedge and NO bump
|
||||
-- 4. a map connection the step is taken; silence
|
||||
-- 5. a map edge with no connection behind it: the border block is a wall
|
||||
--
|
||||
-- The run ends in the overworld so a human takes the controls where it stops.
|
||||
local U = require("tests.drivers.util")
|
||||
|
||||
local Permissions = require("src.world.gen2.Permissions")
|
||||
local Sound = require("src.core.Sound")
|
||||
|
||||
return function(game)
|
||||
local out = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/gold-bug1556-bump"
|
||||
|
||||
local heard = {}
|
||||
local realPlay = Sound.play
|
||||
Sound.play = function(data, name)
|
||||
heard[#heard + 1] = name
|
||||
return realPlay(data, name)
|
||||
end
|
||||
|
||||
local function reset() heard = {} end
|
||||
|
||||
local function report(label)
|
||||
local counts, order = {}, {}
|
||||
for _, name in ipairs(heard) do
|
||||
if not counts[name] then order[#order + 1] = name end
|
||||
counts[name] = (counts[name] or 0) + 1
|
||||
end
|
||||
local parts = {}
|
||||
for _, name in ipairs(order) do
|
||||
parts[#parts + 1] = ("%s x%d"):format(name, counts[name])
|
||||
end
|
||||
U.log(label, #parts > 0 and table.concat(parts, ", ") or "(silence)")
|
||||
return counts
|
||||
end
|
||||
|
||||
U.wait(45)
|
||||
local w = game.world
|
||||
assert(w and w.map, "gold world did not boot")
|
||||
|
||||
local function walkable(map, x, y)
|
||||
return map:inBounds(x, y) and map:isWalkable(x, y)
|
||||
end
|
||||
|
||||
local DELTA = { up = { 0, -1 }, down = { 0, 1 },
|
||||
left = { -1, 0 }, right = { 1, 0 } }
|
||||
|
||||
-- A standing cell whose neighbour in `dir` is a wall.
|
||||
local function findWall(map)
|
||||
for y = 0, map.heightCells - 1 do
|
||||
for x = 0, map.widthCells - 1 do
|
||||
if walkable(map, x, y) then
|
||||
for dir, d in pairs(DELTA) do
|
||||
local nx, ny = x + d[1], y + d[2]
|
||||
if map:inBounds(nx, ny) and not map:isWalkable(nx, ny) then
|
||||
return x, y, dir
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ---- 1. a wall -----------------------------------------------------------
|
||||
assert(w:setMap("PLAYERS_HOUSE_1F", 4, 4, "down"), "setMap PLAYERS_HOUSE_1F")
|
||||
U.wait(5)
|
||||
local wx, wy, wdir = findWall(w.map)
|
||||
if wx then
|
||||
assert(w:setMap("PLAYERS_HOUSE_1F", wx, wy, wdir))
|
||||
U.wait(8)
|
||||
reset()
|
||||
U.hold(game, wdir, 90)
|
||||
U.wait(5)
|
||||
local counts = report("01 wall (" .. wdir .. ", 90 frames held):")
|
||||
U.log(" Sfx_Bump over 90 held frames:", counts.Sfx_Bump or 0,
|
||||
"-- a per-frame count here means the CheckSFX gate is not working")
|
||||
U.shot(game, out .. "/01-wall.png")
|
||||
else
|
||||
U.log("SKIP 01 wall -- no wall cell found in PLAYERS_HOUSE_1F")
|
||||
end
|
||||
|
||||
-- ---- 2. an NPC -----------------------------------------------------------
|
||||
local npc, npcDir
|
||||
for _, e in ipairs(w.entities or {}) do
|
||||
if e ~= w.player and e.cellX and not e.bigObject then
|
||||
for dir, d in pairs(DELTA) do
|
||||
local sx, sy = e.cellX - d[1], e.cellY - d[2]
|
||||
if walkable(w.map, sx, sy) then npc, npcDir = { sx, sy }, dir break end
|
||||
end
|
||||
end
|
||||
if npc then break end
|
||||
end
|
||||
if npc then
|
||||
assert(w:setMap("PLAYERS_HOUSE_1F", npc[1], npc[2], npcDir))
|
||||
U.wait(8)
|
||||
reset()
|
||||
U.hold(game, npcDir, 45)
|
||||
U.wait(5)
|
||||
report("02 NPC (" .. npcDir .. "):")
|
||||
U.shot(game, out .. "/02-npc.png")
|
||||
else
|
||||
U.log("SKIP 02 NPC -- no reachable NPC in PLAYERS_HOUSE_1F")
|
||||
end
|
||||
|
||||
-- ---- 3. a ledge ----------------------------------------------------------
|
||||
local ROUTES = { "ROUTE_29", "ROUTE_30", "ROUTE_31", "ROUTE_32",
|
||||
"ROUTE_33", "ROUTE_34", "ROUTE_35", "ROUTE_36" }
|
||||
local hopped = false
|
||||
for _, mapId in ipairs(ROUTES) do
|
||||
if w:setMap(mapId, 5, 5, "down") then
|
||||
U.wait(5)
|
||||
local map = w.map
|
||||
for y = 0, map.heightCells - 1 do
|
||||
for x = 0, map.widthCells - 1 do
|
||||
local facings = Permissions.ledgeFacings(map:cellCollision(x, y))
|
||||
if facings then
|
||||
for dir, on in pairs(facings) do
|
||||
local d = on and DELTA[dir]
|
||||
if d and walkable(map, x + d[1] * 2, y + d[2] * 2) then
|
||||
assert(w:setMap(mapId, x, y, dir))
|
||||
U.wait(8)
|
||||
reset()
|
||||
U.hold(game, dir, 40)
|
||||
U.wait(20)
|
||||
local counts = report(
|
||||
("03 ledge hop (%s %s):"):format(mapId, dir))
|
||||
U.log(" want Sfx_JumpOverLedge and NO Sfx_Bump; bumps:",
|
||||
counts.Sfx_Bump or 0)
|
||||
U.shot(game, out .. "/03-ledge.png")
|
||||
hopped = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if hopped then break end
|
||||
end
|
||||
if hopped then break end
|
||||
end
|
||||
end
|
||||
if hopped then break end
|
||||
end
|
||||
if not hopped then U.log("SKIP 03 ledge -- no hoppable ledge found") end
|
||||
|
||||
-- ---- 4 and 5. map edges --------------------------------------------------
|
||||
assert(w:setMap("NEW_BARK_TOWN", 5, 5, "down"), "setMap NEW_BARK_TOWN")
|
||||
U.wait(5)
|
||||
local DIR_CONN = { up = "north", down = "south", left = "west",
|
||||
right = "east" }
|
||||
local map = w.map
|
||||
local function edgeCell(dir)
|
||||
local d = DELTA[dir]
|
||||
for y = 0, map.heightCells - 1 do
|
||||
for x = 0, map.widthCells - 1 do
|
||||
if walkable(map, x, y)
|
||||
and not map:inBounds(x + d[1], y + d[2]) then
|
||||
return x, y
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, dir in ipairs({ "up", "down", "left", "right" }) do
|
||||
local conn = map:connection(DIR_CONN[dir])
|
||||
local ex, ey = edgeCell(dir)
|
||||
if ex then
|
||||
assert(w:setMap("NEW_BARK_TOWN", ex, ey, dir))
|
||||
U.wait(8)
|
||||
reset()
|
||||
U.hold(game, dir, 40)
|
||||
U.wait(20)
|
||||
local counts = report(("%s edge %s (connection: %s):")
|
||||
:format(conn and "04" or "05", dir,
|
||||
tostring(conn and conn.mapId or "none")))
|
||||
U.log(" want", conn and "silence" or "Sfx_Bump", "-- bumps:",
|
||||
counts.Sfx_Bump or 0)
|
||||
U.shot(game, out .. ("/0%s-edge-%s.png"):format(conn and "4" or "5", dir))
|
||||
assert(w:setMap("NEW_BARK_TOWN", ex, ey, dir))
|
||||
U.wait(5)
|
||||
end
|
||||
end
|
||||
|
||||
Sound.play = realPlay
|
||||
assert(w:setMap("NEW_BARK_TOWN", 5, 5, "down"))
|
||||
U.log("done -- the controls are yours; walk into anything")
|
||||
end
|
||||
Reference in New Issue
Block a user