mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
107 lines
4.5 KiB
Lua
107 lines
4.5 KiB
Lua
-- MahoganyMart1FLanceUncoversStaircaseScript (maps/MahoganyMart1F.asm:63), the
|
|
-- scene where Lance's DRAGONITE hyper-beams the Rocket behind the counter.
|
|
--
|
|
-- POKEPORT_GAME=gold POKEPORT_DRIVER=tests/drivers/gold_mahogany_lance.lua love .
|
|
--
|
|
-- MAHOGANYMART1F_LANCE and MAHOGANYMART1F_DRAGONITE share ONE
|
|
-- MAPOBJECT_EVENT_FLAG (maps/MahoganyMart1F.asm:158-159), and the script
|
|
-- `disappear`s the DRAGONITE less than half way through and Lance only at the
|
|
-- very end -- so a port that derives who is standing from the event flag pulls
|
|
-- Lance off the map the moment his Dragonite goes, and the rest of his walk and
|
|
-- all three of his text boxes then come out of nobody.
|
|
--
|
|
-- The run prints the standing census every beat and shoots the two moments a
|
|
-- human has to look at: Lance mid-speech (he must be ON SCREEN) and the room
|
|
-- after he takes the stairs (he must be GONE, and an A press where he stood
|
|
-- must do nothing).
|
|
local U = require("tests.drivers.util")
|
|
|
|
local LANCE, DRAGONITE = 3, 4 -- def.objects indices; object consts are +1
|
|
|
|
return function(game)
|
|
local out = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/gold-mahogany"
|
|
|
|
local function tap(button, frames)
|
|
game.input.pressQueue[#game.input.pressQueue + 1] = button
|
|
game.input.state[button] = true
|
|
U.wait(2)
|
|
game.input.state[button] = false
|
|
U.wait(frames or 4)
|
|
end
|
|
|
|
local world
|
|
local function standing(index)
|
|
for _, npc in ipairs(world.npcs) do
|
|
if npc.def and npc.def.index == index then return npc end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
U.wait(45)
|
|
world = game.world
|
|
assert(world and world.map, "gold world did not boot")
|
|
|
|
-- LakeOfRage.asm:61 `clearevent EVENT_MAHOGANY_MART_LANCE_AND_DRAGONITE` is
|
|
-- what puts the pair in the shop; both objects carry that ONE flag
|
|
-- (maps/MahoganyMart1F.asm:236-237). Read it off the object rather than
|
|
-- naming a number, so a re-extracted cache cannot make this stale.
|
|
world:setMap("MAHOGANY_MART_1F", 3, 6, "up")
|
|
U.wait(5)
|
|
world.events:set(world.map.def.objects[LANCE].eventFlag, false)
|
|
-- SCENE_MAHOGANYMART1F_LANCE_UNCOVERS_STAIRS is scene 1; the scene script is
|
|
-- `sdefer`, and World:step only arms it on a map ENTRY, so the id has to be
|
|
-- in place before the load that runs it.
|
|
world.mapScenes["MAHOGANY_MART_1F"] = 1
|
|
world:setMap("MAHOGANY_MART_1F", 3, 6, "up")
|
|
U.wait(20)
|
|
assert(world.map.id == "MAHOGANY_MART_1F", tostring(world.map.id))
|
|
assert(standing(LANCE), "Lance is not on the map before the scene")
|
|
assert(standing(DRAGONITE), "the Dragonite is not on the map before the scene")
|
|
|
|
U.shot(game, out .. "/00-before.png")
|
|
|
|
local lanceGoneAt, dragoniteGoneAt, shotMidway = nil, nil, false
|
|
for step = 1, 900 do
|
|
if not world:busy() and step > 30 then break end
|
|
local lance, drag = standing(LANCE), standing(DRAGONITE)
|
|
if not drag and not dragoniteGoneAt then dragoniteGoneAt = step end
|
|
if not lance and not lanceGoneAt then lanceGoneAt = step end
|
|
-- The Dragonite is gone and Lance is still talking: this is the frame the
|
|
-- shared flag would have culled him on.
|
|
if dragoniteGoneAt and not shotMidway and step == dragoniteGoneAt + 30 then
|
|
shotMidway = true
|
|
U.shot(game, out .. "/01-after-hyper-beam.png")
|
|
print(("[driver] after the Dragonite went: Lance standing = %s")
|
|
:format(tostring(standing(LANCE) ~= nil)))
|
|
end
|
|
tap("a", 2)
|
|
end
|
|
|
|
print(("[driver] Dragonite left the map at beat %s, Lance at beat %s")
|
|
:format(tostring(dragoniteGoneAt), tostring(lanceGoneAt)))
|
|
U.wait(20)
|
|
U.shot(game, out .. "/02-after.png")
|
|
|
|
assert(dragoniteGoneAt, "the Dragonite never disappeared")
|
|
assert(lanceGoneAt, "Lance never disappeared")
|
|
assert(lanceGoneAt > dragoniteGoneAt + 20,
|
|
("Lance left the map %d beats after his Dragonite; the script keeps him "
|
|
.. "standing for the whole walk, the radio speech, the stairs and the "
|
|
.. "split-up line"):format(lanceGoneAt - dragoniteGoneAt))
|
|
|
|
-- The other half: a masked object must not answer an A press. Stand where
|
|
-- Lance ended up and face him.
|
|
local def = world.map.def.objects[LANCE]
|
|
world.player.cellX, world.player.cellY = def.x, def.y + 1
|
|
world.player.px = world.player.cellX * 16
|
|
world.player.py = world.player.cellY * 16
|
|
world.player.facing = "up"
|
|
U.wait(4)
|
|
local answered = world:interact()
|
|
print("[driver] A press on the masked Lance answered: " .. tostring(answered))
|
|
assert(not answered, "a masked object answered a talk")
|
|
|
|
print("[driver] PASS gold mahogany Lance scene in " .. out)
|
|
love.event.quit()
|
|
end
|