mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-29 07:00:55 -04:00
242 lines
12 KiB
Lua
242 lines
12 KiB
Lua
local U = require("tests.drivers.util")
|
|
local S = require("tests.drivers.em_story_util")
|
|
|
|
return function(game)
|
|
local d = S.new("em_event_islands", "/tmp/em_event_islands")
|
|
local check, note = d.check, d.note
|
|
local function shot(name) d.shot(game, name) end
|
|
local function finish() return d.finish() end
|
|
|
|
for _ = 1, 900 do
|
|
if game.phase == "boot" and game.boot then break end
|
|
U.wait(1)
|
|
end
|
|
if not check(game.boot ~= nil, "boot reached") then return finish() end
|
|
|
|
local SaveData = require("src.core.SaveData")
|
|
local Schema = require("src.core.game3.save_schema_firered")
|
|
local raw = love.filesystem.read("saves/emerald/slot1.lua")
|
|
if not check(type(raw) == "string", "identity has the post-Hall-of-Fame save") then return finish() end
|
|
local session = Schema.fromSaveTable(SaveData.decode(raw))
|
|
require("src.core.game3.options").bind(session, game.options)
|
|
game:adoptSave(session, true)
|
|
game.sessionStartedAt = os.time()
|
|
game:_enterField(session, "continue")
|
|
U.wait(30)
|
|
S.settle(game)
|
|
|
|
local Runtime = require("src.core.game3.runtime")
|
|
local Map = require("src.core.game3.map")
|
|
local Natives = require("src.core.game3.scripting.natives")
|
|
local Objects = require("src.core.game3.objects")
|
|
local Player = require("src.core.game3.player")
|
|
session = Runtime.getSession()
|
|
Natives.ensureBound(session)
|
|
require("tests.drivers.em_f4_hooks").install()
|
|
local EI = require("src.core.game3.rse.event_islands")
|
|
check(Natives.handlerFor("DoDeoxysRockInteraction") ~= nil and Natives.handlerFor("SetDeoxysRockPalette") ~= nil,
|
|
"DoDeoxysRockInteraction / SetDeoxysRockPalette bound on Emerald")
|
|
session.repelSteps = 0
|
|
require("src.core.game3.encounters").onStep = function() return nil end
|
|
|
|
local D = require("src.core.game3.rse.frontier.trainers")
|
|
local function tough(name, moves)
|
|
local m = D.createMon(S.species(name), 70, 31, 0, tonumber(session.trainerId) or 0, { otName = session.name })
|
|
local ms = {}
|
|
for i, mv in ipairs(moves) do ms[i] = S.move(mv) end
|
|
D.setMoves(m, ms)
|
|
D.setEvs(m, { 252, 252, 6, 0, 0, 0 })
|
|
m.otId, m.otName, m.ot = session.trainerId, session.name, session.name
|
|
return m
|
|
end
|
|
session.party = {
|
|
tough("SPECIES_METAGROSS", { "MOVE_METEOR_MASH", "MOVE_EARTHQUAKE", "MOVE_PSYCHIC", "MOVE_SHADOW_BALL" }),
|
|
tough("SPECIES_SALAMENCE", { "MOVE_DRAGON_CLAW", "MOVE_EARTHQUAKE", "MOVE_FLAMETHROWER", "MOVE_AERIAL_ACE" }),
|
|
tough("SPECIES_SWAMPERT", { "MOVE_SURF", "MOVE_EARTHQUAKE", "MOVE_ICE_BEAM", "MOVE_BRICK_BREAK" }),
|
|
}
|
|
|
|
local function teleport(mapId, x, y, facing)
|
|
S.settle(game)
|
|
local ok, err = pcall(function() Map.load(nil, game, mapId, { x = x, y = y, facing = facing }) end)
|
|
if not ok then note("Map.load " .. mapId .. ": " .. tostring(err)) end
|
|
local s = Runtime.getSession()
|
|
if s then s.x, s.y, s.facing = x, y, facing end
|
|
U.wait(30)
|
|
S.settle(game)
|
|
return ok
|
|
end
|
|
|
|
check(not EI.enabled(session), "event tickets start OFF")
|
|
local row = EI.optionRow()
|
|
row.step({ options = game.options, session = session })
|
|
check(EI.enabled(session), "the EVENT TICKETS option row turns the distribution on")
|
|
check(S.var("VAR_DISTRIBUTE_EON_TICKET") == 1, "VAR_DISTRIBUTE_EON_TICKET raised for the Mystery Gift man")
|
|
|
|
if not check(teleport("EM_LILYCOVE_CITY_POKEMON_CENTER_2F", 1, 6, "up"), "Lilycove Pokemon Center 2F loads") then
|
|
return finish()
|
|
end
|
|
local man = S.objectByScript("CableClub_EventScript_MysteryGiftMan")
|
|
if not check(man ~= nil and not man.hidden, "the Mystery Gift man stands in the 2F (CableClub_OnTransition)") then
|
|
return finish()
|
|
end
|
|
shot("01_mystery_gift_man")
|
|
local tickets = { "ITEM_EON_TICKET", "ITEM_AURORA_TICKET", "ITEM_MYSTIC_TICKET", "ITEM_OLD_SEA_MAP" }
|
|
for i, t in ipairs(tickets) do
|
|
man = S.objectByScript("CableClub_EventScript_MysteryGiftMan")
|
|
S.goTo(game, { man.cellX, man.cellY + 2 })
|
|
S.face(game, "up")
|
|
U.tap(game, "a")
|
|
U.wait(10)
|
|
local shotTaken = false
|
|
S.settle(game, { limit = 4000, watch = function()
|
|
if i == 2 and not shotTaken and require("src.ui.game3.message").isOpen() then
|
|
shotTaken = true
|
|
U.wait(20)
|
|
shot("02_wonder_card_ticket")
|
|
end
|
|
end })
|
|
check(S.hasItem(t), "talk " .. i .. " delivers " .. t)
|
|
end
|
|
check(S.flag("FLAG_ENABLE_SHIP_SOUTHERN_ISLAND") and S.flag("FLAG_ENABLE_SHIP_BIRTH_ISLAND")
|
|
and S.flag("FLAG_ENABLE_SHIP_NAVEL_ROCK") and S.flag("FLAG_ENABLE_SHIP_FARAWAY_ISLAND"),
|
|
"all four FLAG_ENABLE_SHIP_* flags set by the ticket scripts")
|
|
check(EI.pendingGift(session) == nil, "no wonder card left to deliver")
|
|
|
|
local function ferryOnce(dest, arrive)
|
|
teleport("EM_LILYCOVE_CITY_HARBOR", 8, 12, "up")
|
|
local attendant = S.objectByScript("LilycoveCity_Harbor_EventScript_FerryAttendant")
|
|
if not attendant then return false end
|
|
S.talkTo(game, attendant)
|
|
local listed = false
|
|
S.settle(game, { limit = 20000, until_ = function() return S.mapNow() == arrive end,
|
|
choice = function(ch)
|
|
local labels = {}
|
|
for _, o in ipairs(ch.options or {}) do labels[#labels + 1] = tostring(type(o) == "table" and (o.text or o.label or o[1]) or o) end
|
|
note("ferry choice: " .. table.concat(labels, " | "))
|
|
for idx, o in ipairs(ch.options or {}) do
|
|
local t = tostring(type(o) == "table" and (o.text or o.label or o[1]) or o)
|
|
if t:upper():find(dest, 1, true) then
|
|
listed = true
|
|
return idx
|
|
end
|
|
end
|
|
return "yes"
|
|
end })
|
|
note("ferry to " .. dest .. ": listed=" .. tostring(listed) .. " map=" .. tostring(S.mapNow()))
|
|
return listed and S.mapNow() == arrive
|
|
end
|
|
local function ferry(dest, arrive)
|
|
for _ = 1, 3 do
|
|
if ferryOnce(dest, arrive) then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
if check(ferry("SOUTHERN", "EM_SOUTHERN_ISLAND_EXTERIOR"), "the S.S. Tidal sails to SOUTHERN ISLAND with the EON TICKET") then
|
|
shot("03_southern_island")
|
|
S.travel(game, { "EM_SOUTHERN_ISLAND_INTERIOR" }, { repel = false, settle = { limit = 4000 } })
|
|
if check(S.mapNow() == "EM_SOUTHERN_ISLAND_INTERIOR", "walked into the Southern Island interior") then
|
|
S.goTo(game, { 13, 12 })
|
|
S.face(game, "up")
|
|
U.tap(game, "a")
|
|
local sawBattle = false
|
|
S.settle(game, { limit = 20000, onBattleStart = function(st)
|
|
sawBattle = true
|
|
local foe = st.enemy and st.enemy.mon
|
|
check(foe and (foe.species == S.species("SPECIES_LATIAS") or foe.species == S.species("SPECIES_LATIOS")),
|
|
"the Lati at the rock is Latias or Latios (" .. tostring(foe and foe.species) .. ")")
|
|
S.pendingBattleShot = "04_lati_battle"
|
|
end })
|
|
check(sawBattle, "BattleSetup_StartLatiBattle starts the Lati battle")
|
|
check(S.flag("FLAG_DEFEATED_LATIAS_OR_LATIOS") or S.flag("FLAG_CAUGHT_LATIAS_OR_LATIOS"),
|
|
"the Southern Island Lati is resolved")
|
|
end
|
|
end
|
|
|
|
if check(ferry("BIRTH", "EM_BIRTH_ISLAND_HARBOR"), "the S.S. Tidal sails to BIRTH ISLAND with the AURORA TICKET") then
|
|
S.travel(game, { "EM_BIRTH_ISLAND_EXTERIOR" }, { repel = false, settle = { limit = 4000 } })
|
|
if check(S.mapNow() == "EM_BIRTH_ISLAND_EXTERIOR", "walked onto Birth Island") then
|
|
shot("05_birth_island")
|
|
local moves, sawDeoxys = 0, false
|
|
local lastResult
|
|
local coords = EI.manifest().deoxysRockCoords
|
|
for touch = 1, 13 do
|
|
local rock = Objects.find(EI.LOCALID_ROCK)
|
|
if not rock or rock.hidden then break end
|
|
local level = S.var("VAR_DEOXYS_ROCK_LEVEL")
|
|
local nxt = coords[math.min(level + 2, #coords)]
|
|
local best, bestCost
|
|
for _, dlt in ipairs({ { 0, 1, "up" }, { 0, -1, "down" }, { 1, 0, "left" }, { -1, 0, "right" } }) do
|
|
local tx, ty = rock.cellX + dlt[1], rock.cellY + dlt[2]
|
|
local cost = (math.abs(tx - Player.cellX) + math.abs(ty - Player.cellY)) * 100 + math.abs(tx - nxt[1]) + math.abs(ty - nxt[2])
|
|
if not bestCost or cost < bestCost then best, bestCost = { tx, ty, dlt[3] }, cost end
|
|
end
|
|
S.goTo(game, { best[1], best[2] })
|
|
S.face(game, best[3])
|
|
U.tap(game, "a")
|
|
U.wait(10)
|
|
S.settle(game, { limit = 20000, onBattleStart = function(st)
|
|
sawDeoxys = true
|
|
local foe = st.enemy and st.enemy.mon
|
|
check(foe and foe.species == S.species("SPECIES_DEOXYS"), "the triangle summons Deoxys")
|
|
S.pendingBattleShot = "07_deoxys_battle"
|
|
end })
|
|
lastResult = require("src.core.game3.scripting.natives_event_islands").lastResult
|
|
if lastResult == EI.ROCK.PROGRESSED then moves = moves + 1 end
|
|
note(string.format("touch %d result %s level %d rock %d,%d player %d,%d steps %d", touch, tostring(lastResult),
|
|
S.var("VAR_DEOXYS_ROCK_LEVEL"), rock.cellX, rock.cellY, Player.cellX, Player.cellY, S.var("VAR_DEOXYS_ROCK_STEP_COUNT")))
|
|
require("src.core.game3.scripting.natives_event_islands").lastResult = nil
|
|
if touch == 4 then shot("06_triangle_level_" .. S.var("VAR_DEOXYS_ROCK_LEVEL")) end
|
|
if sawDeoxys then break end
|
|
end
|
|
check(moves == 10, "the triangle moved ten times (" .. moves .. ")")
|
|
check(sawDeoxys, "solving the triangle starts the Deoxys battle")
|
|
check(S.flag("FLAG_BATTLED_DEOXYS") or S.flag("FLAG_DEFEATED_DEOXYS"), "Deoxys resolved")
|
|
end
|
|
end
|
|
|
|
if check(ferry("NAVEL", "EM_NAVEL_ROCK_HARBOR"), "the S.S. Tidal sails to NAVEL ROCK with the MYSTIC TICKET") then
|
|
shot("08_navel_rock")
|
|
teleport("EM_NAVEL_ROCK_TOP", 13, 19, "up")
|
|
local sawHoOh = false
|
|
S.goTo(game, { 12, 11 })
|
|
S.step(game, "up")
|
|
S.settle(game, { limit = 20000, onBattleStart = function(st)
|
|
local foe = st.enemy and st.enemy.mon
|
|
sawHoOh = foe and foe.species == S.species("SPECIES_HO_OH")
|
|
S.pendingBattleShot = "09_ho_oh_battle"
|
|
end })
|
|
check(sawHoOh, "the Navel Rock summit coord event starts the Ho-Oh battle")
|
|
teleport("EM_NAVEL_ROCK_BOTTOM", 14, 18, "up")
|
|
note("after bottom teleport: map " .. tostring(S.mapNow()) .. " player " .. Player.cellX .. "," .. Player.cellY)
|
|
local lugia = S.objectByScript("NavelRock_Bottom_EventScript_Lugia") or Objects.find(1)
|
|
local sawLugia = false
|
|
note("lugia " .. tostring(lugia and lugia.cellX) .. "," .. tostring(lugia and lugia.cellY) .. " hidden=" .. tostring(lugia and lugia.hidden))
|
|
if lugia then
|
|
teleport("EM_NAVEL_ROCK_BOTTOM", lugia.cellX, lugia.cellY + 1, "up")
|
|
lugia = S.objectByScript("NavelRock_Bottom_EventScript_Lugia") or Objects.find(1)
|
|
S.face(game, "up")
|
|
note("at lugia: map " .. tostring(S.mapNow()) .. " player " .. Player.cellX .. "," .. Player.cellY .. " facing " .. tostring(Player.facing))
|
|
U.tap(game, "a")
|
|
U.wait(10)
|
|
S.settle(game, { limit = 20000, onBattleStart = function(st)
|
|
local foe = st.enemy and st.enemy.mon
|
|
sawLugia = foe and foe.species == S.species("SPECIES_LUGIA")
|
|
S.pendingBattleShot = "10_lugia_battle"
|
|
end })
|
|
end
|
|
check(sawLugia, "Lugia waits at the bottom of Navel Rock")
|
|
end
|
|
|
|
if check(ferry("FARAWAY", "EM_FARAWAY_ISLAND_ENTRANCE"), "the S.S. Tidal sails to FARAWAY ISLAND with the OLD SEA MAP") then
|
|
S.travel(game, { "EM_FARAWAY_ISLAND_INTERIOR" }, { repel = false, settle = { limit = 4000 } })
|
|
check(S.mapNow() == "EM_FARAWAY_ISLAND_INTERIOR", "walked into Faraway Island")
|
|
local mew = S.objectByScript("FarawayIsland_Interior_EventScript_Mew") or Objects.find(1)
|
|
check(mew ~= nil, "Mew is on Faraway Island")
|
|
shot("11_faraway_island")
|
|
end
|
|
|
|
note("player at " .. tostring(S.mapNow()) .. " " .. Player.cellX .. "," .. Player.cellY)
|
|
finish()
|
|
end
|