mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
244 lines
8.6 KiB
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
|