mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
285 lines
10 KiB
Lua
285 lines
10 KiB
Lua
local U = require("tests.drivers.util")
|
|
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/game3_encounters_cave"
|
|
|
|
local MT_MOON = "FR_MT_MOON_1F"
|
|
local ROUTE_1 = "FR_ROUTE_1"
|
|
local SURF_MAP = "FR_ROUTE_21_NORTH"
|
|
|
|
return function(game)
|
|
local fails = 0
|
|
local function result(ok, label)
|
|
print((ok and "PASS " or "FAIL ") .. label)
|
|
if not ok then fails = fails + 1 end
|
|
return ok
|
|
end
|
|
local function finish()
|
|
if fails == 0 then
|
|
print("PASS encounters_cave")
|
|
love.event.quit(0)
|
|
else
|
|
print("FAIL encounters_cave failures=" .. fails)
|
|
love.event.quit(1)
|
|
end
|
|
end
|
|
|
|
for _ = 1, 900 do
|
|
if game.phase == "boot" and game.boot then break end
|
|
U.wait(1)
|
|
end
|
|
game:_handleBootAction({ action = "new_game", name = "RED" })
|
|
U.wait(240)
|
|
|
|
local Runtime = require("src.core.game3.runtime")
|
|
local Party = require("src.core.game3.party")
|
|
local Map = require("src.core.game3.map")
|
|
local Player = require("src.core.game3.player")
|
|
local Collision = require("src.core.game3.collision")
|
|
local Encounters = require("src.core.game3.encounters")
|
|
local Battle = require("src.core.game3.battle")
|
|
local Ui = require("src.core.game3.battle.ui")
|
|
local Rng = require("src.core.game3.rng")
|
|
|
|
local session = Runtime.getSession()
|
|
if not result(session ~= nil, "new game reached the game3 field") then return finish() end
|
|
session.party = {}
|
|
Party.giveMon(session, 6, 50)
|
|
|
|
local function placeAt(mapId, x, y, facing)
|
|
Map.load(nil, game, mapId, { x = x, y = y, facing = facing or "down" })
|
|
if game.session then
|
|
game.session.x, game.session.y, game.session.facing = x, y, facing or "down"
|
|
end
|
|
Player.cellX, Player.cellY = x, y
|
|
Player.px, Player.py = x * 16, y * 16
|
|
Player.targetX, Player.targetY = x, y
|
|
Player.facing = facing or "down"
|
|
U.wait(60)
|
|
end
|
|
|
|
local function enterable(want, cx, cy)
|
|
if Encounters.encounterTypeAt(cx, cy) ~= want then return false end
|
|
if want == 2 then return Collision.isWater(cx, cy) end
|
|
return Collision.isWalkable(cx, cy) and Collision.canEnter(game, cx, cy, {}) ~= false
|
|
end
|
|
|
|
local function openCell(want)
|
|
local layout = Map._def and Map._def.midLayout
|
|
if not layout then return nil end
|
|
local best, bestScore = nil, -1
|
|
for cy = 3, layout.height - 4 do
|
|
for cx = 3, layout.width - 4 do
|
|
if enterable(want, cx, cy) then
|
|
local score = 0
|
|
for dy = -2, 2 do
|
|
for dx = -2, 2 do
|
|
if enterable(want, cx + dx, cy + dy) then score = score + 1 end
|
|
end
|
|
end
|
|
if score > bestScore then best, bestScore = { cx, cy }, score end
|
|
end
|
|
end
|
|
end
|
|
if best and bestScore >= 9 then return best[1], best[2], bestScore end
|
|
return nil
|
|
end
|
|
|
|
local DIRS = { "right", "down", "left", "up" }
|
|
local DELTA = { right = { 1, 0 }, down = { 0, 1 }, left = { -1, 0 }, up = { 0, -1 } }
|
|
|
|
local function patrol(mapId, want, maxSteps)
|
|
local steps, stuck, di = 0, 0, 1
|
|
while steps < maxSteps and stuck < 24 do
|
|
if Battle.isActive and Battle.isActive() then return true, steps end
|
|
local d = DELTA[DIRS[di]]
|
|
local tx, ty = Player.cellX + d[1], Player.cellY + d[2]
|
|
if not enterable(want, tx, ty) then
|
|
stuck = stuck + 1
|
|
di = (di % 4) + 1
|
|
else
|
|
local bx, by = Player.cellX, Player.cellY
|
|
local btn = DIRS[di]
|
|
for _ = 1, 30 do
|
|
table.insert(game.input.pressQueue, btn)
|
|
game.input.state[btn] = true
|
|
coroutine.yield()
|
|
if Player.moving or (Battle.isActive and Battle.isActive()) then break end
|
|
end
|
|
game.input.state[btn] = false
|
|
for _ = 1, 60 do
|
|
if not Player.moving then break end
|
|
coroutine.yield()
|
|
end
|
|
U.wait(4)
|
|
if Battle.isActive and Battle.isActive() then return true, steps end
|
|
if Map.current ~= mapId then return false, steps end
|
|
if Player.cellX ~= bx or Player.cellY ~= by then
|
|
steps = steps + 1
|
|
stuck = 0
|
|
else
|
|
stuck = stuck + 1
|
|
di = (di % 4) + 1
|
|
end
|
|
end
|
|
end
|
|
return (Battle.isActive and Battle.isActive()) or false, steps
|
|
end
|
|
|
|
local function enemySpecies()
|
|
local st = Battle.getState and Battle.getState()
|
|
local mon = st and st.enemy and st.enemy.mon
|
|
return mon and (tonumber(mon.species) or mon.species), mon and mon.level
|
|
end
|
|
|
|
local function speciesSet(area)
|
|
local out = {}
|
|
for _, slot in ipairs((area and area.slots) or {}) do out[slot.species] = true end
|
|
return out
|
|
end
|
|
|
|
local function flee()
|
|
for _ = 1, 400 do
|
|
if not (Battle.isActive and Battle.isActive()) then return true end
|
|
if Battle._phase == "command" and Ui._mode == "menu" then
|
|
U.tap(game, "down")
|
|
U.wait(6)
|
|
U.tap(game, "right")
|
|
U.wait(6)
|
|
U.tap(game, "a")
|
|
U.wait(20)
|
|
else
|
|
U.tap(game, "a")
|
|
U.wait(8)
|
|
end
|
|
end
|
|
return not (Battle.isActive and Battle.isActive())
|
|
end
|
|
|
|
-- pokefirered/src/wild_encounter.c:404
|
|
placeAt(SURF_MAP, 10, 10, "down")
|
|
Player.surfing = true
|
|
local waterTable = Encounters.tableFor(SURF_MAP)
|
|
local wx, wy, wScore = openCell(2)
|
|
result(wx ~= nil, SURF_MAP .. " has open surfable water (TILE_ENCOUNTER_WATER)")
|
|
result(type(waterTable) == "table" and type(waterTable.water) == "table",
|
|
SURF_MAP .. " carries a water encounter table")
|
|
if wx and waterTable and waterTable.water then
|
|
U.log(string.format("water start (%d,%d) open=%d", wx, wy, wScore))
|
|
placeAt(SURF_MAP, wx, wy, "right")
|
|
Player.surfing = true
|
|
U.wait(60)
|
|
Rng.SeedRng(0x4321)
|
|
Rng.SeedWildEncounterRng(0x4321)
|
|
Encounters.resetRateModifiers()
|
|
local hit, steps = patrol(SURF_MAP, 2, 220)
|
|
U.log(string.format("surf patrol ended at (%d,%d) after %d steps",
|
|
Player.cellX, Player.cellY, steps))
|
|
result(hit, "surfing started a wild battle (steps=" .. steps .. ")")
|
|
if hit then
|
|
U.wait(120)
|
|
local sp, lv = enemySpecies()
|
|
U.log(string.format("surf wild: species=%s level=%s", tostring(sp), tostring(lv)))
|
|
result(speciesSet(waterTable.water)[sp] == true,
|
|
"species " .. tostring(sp) .. " comes from the " .. SURF_MAP .. " water table")
|
|
U.shot(game, DIR .. "/encounters_cave_01_surf_battle.png")
|
|
result(flee(), "left the surf battle")
|
|
U.wait(90)
|
|
end
|
|
end
|
|
|
|
-- pokefirered/src/wild_encounter.c:712
|
|
placeAt(ROUTE_1, 9, 18, "down")
|
|
local rx, ry = openCell(0)
|
|
result(rx ~= nil, "Route 1 has open road (TILE_ENCOUNTER_NONE)")
|
|
if rx then
|
|
U.log(string.format("Route 1 road start (%d,%d)", rx, ry))
|
|
placeAt(ROUTE_1, rx, ry, "right")
|
|
Rng.SeedRng(0x1234)
|
|
Rng.SeedWildEncounterRng(0x1234)
|
|
Encounters.resetRateModifiers()
|
|
local hit, steps = patrol(ROUTE_1, 0, 24)
|
|
U.log(string.format("road walk ended at (%d,%d) after %d steps",
|
|
Player.cellX, Player.cellY, steps))
|
|
result(steps >= 8, "the road walk actually moved (" .. steps .. " steps)")
|
|
result(not hit, "no wild battle after " .. steps .. " steps on the Route 1 road")
|
|
U.shot(game, DIR .. "/encounters_cave_02_route1_road.png")
|
|
end
|
|
|
|
-- pokefirered/src/wild_encounter.c:366
|
|
placeAt(MT_MOON, 5, 33, "down")
|
|
local cx, cy, cScore = openCell(1)
|
|
result(cx ~= nil, "Mt Moon 1F has open cave floor (TILE_ENCOUNTER_LAND)")
|
|
local landTable = Encounters.tableFor(MT_MOON)
|
|
result(type(landTable) == "table" and type(landTable.land) == "table",
|
|
"Mt Moon 1F carries a land encounter table")
|
|
if cx and landTable and landTable.land then
|
|
U.log(string.format("Mt Moon cave start (%d,%d) open=%d", cx, cy, cScore))
|
|
placeAt(MT_MOON, cx, cy, "right")
|
|
U.shot(game, DIR .. "/encounters_cave_03_mt_moon_floor.png")
|
|
Rng.SeedRng(0x1234)
|
|
Rng.SeedWildEncounterRng(0x1234)
|
|
Encounters.resetRateModifiers()
|
|
local hit, steps = patrol(MT_MOON, 1, 100)
|
|
U.log(string.format("Mt Moon patrol ended at (%d,%d) after %d steps",
|
|
Player.cellX, Player.cellY, steps))
|
|
result(hit, "walking Mt Moon 1F started a wild battle (steps=" .. steps .. ")")
|
|
if hit then
|
|
U.wait(120)
|
|
local sp, lv = enemySpecies()
|
|
U.log(string.format("Mt Moon wild: species=%s level=%s", tostring(sp), tostring(lv)))
|
|
result(speciesSet(landTable.land)[sp] == true,
|
|
"species " .. tostring(sp) .. " comes from the Mt Moon 1F land table")
|
|
U.shot(game, DIR .. "/encounters_cave_04_mt_moon_battle.png")
|
|
result(flee(), "left the Mt Moon battle")
|
|
U.wait(90)
|
|
end
|
|
end
|
|
|
|
-- pokefirered/src/wild_encounter.c:601
|
|
if cx and landTable and landTable.land then
|
|
local topLevel = 0
|
|
for _, slot in ipairs(landTable.land.slots or {}) do
|
|
local hi = tonumber(slot.maxLevel or slot.level) or 0
|
|
if hi > topLevel then topLevel = hi end
|
|
end
|
|
U.log("Mt Moon 1F land table top level " .. topLevel)
|
|
|
|
placeAt(MT_MOON, cx, cy, "right")
|
|
session.party = {}
|
|
Party.giveMon(session, 6, topLevel + 1)
|
|
session.repelSteps = 250
|
|
Rng.SeedRng(0x5150)
|
|
Rng.SeedWildEncounterRng(0x5150)
|
|
Encounters.resetRateModifiers()
|
|
local blocked, bSteps = patrol(MT_MOON, 1, 70)
|
|
U.log(string.format("repel patrol (lead L%d) ended at (%d,%d) after %d steps",
|
|
topLevel + 1, Player.cellX, Player.cellY, bSteps))
|
|
result(bSteps >= 30, "the repel walk actually moved (" .. bSteps .. " steps)")
|
|
result(not blocked,
|
|
"Repel with a Lv" .. (topLevel + 1) .. " lead blocked every Mt Moon wild in " .. bSteps .. " steps")
|
|
U.shot(game, DIR .. "/encounters_cave_05_mt_moon_repel.png")
|
|
|
|
placeAt(MT_MOON, cx, cy, "right")
|
|
session.party = {}
|
|
Party.giveMon(session, 6, topLevel)
|
|
session.repelSteps = 500
|
|
Rng.SeedRng(0x1234)
|
|
Rng.SeedWildEncounterRng(0x1234)
|
|
Encounters.resetRateModifiers()
|
|
local equalHit, eSteps = patrol(MT_MOON, 1, 400)
|
|
U.log(string.format("repel patrol (lead L%d) ended at (%d,%d) after %d steps",
|
|
topLevel, Player.cellX, Player.cellY, eSteps))
|
|
result(equalHit,
|
|
"a wild at exactly the lead's level still battles under Repel (steps=" .. eSteps .. ")")
|
|
if equalHit then
|
|
U.wait(120)
|
|
local sp, lv = enemySpecies()
|
|
U.log(string.format("repel boundary wild: species=%s level=%s", tostring(sp), tostring(lv)))
|
|
result(lv == topLevel,
|
|
"the wild that got through is Lv" .. tostring(lv) .. ", the lead's level")
|
|
U.shot(game, DIR .. "/encounters_cave_06_mt_moon_repel_equal.png")
|
|
end
|
|
end
|
|
|
|
finish()
|
|
end
|