Files
gen1recomp/tests/drivers/game3_encounters_rocksmash.lua

244 lines
8.6 KiB
Lua

local U = require("tests.drivers.util")
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/game3_encounters_rocksmash"
local MT_EMBER = "FR_MT_EMBER_EXTERIOR"
local FOUR_ISLAND = "FR_FOUR_ISLAND"
-- pokefirered/include/constants/flags.h:1369
local FLAG_BADGE06_GET = 0x825
-- pokefirered/include/constants/event_objects.h:102
local GFX_ROCK_SMASH_ROCK = 96
-- pokefirered/include/constants/moves.h:253
local MOVE_ROCK_SMASH = 249
-- pokefirered/include/constants/vars.h:186
local VAR_MAP_SCENE_FOUR_ISLAND = 0x4086
-- pokefirered/src/wild_encounter.c:303
local WILD_SEED = 8
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_rocksmash")
love.event.quit(0)
else
print("FAIL encounters_rocksmash 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 Objects = require("src.core.game3.objects")
local Collision = require("src.core.game3.collision")
local Encounters = require("src.core.game3.encounters")
local Space = require("src.core.game3.scripting.space")
local Flags = require("src.core.game3.scripting.flags")
local Message = require("src.ui.game3.message")
local Choice = require("src.ui.game3.choice")
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
local function ctx() return Space.vm and Space.vm.ctx end
session.party = {}
Party.giveMon(session, 95, 40)
local lead = session.party[1]
lead.moves = { MOVE_ROCK_SMASH }
lead.pp = { 15 }
lead.maxPp = { 15 }
Flags.setFlag(Space.store, ctx(), FLAG_BADGE06_GET, true)
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 findRock()
for _, lid in ipairs(Objects.listActive()) do
local eo = Objects.find(lid)
local gfx = eo and (eo.gfx or eo.graphicsId)
if gfx == GFX_ROCK_SMASH_ROCK then return lid, eo end
end
return nil
end
local NEIGHBOURS = {
{ 0, 1, "up" }, { 0, -1, "down" }, { 1, 0, "left" }, { -1, 0, "right" },
}
local FACE_DELTA = { up = { 0, -1 }, down = { 0, 1 }, left = { -1, 0 }, right = { 1, 0 } }
local function facedObject()
local d = FACE_DELTA[Player.facing] or { 0, 1 }
return Objects.at(Player.cellX + d[1], Player.cellY + d[2])
end
local function standNextTo(mapId, eo)
for _, n in ipairs(NEIGHBOURS) do
local sx, sy = eo.cellX + n[1], eo.cellY + n[2]
if Collision.isWalkable(sx, sy) and not Objects.blocks(sx, sy) then
placeAt(mapId, sx, sy, n[3])
local front = facedObject()
U.log(string.format("at (%d,%d) facing %s, front object gfx=%s script=%s",
sx, sy, n[3], tostring(front and (front.gfx or front.graphicsId)),
tostring(front and (front.script or (front.def and front.def.script)))))
return sx, sy, n[3]
end
end
return nil
end
local function busy()
return (Space.vm and Space.vm:isRunning())
or (Message.isOpen and Message.isOpen())
or Choice.active
or require("src.core.game3.field").locked
end
local function smash(limit)
local ticks, seen = 0, {}
while ticks < (limit or 900) do
if Battle.isActive and Battle.isActive() then return true end
local txt = Message.currentPage and Message.currentPage()
if type(txt) == "string" and txt ~= "" and not seen[txt] then
seen[txt] = true
U.log("dialog: " .. txt:gsub("\n", " / "))
end
U.tap(game, "a")
U.wait(14)
ticks = ticks + 14
if not busy() and ticks > 120 then break end
end
return (Battle.isActive and Battle.isActive()) == true
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 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:446
placeAt(MT_EMBER, 29, 42, "up")
local emberTable = Encounters.tableFor(MT_EMBER)
result(type(emberTable) == "table" and type(emberTable.rocks) == "table",
MT_EMBER .. " carries a rockSmashMonsInfo table")
local rockIds, rockEo = findRock()
result(rockIds ~= nil, "Mt Ember Exterior has a visible ROCK_SMASH_ROCK object")
if rockIds and emberTable and emberTable.rocks then
local sx, sy, facing = standNextTo(MT_EMBER, rockEo)
result(sx ~= nil, string.format("stood next to the rock at (%d,%d)", rockEo.cellX, rockEo.cellY))
U.log(string.format("player at (%s,%s) facing %s, rock at (%d,%d)",
tostring(sx), tostring(sy), tostring(facing), rockEo.cellX, rockEo.cellY))
Rng.SeedRng(0x1234)
Rng.SeedWildEncounterRng(WILD_SEED)
Encounters.resetRateModifiers()
U.tap(game, "a")
for _ = 1, 40 do
if Message.isOpen and Message.isOpen() then break end
U.wait(6)
end
U.wait(40)
result(Message.isOpen and Message.isOpen(), "the rock prompt opened")
U.shot(game, DIR .. "/rocksmash_01_prompt.png")
local hit = smash(1200)
result(hit, "smashing the Mt Ember rock started a wild battle")
result(Objects.find(rockIds) == nil
or not (Objects.find(rockIds).visible and not Objects.find(rockIds).hidden),
"the smashed rock is gone from the map")
if hit then
U.wait(300)
local sp, lv = enemySpecies()
U.log(string.format("rock smash wild: species=%s level=%s", tostring(sp), tostring(lv)))
local allowed, lo, hi = {}, 99, 0
for _, slot in ipairs(emberTable.rocks.slots or {}) do
allowed[slot.species] = true
local a = tonumber(slot.minLevel) or 0
local b = tonumber(slot.maxLevel) or a
if a < lo then lo = a end
if b > hi then hi = b end
end
result(allowed[sp] == true,
"species " .. tostring(sp) .. " comes from the Mt Ember rocks table")
result(lv ~= nil and lv >= lo and lv <= hi,
string.format("level %s is inside the rocks table range %d-%d", tostring(lv), lo, hi))
U.shot(game, DIR .. "/rocksmash_02_wild_battle.png")
result(flee(), "left the rock smash battle")
U.wait(90)
end
end
-- pokefirered/src/wild_encounter.c:451
-- pokefirered/data/maps/FourIsland/scripts.inc:48
Flags.setVar(Space.store, ctx(), VAR_MAP_SCENE_FOUR_ISLAND, 1)
placeAt(FOUR_ISLAND, 5, 12, "up")
Flags.setVar(Space.store, ctx(), VAR_MAP_SCENE_FOUR_ISLAND, 1)
local fourTable = Encounters.tableFor(FOUR_ISLAND)
result(type(fourTable) == "table" and fourTable.rocks == nil,
"Four Island has no rockSmashMonsInfo")
local fourId, fourEo = findRock()
result(fourId ~= nil, "Four Island has a visible ROCK_SMASH_ROCK object")
if fourId and fourTable and fourTable.rocks == nil then
local sx = standNextTo(FOUR_ISLAND, fourEo)
result(sx ~= nil, string.format("stood next to the Four Island rock at (%d,%d)",
fourEo.cellX, fourEo.cellY))
Rng.SeedRng(0x1234)
Rng.SeedWildEncounterRng(WILD_SEED)
Encounters.resetRateModifiers()
local hit2 = smash(900)
result(not hit2, "a map with no rocks area starts no battle")
result(Objects.find(fourId) == nil
or not (Objects.find(fourId).visible and not Objects.find(fourId).hidden),
"the Four Island rock still broke")
U.wait(60)
U.shot(game, DIR .. "/rocksmash_03_no_rocks_area.png")
end
finish()
end