Files
gen1recomp/tests/drivers/museum_back_entrance_bug1690_test.lua
T
bryanthaboi 1905261c5b Spider Car Unleashed
CLOSES #1483, CLOSES #1610, CLOSES #1615, CLOSES #1646, CLOSES #1649, CLOSES #1651, CLOSES #1653, CLOSES #1656, CLOSES #1683, CLOSES #1685, CLOSES #1686, CLOSES #1687, CLOSES #1688, CLOSES #1689, CLOSES #1690, CLOSES #1693, CLOSES #1694, CLOSES #1695, CLOSES #1696, CLOSES #1702, CLOSES #1704, CLOSES #1705, CLOSES #1706, CLOSES #1707, CLOSES #1708, CLOSES #1710, CLOSES #1711, CLOSES #1712, CLOSES #1713, CLOSES #1716, CLOSES #1717, CLOSES #1718, CLOSES #1719, CLOSES #1720, CLOSES #1721, CLOSES #1725, CLOSES #1732, CLOSES #1745, CLOSES #1748, CLOSES #1749, CLOSES #1751, CLOSES #1754
2026-08-24 07:52:05 -04:00

212 lines
8.2 KiB
Lua

-- Manual check of the Pewter museum clerk's back-entrance branches (#1690).
-- scripts/Museum1F.asm:45 reads wYCoord/wXCoord before the ticket flag, so
-- (13,4) and (12,3) behind the counter get the AMBER question and row 4 in
-- front of it gets the ¥50 ask. This walks all three by itself.
-- Do not add POKEPORT_SPEED: fast-forward scales only the logic clock, and
-- what is being judged here is page order and the choice box timing.
-- POKEPORT_DRIVER=tests/drivers/museum_back_entrance_bug1690_test.lua POKEPORT_TOUCH=0 POKEPORT_VERSION=red POKEPORT_IDENTITY=bug1690 SHOT_DIR=/tmp/museum1690 love .
return function(game)
local U = dofile("tests/drivers/util.lua")
local TextBox = require("src.render.TextBox")
local ChoiceBox = require("src.ui.ChoiceBox")
local SHOT_DIR = os.getenv("SHOT_DIR") or "/tmp/shots"
local MAP = "MUSEUM_1F"
local CLERK_TEXT = "TEXT_MUSEUM1F_SCIENTIST1"
-- pokered data/maps/objects/Museum1F.asm: MUSEUM1F_SCIENTIST1 at (12,4),
-- counter column x==11, back door warps in at (16,7)/(17,7)
local BEHIND_EAST = { x = 13, y = 4, facing = "left" }
local BEHIND_NORTH = { x = 12, y = 3, facing = "down" }
local IN_FRONT = { x = 10, y = 4, facing = "right" }
local function check(label, ok)
U.log(ok and "PASS" or "FAIL", label)
return ok
end
-- every one of these failing looks exactly like the bug on screen: a
-- missing string, a renamed key or an unwalkable cell all end in silence
local t = game.data.text or {}
for _, key in ipairs({
"_Museum1FScientist1DoYouKnowWhatAmberIsText",
"_Museum1FScientist1TheresALabSomewhereText",
"_Museum1FScientist1AmberIsFossilizedTreeSapText",
"_Museum1FScientist1GoToOtherSideText",
"_Museum1FScientist1WouldYouLikeToComeInText",
}) do
check(key .. " is in the text catalog",
type(t[key]) == "string" and t[key] ~= "")
end
local function clerkIn(ow)
for _, n in ipairs(ow and ow.npcs or {}) do
if n.def and n.def.text == CLERK_TEXT then return n end
end
return nil
end
local function boxText(box)
local shown = {}
for _, page in ipairs(box.pages or {}) do
for _, line in ipairs(page) do shown[#shown + 1] = line end
end
return table.concat(shown, " / ")
end
-- talking works either straight at the clerk or across the counter tile
local function facingTheClerk()
local ow = game.overworld
local clerk = clerkIn(ow)
if not clerk then return false end
local fx, fy = ow.player:facingCell()
if ow:npcAtCell(fx, fy) == clerk then return true end
if ow.map:isCounterCell(fx, fy) then
local Collision = require("src.world.Collision")
local bx, by = Collision.target(fx, fy, ow.player.facing)
return ow:npcAtCell(bx, by) == clerk
end
return false
end
-- teleport to `spot`, and if a map edit moved the counter fall back to any
-- free walkable neighbour of the clerk so this degrades instead of parking
-- the player at a wall
local function standAt(spot, label)
U.teleport(game, MAP, spot.x, spot.y, spot.facing)
U.wait(10)
if facingTheClerk() then return check(label .. ": in position", true) end
local ow = game.overworld
local clerk = clerkIn(ow)
if clerk then
local sides = {
{ 0, 1, "up" }, { 0, -1, "down" }, { 1, 0, "left" }, { -1, 0, "right" },
}
for _, s in ipairs(sides) do
local cx, cy = clerk.cellX + s[1], clerk.cellY + s[2]
if ow.map:isWalkableCell(cx, cy) and not ow:npcAtCell(cx, cy) then
U.log(("(%d,%d) does not reach the clerk, standing on")
:format(spot.x, spot.y), cx, cy, "facing", s[3])
U.teleport(game, MAP, cx, cy, s[3])
U.wait(10)
break
end
end
end
return check(label .. ": in position", facingTheClerk())
end
-- press A and wait for the dialogue box to actually mount
local function talk()
U.tap(game, "a")
for _ = 1, 60 do
local top = game.stack:top()
if getmetatable(top) == TextBox then return top end
U.wait(1)
end
return nil
end
-- page through until the YES/NO box pops (the clerk's question is two
-- pages, so one A press sits between the box opening and the choice)
local function toChoice()
for _ = 1, 20 do
if getmetatable(game.stack:top()) == ChoiceBox then
return game.stack:top()
end
U.tap(game, "a")
U.wait(20)
end
return getmetatable(game.stack:top()) == ChoiceBox and game.stack:top() or nil
end
-- ChoiceBox starts on YES; NO is one step down
local function answer(yes)
if not yes then U.tap(game, "down") U.wait(10) end
U.tap(game, "a")
for _ = 1, 60 do
local top = game.stack:top()
if getmetatable(top) == TextBox then return top end
U.wait(1)
end
return nil
end
game.save.flags = game.save.flags or {}
game.save.flags.EVENT_BOUGHT_MUSEUM_TICKET = nil
standAt(BEHIND_EAST, "east of the clerk (13,4)")
local box = talk()
if check("A behind the counter opens a box", box ~= nil) then
U.log("box reads:", boxText(box))
check("it is the can't-sneak-in-the-back-way line",
boxText(box):find("sneak", 1, true) ~= nil)
check("no money window rides along with it", box.money == nil)
U.shot(game, SHOT_DIR .. "/bug1690_a_sneak.png")
end
local choice = toChoice()
if check("the AMBER question offers YES/NO", choice ~= nil) then
U.shot(game, SHOT_DIR .. "/bug1690_b_amber_choice.png")
local answered = answer(true)
if check("YES opens a follow-up box", answered ~= nil) then
U.log("YES reads:", boxText(answered))
check("YES is the resurrection lab line",
boxText(answered):find("lab", 1, true) ~= nil)
U.shot(game, SHOT_DIR .. "/bug1690_c_lab.png")
end
end
-- with the ticket already bought the coordinate check still wins: a
-- ticket holder round the back is told off, not thanked (asm:45 runs
-- before the CheckEvent at asm:59)
game.save.flags.EVENT_BOUGHT_MUSEUM_TICKET = true
standAt(BEHIND_NORTH, "north of the clerk (12,3), ticket in hand")
box = talk()
if check("A north of the clerk opens a box", box ~= nil) then
U.log("box reads:", boxText(box))
check("a ticket holder round the back still gets told off",
boxText(box):find("sneak", 1, true) ~= nil)
U.shot(game, SHOT_DIR .. "/bug1690_d_ticket_holder_sneak.png")
end
choice = toChoice()
if check("it still offers YES/NO", choice ~= nil) then
local answered = answer(false)
if check("NO opens a follow-up box", answered ~= nil) then
U.log("NO reads:", boxText(answered))
check("NO is the fossilized tree sap line",
boxText(answered):find("tree sap", 1, true) ~= nil)
U.shot(game, SHOT_DIR .. "/bug1690_e_tree_sap.png")
end
end
-- the control case: the public side of the counter is untouched
game.save.flags.EVENT_BOUGHT_MUSEUM_TICKET = nil
game.save.money = 3000
standAt(IN_FRONT, "in front of the counter (10,4)")
box = talk()
if check("A across the counter opens a box", box ~= nil) then
U.log("box reads:", boxText(box))
check("the front of the counter is still the ¥50 ticket ask",
boxText(box):find("50", 1, true) ~= nil)
check("and it still raises the money window", box.money ~= nil)
U.shot(game, SHOT_DIR .. "/bug1690_f_ticket_ask.png")
end
U.log("shots are in " .. SHOT_DIR .. ", in the order they were taken.")
U.log("behind the counter the clerk should say \"You can't sneak in the back")
U.log("way!\", then \"Oh, whatever! Do you know what AMBER is?\" with YES/NO,")
U.log("and never a money window. YES talks about a lab resurrecting ancient")
U.log("POKeMON, NO says AMBER is fossilized tree sap. The box left on screen")
U.log("now is the last case: standing at (10,4) with no ticket, which must")
U.log("still be the ¥50 ask with the money window in the corner.")
U.log("the near misses to watch for: a money window sitting behind the AMBER")
U.log("question, or \"Take your time, and enjoy it all!\" at (12,3) once the")
U.log("ticket flag is set, which would mean the ticket check ran first.")
U.log("Yellow shares this script, so POKEPORT_VERSION=yellow should read")
U.log("exactly the same at all three spots.")
while true do
coroutine.yield()
end
end