Files
gen1recomp/tests/drivers/em_event_islands.lua
T
bryanthaboi 690f0cd9a1 TOUCHDOWN
2026-09-27 16:07:31 -04:00

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