mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-25 23:11:15 +02:00
1905261c5b
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
234 lines
9.0 KiB
Lua
234 lines
9.0 KiB
Lua
-- Parity test: Vermilion City S.S. Anne sailor (#122).
|
|
--
|
|
-- pokered VermilionCityDefaultScript (scripts/VermilionCity.asm):
|
|
-- stepping onto SSAnneTicketCheckCoords (18,30) facing down always
|
|
-- DisplayTextID's the sailor. With a ticket and the ship still docked,
|
|
-- FlashedTicket plays and the player may continue; without a ticket, or
|
|
-- after EVENT_SS_ANNE_LEFT, they are walked back up.
|
|
--
|
|
-- The port used to early-return when the ticket was in the bag, skipping
|
|
-- the flash dialog entirely.
|
|
--
|
|
-- Self-contained; run via `luajit tests/parity_ss_anne_guard.lua`.
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
if not _G.love then _G.love = require("tests.love_stub") end
|
|
local S = require("tests.harness").suite("parity ss anne guard")
|
|
local check, eq = S.check, S.eq
|
|
|
|
-- restored at the bottom for the suites run after this file
|
|
local realTextBox = package.loaded["src.render.TextBox"]
|
|
local realMusic = package.loaded["src.core.Music"]
|
|
local realSound = package.loaded["src.core.Sound"]
|
|
-- Commands captures TextBox at module load; drop any already-loaded copy
|
|
-- so the script runner below binds the stub, not the real renderer
|
|
local realCommands = package.loaded["src.script.Commands"]
|
|
local realScriptRunner = package.loaded["src.script.ScriptRunner"]
|
|
package.loaded["src.script.Commands"] = nil
|
|
package.loaded["src.script.ScriptRunner"] = nil
|
|
package.loaded["src.render.TextBox"] = {
|
|
new = function(_, text, done) return { text = text, done = done } end,
|
|
}
|
|
|
|
local musicCalls = {}
|
|
package.loaded["src.core.Music"] = {
|
|
stop = function() musicCalls[#musicCalls + 1] = { "stop" } end,
|
|
play = function(_, song)
|
|
musicCalls[#musicCalls + 1] = { "play", song }
|
|
end,
|
|
playOnce = function(_, song)
|
|
musicCalls[#musicCalls + 1] = { "playOnce", song }
|
|
return true
|
|
end,
|
|
}
|
|
|
|
local soundCalls = {}
|
|
package.loaded["src.core.Sound"] = {
|
|
play = function(_, id) soundCalls[#soundCalls + 1] = id end,
|
|
}
|
|
|
|
local story = dofile("data/scripts/story.lua")
|
|
local story3 = dofile("data/scripts/story3.lua")
|
|
local Flags = require("src.script.Flags")
|
|
|
|
local function gameWith(opts)
|
|
local pushed, moved = {}, {}
|
|
local game = {
|
|
save = {
|
|
inventory = opts.inventory or {},
|
|
flags = opts.flags or {},
|
|
},
|
|
data = {
|
|
text = {
|
|
_VermilionCitySailor1DoYouHaveATicketText =
|
|
"Welcome to S.S.\nANNE!\fExcuse me, do you\nhave a ticket?",
|
|
_VermilionCitySailor1FlashedTicketText =
|
|
"PLAYER flashed\nthe S.S.TICKET!",
|
|
_VermilionCitySailor1YouNeedATicketText =
|
|
"You need a ticket\nto get aboard.",
|
|
_VermilionCitySailor1ShipSetSailText = "The ship set sail.",
|
|
_VermilionCitySailor1WelcomeToSSAnneText = "Welcome to S.S.\nANNE!",
|
|
_SSAnneCaptainsRoomRubCaptainsBackText = "Rub-rub...",
|
|
_SSAnneCaptainsRoomCaptainIFeelMuchBetterText = "I feel better!",
|
|
_SSAnneCaptainsRoomCaptainReceivedHM01Text = "Got HM01!",
|
|
_SSAnneCaptainsRoomCaptainNotSickAnymoreText = "Not sick.",
|
|
},
|
|
},
|
|
stack = { push = function(_, box) pushed[#pushed + 1] = box end },
|
|
_pushed = pushed,
|
|
_moved = moved,
|
|
}
|
|
return game, pushed, moved
|
|
end
|
|
|
|
local function owWith(moved)
|
|
return {
|
|
player = { facing = "down", cellX = 14, cellY = 2 },
|
|
scriptMove = function(_, _, dir, n) moved[#moved + 1] = { dir, n } end,
|
|
queueScript = function(self, rows) self._queued = rows end,
|
|
startDustAnim = function() end,
|
|
map = {
|
|
setBlock = function() end,
|
|
renderer = { rebuild = function() end },
|
|
},
|
|
}
|
|
end
|
|
|
|
local city = story.VERMILION_CITY
|
|
check(city and city.onStep, "VERMILION_CITY has the sailor coord trigger")
|
|
|
|
-- With ticket, ship still docked: flash dialog, do NOT walk back.
|
|
do
|
|
local game, pushed, moved = gameWith({ inventory = { S_S_TICKET = 1 } })
|
|
local ow = owWith(moved)
|
|
check(city.onStep(game, ow, 18, 30), "ticket: walk-past trigger consumes the step")
|
|
check(#pushed == 1, "ticket: auto dialog is shown")
|
|
check(pushed[1].text:find("flashed", 1, true)
|
|
or pushed[1].text:find("ticket", 1, true),
|
|
"ticket: flash / ticket-check dialog text")
|
|
check(#moved == 0, "ticket: player is not walked back")
|
|
end
|
|
|
|
-- Without ticket: dialog + walk back.
|
|
do
|
|
local game, pushed, moved = gameWith({})
|
|
local ow = owWith(moved)
|
|
check(city.onStep(game, ow, 18, 30), "no ticket: trigger fires")
|
|
check(#pushed == 1, "no ticket: dialog shown")
|
|
if pushed[1] and pushed[1].done then pushed[1].done() end
|
|
check(#moved == 1 and moved[1][1] == "up",
|
|
"no ticket: walked back up after dialog")
|
|
end
|
|
|
|
-- After the ship leaves: ShipSetSail + walk back, even with a ticket.
|
|
do
|
|
local game, pushed, moved = gameWith({
|
|
inventory = { S_S_TICKET = 1 },
|
|
flags = { EVENT_SS_ANNE_LEFT = true },
|
|
})
|
|
local ow = owWith(moved)
|
|
check(city.onStep(game, ow, 18, 30), "ship left: trigger still fires")
|
|
eq(pushed[1] and pushed[1].text, "The ship set sail.",
|
|
"ship left: dialog updates to ShipSetSail")
|
|
if pushed[1] and pushed[1].done then pushed[1].done() end
|
|
check(#moved == 1 and moved[1][1] == "up",
|
|
"ship left: walked back up")
|
|
end
|
|
|
|
-- Off-tile / wrong facing: no trigger.
|
|
do
|
|
local game, pushed = gameWith({ inventory = { S_S_TICKET = 1 } })
|
|
local ow = owWith({})
|
|
eq(city.onStep(game, ow, 18, 29), false, "wrong Y: no trigger")
|
|
ow.player.facing = "up"
|
|
eq(city.onStep(game, ow, 18, 30), false, "facing up: no trigger")
|
|
check(#pushed == 0, "no spurious dialog off the check")
|
|
end
|
|
|
|
-- Sailor talk: once she has sailed he only reports it gone, and before
|
|
-- that an A press is the plain greeting, never the ticket check (#1651).
|
|
-- scripts/VermilionCity.asm:158-198
|
|
do
|
|
local talk = city.talk.TEXT_VERMILIONCITY_SAILOR1
|
|
local game, pushed = gameWith({ flags = { EVENT_SS_ANNE_LEFT = true } })
|
|
talk(game, owWith({}), nil, function() end)
|
|
eq(pushed[#pushed] and pushed[#pushed].text, "The ship set sail.",
|
|
"talk after ship left shows ShipSetSail")
|
|
|
|
game, pushed = gameWith({})
|
|
local ow = owWith({})
|
|
ow.player.cellX, ow.player.cellY, ow.player.facing = 18, 30, "right"
|
|
talk(game, ow, nil, function() end)
|
|
eq(pushed[#pushed] and pushed[#pushed].text, "Welcome to S.S.\nANNE!",
|
|
"facing him from the west is the plain greeting, no ticket check")
|
|
|
|
game, pushed = gameWith({})
|
|
ow = owWith({})
|
|
ow.player.cellX, ow.player.cellY, ow.player.facing = 19, 29, "down"
|
|
talk(game, ow, nil, function() end)
|
|
eq(pushed[#pushed] and pushed[#pushed].text, "Welcome to S.S.\nANNE!",
|
|
"talking from in front of him is the plain greeting too")
|
|
|
|
game, pushed = gameWith({})
|
|
ow = owWith({})
|
|
ow.player.cellX, ow.player.cellY, ow.player.facing = 19, 31, "up"
|
|
talk(game, ow, nil, function() end)
|
|
eq(pushed[#pushed] and pushed[#pushed].text, "Welcome to S.S.\nANNE!",
|
|
"and from behind him")
|
|
end
|
|
|
|
-- Departure cutscene: Music_Surfing + EVENT_SS_ANNE_LEFT via Flags.set.
|
|
do
|
|
for i = #musicCalls, 1, -1 do musicCalls[i] = nil end
|
|
local game, _, moved = gameWith({ flags = { EVENT_GOT_HM01 = true } })
|
|
local ow = owWith(moved)
|
|
story3.VERMILION_DOCK.onEnter(game, ow)
|
|
check(Flags.get(game.save, "EVENT_SS_ANNE_LEFT"),
|
|
"departure sets EVENT_SS_ANNE_LEFT")
|
|
local sawSurf = false
|
|
for _, c in ipairs(musicCalls) do
|
|
if c[1] == "play" and c[2] == "Music_Surfing" then sawSurf = true end
|
|
end
|
|
check(sawSurf, "departure plays Music_Surfing")
|
|
check(ow._queued ~= nil, "departure queues the sail-away script")
|
|
-- #360: the surf override must NOT ride into Vermilion City, and she
|
|
-- sails west block by block
|
|
local kept, horns, sails, shuffled, faced = false, 0, 0, 0, false
|
|
for _, row in ipairs(ow._queued or {}) do
|
|
if row[1] == "play_music" and row[3] and row[3].keep then kept = true end
|
|
if row[1] == "play_sound" and row[2] == "SS_Anne_Horn" then
|
|
horns = horns + 1
|
|
end
|
|
if row[1] == "ss_anne_departs" then sails = sails + 1 end
|
|
if row[1] == "replace_block" then shuffled = shuffled + 1 end
|
|
if row[1] == "face_player_dir" and row[2] == "down" then faced = true end
|
|
end
|
|
eq(kept, false, "departure lets VERMILION_CITY's own theme take the warp")
|
|
eq(horns, 2, "the horn blows before and after she sails")
|
|
eq(sails, 1, "she slides west as one animation, not a block shuffle")
|
|
eq(shuffled, 0, "and no hull block is stamped across the dock any more")
|
|
-- scripts/VermilionDock.asm:50 (#1689)
|
|
eq(faced, true, "he keeps facing down until he walks out")
|
|
end
|
|
|
|
-- Captain rub jingle: play_once Music_PkmnHealed sits after the rub text.
|
|
do
|
|
local rows = story.SS_ANNE_CAPTAINS_ROOM.talk.TEXT_SSANNECAPTAINSROOM_CAPTAIN
|
|
local found = false
|
|
for i, row in ipairs(rows) do
|
|
if row[1] == "play_once" and row[2] == "Music_PkmnHealed" then
|
|
found = true
|
|
check(rows[i - 1] and rows[i - 1][2] == "_SSAnneCaptainsRoomRubCaptainsBackText",
|
|
"play_once follows the rub-back text")
|
|
end
|
|
end
|
|
check(found, "captain script plays Music_PkmnHealed after the rub")
|
|
end
|
|
|
|
package.loaded["src.render.TextBox"] = realTextBox
|
|
package.loaded["src.core.Music"] = realMusic
|
|
package.loaded["src.core.Sound"] = realSound
|
|
package.loaded["src.script.Commands"] = realCommands
|
|
package.loaded["src.script.ScriptRunner"] = realScriptRunner
|
|
|
|
S.finish()
|