Files
gen1recomp/tests/drivers/game3_collision_surf_channel.lua

168 lines
6.2 KiB
Lua

local U = require("tests.drivers.util")
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/game3_collision_surf_channel"
io.stdout:setvbuf("no")
local B3F = "FR_SEAFOAM_ISLANDS_B3F"
local ROUTE_19 = "FR_ROUTE_19"
local SWIMMER = 5
-- pokefirered/include/constants/metatile_behaviors.h:21
local MB_SHALLOW_WATER = 0x17
local failures = 0
local function result(ok, label)
print((ok and "PASS " or "FAIL ") .. label)
if not ok then failures = failures + 1 end
return ok
end
local function finish()
if failures == 0 then
print("PASS collision_surf_channel")
love.event.quit(0)
else
print("FAIL collision_surf_channel failures=" .. failures)
love.event.quit(1)
end
end
return function(game)
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(150)
local Runtime = require("src.core.game3.runtime")
local Map = require("src.core.game3.map")
local Player = require("src.core.game3.player")
local Collision = require("src.core.game3.collision")
local Objects = require("src.core.game3.objects")
local Space = require("src.core.game3.scripting.space")
local Message = require("src.ui.game3.message")
local session = Runtime.getSession()
if not result(session ~= nil, "new game reached the game3 field") then return finish() end
session.repelSteps = 250
local function settle(limit)
for _ = 1, (limit or 240) do
local busy = (Space.vm and Space.vm:isRunning())
or (Message.isOpen and Message.isOpen())
if not busy then return true end
if Message.isOpen and Message.isOpen() then U.tap(game, "a") end
U.wait(4)
end
return false
end
local function place(x, y, facing)
Player.moving = false
Player.progress = 0
Player.cellX, Player.cellY = x, y
Player.px, Player.py = x * 16, y * 16
Player.targetX, Player.targetY = x, y
Player.facing = facing
Player.surfing = true
Player.dismounting = false
if game.session then
game.session.x, game.session.y, game.session.facing = x, y, facing
end
end
local function goTo(id, x, y, facing)
Map.load(nil, game, id, { x = x, y = y, facing = facing or "down" })
place(x, y, facing or "down")
U.wait(60)
settle(200)
place(x, y, facing or "down")
U.wait(20)
end
print("[driver] 1. the Seafoam B3F current channel")
local Flags = require("src.core.game3.scripting.flags")
-- data/maps/Route20/scripts.inc:17
Flags.setFlag(Space.store, nil, 0x46, true)
-- data/maps/SeafoamIslands_B2F/map.json:41
Flags.setFlag(Space.store, nil, 0x47, false)
goTo(B3F, 23, 8, "right")
print(string.format("[driver] on %s at (%d,%d) surfing=%s",
tostring(Space.mapId), Player.cellX, Player.cellY, tostring(Player.surfing)))
result(Space.mapId == B3F, "surfed into Seafoam Islands B3F, map=" .. tostring(Space.mapId))
result(Player.cellX == 23 and Player.cellY == 8,
"the surfer sits on the mid-channel shallow cell")
result(Player.surfing == true, "and is still on Surf there")
result(Player.dismounting ~= true, "with no dismount queued")
for _, cell in ipairs({ { 23, 8 }, { 24, 8 } }) do
local cx, cy = cell[1], cell[2]
result(Collision.behavior(cx, cy) == MB_SHALLOW_WATER,
string.format("(%d,%d) is MB_SHALLOW_WATER (0x%02X)", cx, cy,
Collision.behavior(cx, cy) or 0))
result(Collision.elevationAt(cx, cy) == 1,
string.format("(%d,%d) sits at elevation 1, below CanStopSurfing's elevation 3",
cx, cy))
result(Collision.isWater(cx, cy) == true,
string.format("(%d,%d) still counts as surf water", cx, cy))
end
U.shot(game, DIR .. "/collision_surf_channel_01_seafoam_shallow.png")
local okEast, whyEast = Collision.canEnter(game, 24, 8,
{ fromX = 23, fromY = 8, dir = "right", surfing = true })
print("[driver] east onto (24,8): canEnter=" .. tostring(okEast)
.. " reason=" .. tostring(whyEast))
result(okEast == false and whyEast == "entity",
"(24,8) is refused by the boulder standing on it, not by the water rule")
local visited, dropped = {}, false
local moved
for _ = 1, 4 do
moved = Player.tryMove("up", game, false)
print("[driver] tryMove up -> " .. tostring(moved)
.. " dismounting=" .. tostring(Player.dismounting))
if moved == "step" then break end
U.wait(8)
end
result(moved == "step", "the surfer steps north onto the current cell above")
result(Player.dismounting ~= true, "leaving the shallow cell is not a dismount")
for _ = 1, 120 do
U.wait(1)
visited[Player.cellX .. "," .. Player.cellY] = true
if Player.surfing ~= true or Player.dismounting == true then dropped = true end
end
local cells = {}
for k in pairs(visited) do cells[#cells + 1] = k end
table.sort(cells)
print("[driver] the surfer occupied " .. table.concat(cells, " "))
result(visited["23,8"] == true, "the current carries him back over the shallow cell")
result(not dropped, "Surf never dropped inside the channel")
result(Player.surfing == true, "and the player is still surfing")
print("[driver] 2. the Route 19 swimmer keeps wandering")
goTo(ROUTE_19, 8, 25, "down")
local swimmer = Objects.find(SWIMMER)
if not result(swimmer ~= nil, "the Route 19 swimmer is loaded") then return finish() end
result(swimmer.movement == "WALK", "she is a wandering object event")
result(Collision.isWater(swimmer.cellX, swimmer.cellY) == true,
string.format("and treads water at (%d,%d)", swimmer.cellX, swimmer.cellY))
local homeX, homeY = swimmer.cellX, swimmer.cellY
local wet, ashore, moved = {}, false, false
for _ = 1, 300 do
U.wait(1)
wet[swimmer.cellX .. "," .. swimmer.cellY] = true
if swimmer.cellX ~= homeX or swimmer.cellY ~= homeY then moved = true end
if not Collision.isWater(swimmer.cellX, swimmer.cellY) then ashore = true end
end
local swum = {}
for k in pairs(wet) do swum[#swum + 1] = k end
table.sort(swum)
print("[driver] the swimmer occupied " .. table.concat(swum, " "))
result(moved, "she moves while the player floats beside her")
result(not ashore, "and never climbs out onto the land")
U.shot(game, DIR .. "/collision_surf_channel_02_route19_swimmer.png")
finish()
end