-- 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