mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-28 23:00:21 -04:00
281 lines
10 KiB
Lua
281 lines
10 KiB
Lua
local U = require("tests.drivers.util")
|
|
local L = require("tests.drivers.em_battle_loop")
|
|
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/em_wild_encounters"
|
|
|
|
local failures = 0
|
|
local function check(ok, label)
|
|
print((ok and "PASS " or "FAIL ") .. label)
|
|
if not ok then failures = failures + 1 end
|
|
return ok
|
|
end
|
|
|
|
local function finish()
|
|
print((failures == 0 and "PASS" or "FAIL") .. " em_wild_encounters failures=" .. failures)
|
|
love.event.quit(failures == 0 and 0 or 1)
|
|
end
|
|
|
|
return function(game)
|
|
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
|
|
game:_handleBootAction({ action = "new_game", name = "BRENDAN", gender = 0 })
|
|
U.wait(60)
|
|
|
|
local Runtime = require("src.core.game3.runtime")
|
|
local Map = require("src.core.game3.map")
|
|
local Player = require("src.core.game3.player")
|
|
local Warp = require("src.core.game3.warp")
|
|
local Message = require("src.ui.game3.message")
|
|
local Choice = require("src.ui.game3.choice")
|
|
local Party = require("src.core.game3.party")
|
|
local Space = require("src.core.game3.scripting.space")
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
local Collision = require("src.core.game3.collision")
|
|
local Objects = require("src.core.game3.objects")
|
|
local Field = require("src.core.game3.field")
|
|
local FieldMoves = require("src.core.game3.field_moves")
|
|
local Encounters = require("src.core.game3.encounters")
|
|
local Battle = require("src.core.game3.battle")
|
|
local Bag = require("src.core.game3.bag")
|
|
local MB = require("src.core.game3.mb")
|
|
local C = require("src.core.game3.constants").of("emerald")
|
|
local session = Runtime.getSession()
|
|
if not check(session ~= nil, "field session exists") then return finish() end
|
|
local IDS = Flags.forVersion("emerald").IDS
|
|
local function mv(n) return C.moves.byName["MOVE_" .. n] end
|
|
local function sp(n) return C.species.byName["SPECIES_" .. n] end
|
|
local function item(n) return C.items.byName["ITEM_" .. n] end
|
|
|
|
session.party = {}
|
|
Party.giveMon(session, sp("SWAMPERT"), 100, "SWAMPERT")
|
|
session.party[1].moves = { mv("SURF"), mv("ROCK_SMASH"), mv("STRENGTH"), mv("EARTHQUAKE") }
|
|
for i = 1, 8 do Flags.setFlag(Space.store, nil, IDS[string.format("FLAG_BADGE0%d_GET", i)], true) end
|
|
Bag.add(session.bag, item("OLD_ROD"), 1)
|
|
|
|
local function idle()
|
|
return not (Space.vm and Space.vm:isRunning()) and not Message.isOpen() and not Field.locked
|
|
and not Warp.isBusy() and not (Choice.isOpen and Choice.isOpen())
|
|
and not require("src.core.game3.field_move_show_mon").isActive() and not Battle.isActive()
|
|
end
|
|
|
|
local function pump(pred, frames)
|
|
for _ = 1, frames or 600 do
|
|
if pred() then return true end
|
|
if Battle.isActive() then return pred() end
|
|
if (Choice.isOpen and Choice.isOpen()) or Message._choice then
|
|
U.tap(game, "a")
|
|
elseif Message.isOpen and Message.isOpen() then
|
|
U.tap(game, "a")
|
|
U.wait(3)
|
|
else
|
|
U.wait(1)
|
|
end
|
|
end
|
|
return pred()
|
|
end
|
|
|
|
local function place(mapId, x, y, facing, surfing)
|
|
for _ = 1, 300 do if idle() then break end U.wait(1) end
|
|
Map.load(nil, game, mapId, { x = x, y = y, facing = facing })
|
|
local s = Runtime.getSession()
|
|
s.x, s.y, s.facing = x, y, facing
|
|
Player.surfing = surfing == true
|
|
Field.unlock()
|
|
U.wait(20)
|
|
end
|
|
|
|
local function size()
|
|
local layout = Collision._mapDef and Collision._mapDef.midLayout
|
|
return layout and layout.width or 0, layout and layout.height or 0
|
|
end
|
|
|
|
local function inTable(mapId, kind, species)
|
|
local t = Encounters.tableFor(mapId)
|
|
local area = t and t[kind]
|
|
for _, s in ipairs(area and area.slots or {}) do
|
|
if tonumber(s.species) == tonumber(species) then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function enemySpecies()
|
|
local st = Battle._st
|
|
local mon = st and st.enemy and st.enemy.mon
|
|
return mon and tonumber(mon.species)
|
|
end
|
|
|
|
local function winBattle()
|
|
for _ = 1, 600 do if Battle._phase == "command" or not Battle.isActive() then break end U.wait(2) end
|
|
L.run(game, { turnCap = 20 })
|
|
for _ = 1, 900 do
|
|
if not Battle.isActive() and idle() then return true end
|
|
if Message.isOpen() then U.tap(game, "a") end
|
|
U.wait(2)
|
|
end
|
|
return not Battle.isActive()
|
|
end
|
|
|
|
local function walkUntilBattle(a, b, steps)
|
|
for i = 1, steps do
|
|
U.hold(game, (i % 2 == 1) and a or b, 12)
|
|
for _ = 1, 20 do
|
|
if Battle.isActive() then return true end
|
|
U.wait(1)
|
|
end
|
|
end
|
|
return Battle.isActive()
|
|
end
|
|
|
|
-- pokeemerald/src/wild_encounter.c:552
|
|
place("EM_ROUTE101", 10, 10, "down")
|
|
local gx, gy
|
|
local w, h = size()
|
|
for y = 1, h - 2 do
|
|
for x = 1, w - 2 do
|
|
if not gx and Collision.behavior(x, y) == MB.id("TALL_GRASS") and Collision.behavior(x + 1, y) == MB.id("TALL_GRASS")
|
|
and Collision.isWalkable(x, y) and Collision.isWalkable(x + 1, y) then
|
|
gx, gy = x, y
|
|
end
|
|
end
|
|
end
|
|
check(gx ~= nil, "Route 101 has a pair of tall grass cells (" .. tostring(gx) .. "," .. tostring(gy) .. ")")
|
|
if gx then
|
|
place("EM_ROUTE101", gx, gy, "right")
|
|
local got = walkUntilBattle("right", "left", 200)
|
|
check(got, "walking in Route 101 grass starts a wild battle")
|
|
if got then
|
|
U.wait(90)
|
|
U.shot(game, DIR .. "/01_grass_battle.png")
|
|
local s = enemySpecies()
|
|
check(s and inTable("EM_ROUTE101", "land", s), "the grass mon comes from the Route 101 land table (" .. tostring(s) .. ")")
|
|
check(winBattle(), "the grass battle ends")
|
|
end
|
|
end
|
|
|
|
-- pokeemerald/src/wild_encounter.c:599
|
|
place("EM_ROUTE103", 10, 10, "down")
|
|
local sx, sy
|
|
w, h = size()
|
|
for y = 1, h - 2 do
|
|
for x = 1, w - 2 do
|
|
if not sx and Collision.isWater(x, y) and Collision.isWater(x + 1, y) and Collision.isSurfable(Collision.behavior(x, y))
|
|
and Collision.isSurfable(Collision.behavior(x + 1, y)) then
|
|
sx, sy = x, y
|
|
end
|
|
end
|
|
end
|
|
check(sx ~= nil, "Route 103 has open water (" .. tostring(sx) .. "," .. tostring(sy) .. ")")
|
|
if sx then
|
|
place("EM_ROUTE103", sx, sy, "right", true)
|
|
local got = walkUntilBattle("right", "left", 300)
|
|
check(got, "surfing on Route 103 starts a wild battle")
|
|
if got then
|
|
U.wait(90)
|
|
U.shot(game, DIR .. "/02_surf_battle.png")
|
|
local s = enemySpecies()
|
|
check(s and inTable("EM_ROUTE103", "water", s), "the surf mon comes from the Route 103 water table (" .. tostring(s) .. ")")
|
|
check(winBattle(), "the surf battle ends")
|
|
end
|
|
end
|
|
|
|
-- pokeemerald/src/wild_encounter.c:446
|
|
local rocks = 0
|
|
local rockSpecies
|
|
for attempt = 1, 25 do
|
|
place("EM_ROUTE111", 10, 10, "down")
|
|
local cleared = false
|
|
for _, eo in pairs(Objects._byId) do
|
|
local gfx = eo.def and (eo.def.graphicsId or eo.def.gfx)
|
|
local f = eo.def and tonumber(eo.def.flag or eo.def.flagId)
|
|
if gfx == FieldMoves.GFX_IDS.ROCK_SMASH_ROCK and f and f ~= 0 and Flags.getFlag(Space.store, nil, f) then
|
|
Flags.setFlag(Space.store, nil, f, false)
|
|
cleared = true
|
|
end
|
|
end
|
|
if cleared then place("EM_ROUTE111", 10, 10, "down") end
|
|
local rock
|
|
for _, eo in pairs(Objects._byId) do
|
|
local gfx = eo.def and (eo.def.graphicsId or eo.def.gfx)
|
|
if not rock and gfx == FieldMoves.GFX_IDS.ROCK_SMASH_ROCK and not eo.hidden then rock = eo end
|
|
end
|
|
if not rock then break end
|
|
local rx, ry = rock.cellX, rock.cellY
|
|
local stand
|
|
for _, d in ipairs({ { 0, 1, "up" }, { -1, 0, "right" }, { 1, 0, "left" }, { 0, -1, "down" } }) do
|
|
if not stand and Collision.isWalkable(rx + d[1], ry + d[2]) then stand = d end
|
|
end
|
|
if not stand then break end
|
|
place("EM_ROUTE111", rx + stand[1], ry + stand[2], stand[3])
|
|
U.tap(game, "a")
|
|
pump(function() return Battle.isActive() or idle() end, 900)
|
|
rocks = rocks + 1
|
|
for _ = 1, 60 do if Battle.isActive() then break end U.wait(1) end
|
|
if Battle.isActive() then
|
|
U.wait(90)
|
|
U.shot(game, DIR .. "/03_rock_smash_battle.png")
|
|
rockSpecies = enemySpecies()
|
|
winBattle()
|
|
break
|
|
end
|
|
end
|
|
check(rockSpecies ~= nil, "ROCK SMASH on a Route 111 rock started a wild battle (" .. rocks .. " rocks)")
|
|
check(rockSpecies and inTable("EM_ROUTE111", "rocks", rockSpecies),
|
|
"the rock mon comes from the Route 111 rock smash table (" .. tostring(rockSpecies) .. ")")
|
|
|
|
-- pokeemerald/src/wild_encounter.c:113
|
|
place("EM_ROUTE119", 17, 30, "up")
|
|
local rules = Encounters.rules()
|
|
local fx, fy
|
|
w, h = size()
|
|
for y = 2, h - 2 do
|
|
for x = 2, w - 2 do
|
|
if not fx and Collision.isWater(x, y) and Collision.isSurfable(Collision.behavior(x, y))
|
|
and Collision.isWater(x, y + 1) and Collision.isSurfable(Collision.behavior(x, y + 1)) then
|
|
for _ = 1, 8 do
|
|
if rules.checkFeebas("EM_ROUTE119", { x = x, y = y }) then fx, fy = x, y break end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
check(fx ~= nil, "a Feebas tile exists on Route 119 for this save's trend seed (" .. tostring(fx) .. "," .. tostring(fy) .. ")")
|
|
local fished, feebas, other = 0, false, {}
|
|
if fx then
|
|
session.registeredItem = item("OLD_ROD")
|
|
for _ = 1, 40 do
|
|
place("EM_ROUTE119", fx, fy + 1, "up", true)
|
|
U.tap(game, "select")
|
|
fished = fished + 1
|
|
for _ = 1, 900 do
|
|
if Battle.isActive() then break end
|
|
if idle() and not Field.isFishing() then break end
|
|
if Message.isOpen() then U.tap(game, "a") end
|
|
U.wait(2)
|
|
end
|
|
if Battle.isActive() then
|
|
U.wait(90)
|
|
local s = enemySpecies()
|
|
if s == sp("FEEBAS") then
|
|
feebas = true
|
|
U.shot(game, DIR .. "/04_feebas.png")
|
|
else
|
|
other[#other + 1] = s
|
|
end
|
|
winBattle()
|
|
if feebas then break end
|
|
end
|
|
end
|
|
end
|
|
check(#other > 0 or feebas, "fishing with the OLD ROD hooks wild mons (" .. fished .. " casts)")
|
|
local otherOk = true
|
|
for _, s in ipairs(other) do if not inTable("EM_ROUTE119", "fishing", s) then otherOk = false end end
|
|
check(otherOk, "non-Feebas bites come from the Route 119 fishing table")
|
|
check(feebas, "fishing the Feebas tile hooks a FEEBAS (" .. fished .. " casts)")
|
|
|
|
local st = Space.store
|
|
local wilds = Flags.getVar(st, nil, C:require("vars", "VAR_DAILY_WILDS"))
|
|
check((tonumber(wilds) or 0) >= 3, "IncrementDailyWildBattles counted the wild battles (" .. tostring(wilds) .. ")")
|
|
finish()
|
|
end
|