mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
123feef3a1
CLOSES #2425, CLOSES #2428, CLOSES #2431, CLOSES #2432, CLOSES #2433, CLOSES #2435, CLOSES #2436, CLOSES #2437, CLOSES #2440
289 lines
11 KiB
Lua
289 lines
11 KiB
Lua
local U = require("tests.drivers.util")
|
|
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/game3_town_map"
|
|
|
|
-- pokefirered/data/maps/PalletTown_RivalsHouse/scripts.inc:144
|
|
local ITEM_TOWN_MAP = 361
|
|
|
|
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 town_map")
|
|
love.event.quit(0)
|
|
else
|
|
print("FAIL town_map 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(240)
|
|
|
|
local Runtime = require("src.core.game3.runtime")
|
|
local Bag = require("src.core.game3.bag")
|
|
local Map = require("src.core.game3.map")
|
|
local Player = require("src.core.game3.player")
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
local Space = require("src.core.game3.scripting.space")
|
|
local ItemUse = require("src.core.game3.item_use")
|
|
local StartMenu = require("src.ui.game3.start_menu")
|
|
local BagMenu = require("src.ui.game3.bag_menu")
|
|
local RegionMap = require("src.ui.game3.region_map")
|
|
|
|
local session = Runtime.getSession()
|
|
if not result(session ~= nil, "new game reached the game3 field") then return finish() end
|
|
|
|
for _, name in ipairs({
|
|
"FLAG_WORLD_MAP_PALLET_TOWN", "FLAG_WORLD_MAP_VIRIDIAN_CITY", "FLAG_WORLD_MAP_MT_MOON_1F",
|
|
"FLAG_SYS_SEVII_MAP_123", "FLAG_SYS_SEVII_MAP_4567",
|
|
"FLAG_WORLD_MAP_ONE_ISLAND", "FLAG_WORLD_MAP_FOUR_ISLAND", "FLAG_WORLD_MAP_SEVEN_ISLAND",
|
|
}) do
|
|
Flags.setFlag(Space.store, Space.vm and Space.vm.ctx, name, true)
|
|
end
|
|
|
|
session.bag = session.bag or Bag.new()
|
|
Bag.add(session.bag, ITEM_TOWN_MAP, 1)
|
|
|
|
local function state() return RegionMap.state() end
|
|
local function waitFor(cond, max)
|
|
for _ = 1, max or 300 do
|
|
if cond() then return true end
|
|
U.wait(1)
|
|
end
|
|
return cond()
|
|
end
|
|
local function settle() return waitFor(function() return RegionMap.inputReady() end, 400) end
|
|
|
|
U.tap(game, "start")
|
|
U.wait(30)
|
|
if not result(StartMenu.isOpen(), "START opened the field menu") then return finish() end
|
|
for _ = 1, 12 do
|
|
local e = StartMenu.ENTRIES and StartMenu.ENTRIES[StartMenu.cursor]
|
|
if e and e.id == "bag" then break end
|
|
U.tap(game, "down")
|
|
U.wait(8)
|
|
end
|
|
U.tap(game, "a")
|
|
U.wait(60)
|
|
if not result(BagMenu.isOpen(), "BAG opened") then return finish() end
|
|
for _ = 1, 4 do
|
|
if BagMenu.currentPocket() == "KEY_ITEMS" then break end
|
|
U.tap(game, "right")
|
|
U.wait(15)
|
|
end
|
|
local function selectedName()
|
|
local rows = BagMenu.list()
|
|
local row = rows and rows[BagMenu.cursor]
|
|
return row and tostring(row.name) or nil
|
|
end
|
|
for _ = 1, 20 do
|
|
if selectedName() == "TOWN MAP" then break end
|
|
U.tap(game, "down")
|
|
U.wait(8)
|
|
end
|
|
if not result(selectedName() == "TOWN MAP", "the bag cursor is on TOWN MAP") then return finish() end
|
|
U.tap(game, "a")
|
|
U.wait(25)
|
|
U.tap(game, "a")
|
|
|
|
-- src/region_map.c:2462 MoveMapEdgesOutward
|
|
local sliding = waitFor(function()
|
|
local s = state()
|
|
return s and s.anim and s.anim.openState == 6 and s.anim.moveState == 5
|
|
end, 200)
|
|
result(sliding, "the Town Map opens with the map-edge slide")
|
|
U.still(game, DIR .. "/rm_open_anim_mid.png")
|
|
|
|
-- src/region_map.c:2438
|
|
local whiteFade = waitFor(function()
|
|
local s = state()
|
|
return s and s.anim and s.anim.openState >= 12
|
|
end, 200)
|
|
result(whiteFade, "the map fades in from white after the slide")
|
|
-- src/region_map.c:2440 SetMapEdgeInvisibility
|
|
local edgesFreed = waitFor(function()
|
|
local s = state()
|
|
if not (s and s.anim and s.anim.openState >= 13) then return false end
|
|
for _, e in ipairs(s.edges or {}) do
|
|
if e.visible then return false end
|
|
end
|
|
return true
|
|
end, 200)
|
|
result(edgesFreed, "the edge sprites are gone once the white fade ends")
|
|
local fadePath = DIR .. "/rm_open_white_fade.png"
|
|
U.still(game, fadePath)
|
|
do
|
|
local f = io.open(fadePath, "rb")
|
|
local bytes = f and f:read("*a")
|
|
if f then f:close() end
|
|
local ok, img = pcall(function()
|
|
return love.image.newImageData(love.filesystem.newFileData(bytes, "rm_open_white_fade.png"))
|
|
end)
|
|
if ok and img then
|
|
local w, h = img:getDimensions()
|
|
local scale = math.floor(math.min(w / 240, h / 160))
|
|
local ox, oy = math.floor((w - 240 * scale) / 2), math.floor((h - 160 * scale) / 2)
|
|
local gx, gy = 7, 134
|
|
local r, g, b = img:getPixel(ox + gx * scale + 1, oy + gy * scale + 1)
|
|
r, g, b = math.floor(r * 255 + 0.5), math.floor(g * 255 + 0.5), math.floor(b * 255 + 0.5)
|
|
print(string.format("[driver] frame edge pixel at %d,%d = %d,%d,%d", gx, gy, r, g, b))
|
|
-- src/region_map.c:963 RegionMap_DarkenPalette 95
|
|
result(math.abs(r - 230) <= 6 and math.abs(g - 189) <= 6 and math.abs(b - 41) <= 6,
|
|
string.format("the frame edge is the 95%% tinted yellow (%d,%d,%d ~ 230,189,41)", r, g, b))
|
|
else
|
|
result(false, "read back rm_open_white_fade.png")
|
|
end
|
|
end
|
|
|
|
if not result(settle(), "the Town Map reached its input state") then return finish() end
|
|
result(RegionMap.state().fromField == false, "opened from the BAG, so SELECT will not close it")
|
|
result(RegionMap.currentLocationName() == "PALLET TOWN",
|
|
"the Town Map opens on PALLET TOWN, got " .. tostring(RegionMap.currentLocationName()))
|
|
local cursorImg = RegionMap._images["cursor"]
|
|
result(cursorImg and cursorImg:getWidth() == 16 and cursorImg:getHeight() == 32,
|
|
"the cursor sheet holds both 16x16 frames")
|
|
U.still(game, DIR .. "/rm_kanto_town_map.png")
|
|
|
|
local function moveTo(x, y)
|
|
for _ = 1, 60 do
|
|
if RegionMap.cursorX == x and RegionMap.cursorY == y then return true end
|
|
if RegionMap.cursorX < x then U.tap(game, "right")
|
|
elseif RegionMap.cursorX > x then U.tap(game, "left")
|
|
elseif RegionMap.cursorY < y then U.tap(game, "down")
|
|
else U.tap(game, "up") end
|
|
U.wait(6)
|
|
end
|
|
return RegionMap.cursorX == x and RegionMap.cursorY == y
|
|
end
|
|
|
|
result(moveTo(9, 3), "the cursor walked to MT. MOON")
|
|
U.wait(4)
|
|
result(RegionMap.currentDungeonName() == "MT. MOON", "the dungeon name box reads MT. MOON")
|
|
local _, right = RegionMap.topBarText()
|
|
result(right == "gText_RegionMap_AButtonGuide", "a visited dungeon offers A GUIDE")
|
|
U.still(game, DIR .. "/rm_name_box_mt_moon.png")
|
|
|
|
U.tap(game, "a")
|
|
local growing = waitFor(function()
|
|
local s = state()
|
|
return s and s.preview and s.preview.updateCounter == 4
|
|
end, 60)
|
|
result(growing, "A opened the GUIDE window")
|
|
U.still(game, DIR .. "/rm_guide_growing.png")
|
|
local texted = waitFor(function()
|
|
local s = state()
|
|
return s and s.preview and s.preview.text ~= nil
|
|
end, 200)
|
|
result(texted, "the GUIDE printed its text after the sepia tint")
|
|
U.still(game, DIR .. "/rm_guide_text.png")
|
|
U.tap(game, "b")
|
|
local shrinking = waitFor(function()
|
|
local s = state()
|
|
return s and s.preview and s.preview.mainState == 8 and s.preview.updateCounter == 4
|
|
end, 60)
|
|
result(shrinking, "B shrinks the GUIDE window")
|
|
U.still(game, DIR .. "/rm_guide_shrinking.png")
|
|
settle()
|
|
result(RegionMap.previewDungeon == nil, "the GUIDE closed")
|
|
|
|
-- src/region_map.c:2862 SnapToIconOrButton
|
|
U.tap(game, "start")
|
|
U.wait(4)
|
|
result(RegionMap.cursorX == 21 and RegionMap.cursorY == 11, "START snapped to the SWITCH button")
|
|
U.tap(game, "a")
|
|
local menu = waitFor(function()
|
|
local s = state()
|
|
return s and s.switch and s.switch.mainState == 9
|
|
end, 120)
|
|
result(menu, "A on SWITCH opened the switch menu")
|
|
result(state().switch and state().switch.maxSelection == 3, "FLAG_SYS_SEVII_MAP_4567 offers all four maps")
|
|
U.still(game, DIR .. "/rm_switch_menu.png")
|
|
U.tap(game, "down")
|
|
U.wait(4)
|
|
U.still(game, DIR .. "/rm_switch_menu_sevii123.png")
|
|
U.tap(game, "a")
|
|
waitFor(function() return state() and state().switch == nil end, 120)
|
|
settle()
|
|
result(state().selectedRegion == 1, "the map switched to SEVII 1-2-3")
|
|
U.still(game, DIR .. "/rm_sevii123_switched.png")
|
|
|
|
result(state().palTinted == true, "the open Town Map draws bank 2 at 95%")
|
|
U.tap(game, "b")
|
|
-- src/region_map.c:2572
|
|
local untinted = waitFor(function()
|
|
local s = state()
|
|
return s and s.anim and s.anim.closeState == 5 and s.anim.blendY == 1
|
|
end, 120)
|
|
result(untinted and state().palTinted == false, "close state 2 reloads sRegionMap_Pal untinted")
|
|
U.still(game, DIR .. "/rm_close_untinted.png")
|
|
local closing = waitFor(function()
|
|
local s = state()
|
|
return s and s.anim and s.anim.closeState == 7 and s.anim.moveState == 6
|
|
end, 120)
|
|
result(closing, "B runs the map-edge close slide")
|
|
U.still(game, DIR .. "/rm_close_anim_mid.png")
|
|
waitFor(function() return not RegionMap.isOpen() end, 200)
|
|
result(not RegionMap.isOpen(), "B closed the Town Map")
|
|
for _ = 1, 20 do
|
|
if not BagMenu.isOpen() then break end
|
|
U.tap(game, "b")
|
|
U.wait(10)
|
|
end
|
|
U.wait(30)
|
|
|
|
local function goTo(mapId, x, y)
|
|
Map.load(nil, game, mapId, { x = x, y = y, facing = "down" })
|
|
if game.session then
|
|
game.session.x, game.session.y, game.session.facing = x, y, "down"
|
|
end
|
|
Player.cellX, Player.cellY = x, y
|
|
Player.px, Player.py = x * 16, y * 16
|
|
Player.targetX, Player.targetY = x, y
|
|
U.wait(120)
|
|
end
|
|
|
|
local function openFromField(label)
|
|
ItemUse.useField(session, session.bag, ITEM_TOWN_MAP, nil)
|
|
return result(settle(), label)
|
|
end
|
|
|
|
-- src/region_map.c:1028-1049
|
|
local sevii = {
|
|
{ map = "FR_FOUR_ISLAND", x = 12, y = 14, region = 2, name = "FOUR ISLAND", shot = "rm_four_island_sevii45.png" },
|
|
{ map = "SEVII_ONE_ISLAND", x = 12, y = 12, region = 1, name = "ONE ISLAND", shot = "rm_one_island_sevii123.png" },
|
|
{ map = "FR_SEVEN_ISLAND", x = 10, y = 10, region = 3, name = "SEVEN ISLAND", shot = "rm_seven_island_sevii67.png" },
|
|
}
|
|
for i, case in ipairs(sevii) do
|
|
goTo(case.map, case.x, case.y)
|
|
if openFromField("the Town Map opened on " .. case.map) then
|
|
result(state().selectedRegion == case.region,
|
|
case.map .. " opens the Sevii map " .. case.region .. ", got " .. tostring(state().selectedRegion))
|
|
result(RegionMap.currentLocationName() == case.name,
|
|
"the cursor starts on " .. case.name .. ", got " .. tostring(RegionMap.currentLocationName()))
|
|
U.still(game, DIR .. "/" .. case.shot)
|
|
if i == 1 then
|
|
result(state().fromField == true, "opened from the field")
|
|
U.tap(game, "select")
|
|
else
|
|
U.tap(game, "b")
|
|
end
|
|
waitFor(function() return not RegionMap.isOpen() end, 200)
|
|
result(not RegionMap.isOpen(), (i == 1 and "SELECT" or "B") .. " closed the field Town Map")
|
|
U.wait(20)
|
|
end
|
|
end
|
|
|
|
finish()
|
|
end
|