mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 00:10:56 +02:00
3069b2e2a9
* new launcher and save converts and pipeline * fixing bugs
204 lines
7.0 KiB
Lua
204 lines
7.0 KiB
Lua
-- Driver: #154 Route 22 rival exit direction + #168 Cerulean Bill text
|
|
-- and southbound walk-off.
|
|
--
|
|
-- SHOT_DIR=/tmp/rival_walkoff POKEPORT_SPEED=8 \
|
|
-- POKEPORT_DRIVER=tests/drivers/rival_walkoff_test.lua love .
|
|
|
|
return function(game)
|
|
local U = dofile("tests/drivers/util.lua")
|
|
local DIR = os.getenv("SHOT_DIR") or "/tmp/rival_walkoff"
|
|
os.execute("mkdir -p " .. DIR)
|
|
|
|
local Pokemon = require("src.pokemon.Pokemon")
|
|
local Flags = require("src.script.Flags")
|
|
local Zoom = require("src.render.Zoom")
|
|
if game.save.options then game.save.options.zoom = 0 end
|
|
Zoom.reset()
|
|
|
|
local function tank()
|
|
local mon = Pokemon.new(game.data, "MEWTWO", 100)
|
|
mon.moves = {
|
|
{ id = "PSYCHIC_M", pp = 99 },
|
|
{ id = "THUNDERBOLT", pp = 99 },
|
|
{ id = "ICE_BEAM", pp = 99 },
|
|
{ id = "RECOVER", pp = 99 },
|
|
}
|
|
return mon
|
|
end
|
|
|
|
game.save.party = { tank() }
|
|
game.save.player = game.save.player or {}
|
|
game.save.player.name = "RED"
|
|
game.save.player.rival = "BLUE"
|
|
Flags.set(game.save, "EVENT_CHOSE_SQUIRTLE")
|
|
|
|
local function idle(ow)
|
|
return game.stack:top() == ow and not ow.runner:isRunning()
|
|
and #ow.scriptMoves == 0 and not ow.transitioning
|
|
end
|
|
|
|
local function mashUntil(cond, label, cap)
|
|
for _ = 1, cap or 800 do
|
|
if cond() then return true end
|
|
if game.stack:top() ~= game.overworld then U.tap(game, "a") end
|
|
U.wait(2)
|
|
end
|
|
U.log("TIMEOUT waiting for " .. label)
|
|
return false
|
|
end
|
|
|
|
local function rivalNpc()
|
|
local ow = game.overworld
|
|
for _, npc in ipairs(ow.npcs or {}) do
|
|
if npc.def and npc.def.name and npc.def.name:find("RIVAL") then
|
|
return npc
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Fight until the battle state leaves the stack. Do NOT mash the
|
|
-- post-battle script text -- the caller screenshots that.
|
|
local function winBattle(label)
|
|
local ow = game.overworld
|
|
local sawBattle = false
|
|
for frames = 1, 5000 do
|
|
local top = game.stack:top()
|
|
if top and top.phase then
|
|
sawBattle = true
|
|
if top.phase == "menu" then
|
|
top.menuIndex = 1
|
|
elseif top.phase == "moveSelect" then
|
|
top.moveIndex = 1
|
|
end
|
|
U.tap(game, "a")
|
|
if frames > 2400 and top.onFinish then
|
|
U.log("force-finishing stalled", label)
|
|
top.onFinish("win")
|
|
if game.stack:top() == top then game.stack:pop() end
|
|
end
|
|
elseif sawBattle then
|
|
-- battle popped: either a TextBox or the overworld runner
|
|
return true
|
|
elseif top ~= ow then
|
|
U.tap(game, "a") -- pre-battle dialogue
|
|
end
|
|
U.wait(2)
|
|
end
|
|
U.log("TIMEOUT winBattle", label)
|
|
return false
|
|
end
|
|
|
|
-- ---------------------------------------------------------- #154
|
|
-- Route 22 optional post-lab rival: after the fight he must walk
|
|
-- toward Viridian (right / down), not back toward the League.
|
|
Flags.set(game.save, "EVENT_GOT_POKEDEX")
|
|
Flags.clear(game.save, "EVENT_BEAT_BROCK")
|
|
Flags.clear(game.save, "EVENT_BEAT_ROUTE22_RIVAL_1ST_BATTLE")
|
|
Flags.clear(game.save, "EVENT_BEAT_GIOVANNI")
|
|
Flags.clear(game.save, "EVENT_BEAT_ROUTE22_RIVAL_2ND_BATTLE")
|
|
|
|
U.teleport(game, "ROUTE_22", 30, 5, "left")
|
|
local ow = game.overworld
|
|
U.shot(game, DIR .. "/r22_0_before.png")
|
|
U.hold(game, "left", 20)
|
|
|
|
mashUntil(function()
|
|
return ow.runner:isRunning() or game.stack:top() ~= ow
|
|
end, "route22 ambush", 200)
|
|
U.shot(game, DIR .. "/r22_1_ambush.png")
|
|
mashUntil(function() return game.stack:top() ~= ow end, "route22 battle", 800)
|
|
winBattle("route22")
|
|
|
|
local sawExit, exitFacing, exitX, exitY = false, nil, nil, nil
|
|
for _ = 1, 600 do
|
|
if game.stack:top() ~= ow then U.tap(game, "a") end
|
|
local r = rivalNpc()
|
|
if r and game.save.flags.EVENT_BEAT_ROUTE22_RIVAL_1ST_BATTLE then
|
|
if (r.facing == "right" or r.facing == "down" or r.cellX > 28)
|
|
and not sawExit then
|
|
sawExit = true
|
|
exitFacing, exitX, exitY = r.facing, r.cellX, r.cellY
|
|
U.shot(game, DIR .. "/r22_2_exit.png")
|
|
U.log("r22 exit:", exitFacing, exitX, exitY)
|
|
elseif sawExit and (r.facing == "down" or r.cellY > 5) then
|
|
U.shot(game, DIR .. "/r22_3_exit_mid.png")
|
|
U.log("r22 exit mid:", r.facing, r.cellX, r.cellY)
|
|
break
|
|
end
|
|
end
|
|
if idle(ow) and game.save.flags.EVENT_BEAT_ROUTE22_RIVAL_1ST_BATTLE then
|
|
break
|
|
end
|
|
U.wait(2)
|
|
end
|
|
mashUntil(function() return idle(ow) end, "route22 done", 800)
|
|
U.shot(game, DIR .. "/r22_4_done.png")
|
|
U.log("r22 beat:", tostring(game.save.flags.EVENT_BEAT_ROUTE22_RIVAL_1ST_BATTLE),
|
|
"exitFacing:", tostring(exitFacing))
|
|
|
|
-- ---------------------------------------------------------- #168
|
|
-- Nugget Bridge: Bill dialogue, then walk into Cerulean (south).
|
|
Flags.clear(game.save, "EVENT_BEAT_CERULEAN_RIVAL")
|
|
game.save.party = { tank() }
|
|
|
|
U.teleport(game, "CERULEAN_CITY", 20, 7, "up")
|
|
ow = game.overworld
|
|
U.shot(game, DIR .. "/cer_0_before.png")
|
|
U.hold(game, "up", 20)
|
|
|
|
mashUntil(function()
|
|
return ow.runner:isRunning() or game.stack:top() ~= ow
|
|
end, "cerulean ambush", 200)
|
|
U.shot(game, DIR .. "/cer_1_ambush.png")
|
|
mashUntil(function() return game.stack:top() ~= ow end, "cerulean battle", 800)
|
|
winBattle("cerulean")
|
|
|
|
local function boxText(top)
|
|
if not top or type(top.pages) ~= "table" then return "" end
|
|
local parts = {}
|
|
for _, page in ipairs(top.pages) do
|
|
if type(page) == "table" then
|
|
for _, line in ipairs(page) do parts[#parts + 1] = tostring(line) end
|
|
end
|
|
end
|
|
return table.concat(parts, " ")
|
|
end
|
|
|
|
local billShot, exitShot, lastBox, postBoxes = false, false, nil, 0
|
|
for _ = 1, 2000 do
|
|
local top = game.stack:top()
|
|
if top ~= ow then
|
|
local t = boxText(top)
|
|
if game.save.flags.EVENT_BEAT_CERULEAN_RIVAL and t ~= "" and top ~= lastBox then
|
|
lastBox = top
|
|
postBoxes = postBoxes + 1
|
|
U.log("post-battle box", postBoxes, t:sub(1, 80))
|
|
-- Bill line is the second post-flag text (after DefeatedText)
|
|
if not billShot and (t:find("BILL") or t:find("Storage")
|
|
or t:find("invented") or t:find("MANIAC") or t:find("pages")
|
|
or t:find("guess what") or postBoxes >= 2) then
|
|
billShot = true
|
|
for _ = 1, 30 do U.wait(2); U.tap(game, "a") end -- advance into Bill body
|
|
U.wait(20)
|
|
U.shot(game, DIR .. "/cer_2_bill.png")
|
|
U.log("bill text:", boxText(game.stack:top()):sub(1, 160))
|
|
end
|
|
end
|
|
U.tap(game, "a")
|
|
elseif game.save.flags.EVENT_BEAT_CERULEAN_RIVAL then
|
|
local r = rivalNpc()
|
|
if r and r.cellY and r.cellY >= 6 and r.facing == "down" and not exitShot then
|
|
exitShot = true
|
|
U.shot(game, DIR .. "/cer_3_exit.png")
|
|
U.log("cer exit:", r.facing, r.cellX, r.cellY)
|
|
end
|
|
if idle(ow) then break end
|
|
end
|
|
U.wait(2)
|
|
end
|
|
mashUntil(function() return idle(ow) end, "cerulean done", 800)
|
|
U.shot(game, DIR .. "/cer_4_done.png")
|
|
U.log("cer beat:", tostring(game.save.flags.EVENT_BEAT_CERULEAN_RIVAL),
|
|
"billShot:", tostring(billShot), "exitShot:", tostring(exitShot))
|
|
end
|