-- pokefirered/src/pokemon_summary_screen.c:1615 local U = require("tests.drivers.util") local DIR = os.getenv("POKEPORT_SHOT_DIR") or ".bazinga/BSA/09-24-26-01-followup/shots/game3_summary_pages_s3" local failures = 0 local function pass(label, ok, detail) if ok then print("PASS " .. label) else failures = failures + 1 print("FAIL " .. label .. (detail and (" " .. tostring(detail)) or "")) end end local calls = {} local function spy(mod, name) local real = mod[name] mod[name] = function(...) calls[#calls + 1] = { name = name, args = { ... } } return real(...) end end local function called(name, pred) for _, c in ipairs(calls) do if c.name == name and (not pred or pred(c.args)) then return true end end return false end local function run(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 Map = require("src.core.game3.map") local Player = require("src.core.game3.player") local Party = require("src.core.game3.party") local Pokemon = require("src.core.game3.pokemon") local SummaryMenu = require("src.ui.game3.summary_menu") local SummaryChrome = require("src.ui.game3.summary_chrome") local session = Runtime.getSession() if not session then print("FAIL no session") love.event.quit(1) return end session.party = {} Party.giveMon(session, 25, 20) Party.giveMon(session, 1, 20) Party.giveMon(session, 4, 5) local mon = session.party[1] mon.isShiny = true mon.status = "PSN" mon.pokerus = 0x10 mon.markings = 5 mon.moves[4] = 0 mon.pp[4] = 0 mon.maxPp[4] = 0 mon.pp[1] = 4 mon.pp[2] = 14 mon.pp[3] = 0 mon.hp = math.max(1, math.floor((tonumber(mon.maxHp) or 40) / 2)) local plain = session.party[2] plain.hp = plain.maxHp plain.status = nil session.party[3].isEgg = true session.party[3].friendship = 5 Map.load(nil, game, "FR_PALLET_TOWN", { x = 10, y = 6, facing = "down" }) Player.cellX, Player.cellY = 10, 6 U.wait(60) for _, n in ipairs({ "drawBg3", "drawProgress", "drawLayer", "drawMarkings", "drawShinyStar", "drawStatusIcon", "drawTypeBadge", "drawMoveSelectionCursor" }) do spy(SummaryChrome, n) end spy(Pokemon, "monFrontPic") spy(Pokemon, "monIcon") local function frame_calls() calls = {} for _ = 1, 4000 do U.wait(1) if called("drawBg3") then calls = {} break end end for _ = 1, 4000 do U.wait(1) if called("drawBg3") then return end end end local function shot(name) return U.still(game, DIR .. "/" .. name .. ".png") end local function settle() for _ = 1, 120 do if not SummaryMenu._slide.active then break end U.wait(1) end U.wait(4) end local function until_step(n) for _ = 1, 60 do if SummaryMenu._slide.active and SummaryMenu.flipStep() == n then return true end U.wait(1) end return false end SummaryMenu.openMenu(session.party, 1, {}) settle() frame_calls() pass("s3 info shiny bg", called("drawBg3", function(a) return a[1] == "info" and a[2] == true end)) pass("s3 info shiny star frame", called("drawShinyStar", function(a) return a[1] == 102 and a[2] == 36 end)) pass("s3 info status TL", called("drawStatusIcon", function(a) return a[1] == 0 and a[2] == 34 end)) pass("s3 info markings", called("drawMarkings", function(a) return a[1] == 5 and a[2] == 4 and a[3] == 87 end)) shot("s3_info_shiny_psn_markings") U.tap(game, "left") U.wait(4) pass("s3 left on INFO does not wrap", SummaryMenu._page == SummaryMenu.PAGE_INFO and not SummaryMenu._slide.active) U.tap(game, "right") pass("s3 right from INFO starts a slide", SummaryMenu._slide.active and SummaryMenu._page == SummaryMenu.PAGE_SKILLS) local waited = 0 while SummaryMenu._slide.active and SummaryMenu.flipStep() == 0 and waited < 30 do U.wait(1) waited = waited + 1 end pass("s3r flip waits the cart's task frames before sliding", waited >= 5, waited) until_step(2) shot("s3_slide_info_out_to_skills") settle() shot("s3_skills_right_aligned") U.tap(game, "left") U.wait(3) U.tap(game, "right") U.wait(1) pass("s3r opposite press during a flip is dropped", SummaryMenu._slide.active and SummaryMenu._slide.queued == nil) settle() pass("s3r dropped press did not flip", SummaryMenu._page == SummaryMenu.PAGE_INFO) U.tap(game, "right") U.wait(3) U.tap(game, "right") U.wait(1) pass("s3r same-direction press during a flip is queued", SummaryMenu._slide.queued == 1) settle() settle() pass("s3r right-right from INFO lands on KNOWN MOVES", SummaryMenu._page == SummaryMenu.PAGE_MOVES, SummaryMenu._page) U.tap(game, "left") until_step(2) pass("s3r left flip header on incoming layer", SummaryMenu._page == SummaryMenu.PAGE_SKILLS and SummaryMenu._slide.frame >= SummaryMenu.FLIP_TIMING.page.header) shot("s3r_flip_left_header_rides_incoming_layer") settle() local Options = require("src.core.game3.options") local opts = Options.ensure(session) local savedMode = opts.buttonMode opts.buttonMode = 2 U.tap(game, "r") U.wait(2) pass("s3r R does not flip in L=A mode", SummaryMenu._page == SummaryMenu.PAGE_SKILLS and not SummaryMenu._slide.active) opts.buttonMode = 1 U.tap(game, "r") pass("s3r R flips in LR mode", SummaryMenu._page == SummaryMenu.PAGE_MOVES) settle() opts.buttonMode = savedMode frame_calls() pass("s3 known moves page", SummaryMenu._page == SummaryMenu.PAGE_MOVES) pass("s3 known moves picture frame bg3", called("drawBg3", function(a) return a[1] == "info" end) and not called("drawBg3", function(a) return a[1] == "moves" end)) pass("s3 known moves draws front pic", called("monFrontPic")) pass("s3 known moves hides icon", not called("monIcon")) pass("s3 known moves status TL", called("drawStatusIcon", function(a) return a[1] == 0 and a[2] == 34 end)) pass("s3 known moves shiny star", called("drawShinyStar", function(a) return a[1] == 102 and a[2] == 36 end)) shot("s3_known_moves_lowpp_empty_slot") U.tap(game, "right") U.wait(4) pass("s3 right on MOVES does not wrap", SummaryMenu._page == SummaryMenu.PAGE_MOVES and not SummaryMenu._slide.active) U.tap(game, "a") pass("s3 A on MOVES slides detail in", SummaryMenu._slide.active and SummaryMenu._slide.kind == "detail") until_step(2) pass("s3r detail slide name strip blank", SummaryMenu._slide.frame < SummaryMenu.FLIP_TIMING.detail.name) shot("s3r_detail_slide_blank_name_strip") settle() frame_calls() pass("s3 detail page", SummaryMenu._page == SummaryMenu.PAGE_MOVES_INFO) pass("s3 detail keeps move list panel", called("drawLayer", function(a) return a[1] == "moves" end) and called("drawLayer", function(a) return a[1] == "moves_info" end)) pass("s3 detail icon not pic", called("monIcon") and not called("monFrontPic")) pass("s3 detail hides status on A path", not called("drawStatusIcon")) pass("s3 detail shiny star TL", called("drawShinyStar", function(a) return a[1] == 4 and a[2] == 20 end)) pass("s3 detail mon type badge", called("drawTypeBadge", function(a) return a[2] == 48 and a[3] == 35 end)) shot("s3_move_detail") U.tap(game, "down") U.wait(2) U.tap(game, "a") U.wait(2) U.tap(game, "down") U.wait(2) pass("s3 swap started", SummaryMenu._swapSlot == 2 and SummaryMenu._moveCursor == 3) shot("s3_swap_cursor_shown") local flipped = false for _ = 1, 70 do U.wait(1) if SummaryMenu._blink.hidden then flipped = true break end end pass("s3 swap cursor blinks", flipped) if flipped then shot("s3_swap_cursor_blinked_off") end U.tap(game, "b") U.wait(2) pass("s3 B cancels swap", SummaryMenu._swapSlot == nil and SummaryMenu._page == SummaryMenu.PAGE_MOVES_INFO) U.tap(game, "b") settle() U.tap(game, "left") settle() U.tap(game, "right") settle() U.tap(game, "a") settle() pass("s3r move cursor kept across back-out and page flips", SummaryMenu._page == SummaryMenu.PAGE_MOVES_INFO and SummaryMenu._moveCursor == 3, SummaryMenu._moveCursor) U.tap(game, "down") U.wait(2) pass("s3 detail cursor skips the empty slot onto CANCEL", SummaryMenu._moveCursor == 5, SummaryMenu._moveCursor) shot("s3_detail_cancel_row") U.tap(game, "b") until_step(2) shot("s3_detail_slide_out") settle() pass("s3 B returns to known moves", SummaryMenu._page == SummaryMenu.PAGE_MOVES and not SummaryMenu._slide.active) pass("s3r B on CANCEL resets the move cursor", SummaryMenu._moveCursor == 1, SummaryMenu._moveCursor) U.tap(game, "left") until_step(3) shot("s3_slide_skills_in_from_moves") settle() U.tap(game, "left") settle() pass("s3 back on INFO", SummaryMenu._page == SummaryMenu.PAGE_INFO) U.tap(game, "a") U.wait(4) pass("s3 A on INFO closes", not SummaryMenu.isOpen()) for _ = 1, 10 do if not SummaryMenu.isOpen() then break end U.tap(game, "b") U.wait(4) end SummaryMenu.openMenu(session.party, 1, { mode = "select_move", moveToLearn = 85, onSelectMove = function() end }) settle() frame_calls() pass("s3 learn progress tiles", called("drawProgress", function(a) return a[1] == "moves_info_select" end)) pass("s3 learn status TL", called("drawStatusIcon", function(a) return a[1] == 0 and a[2] == 41 end)) shot("s3_learn_move_select") for _ = 1, 10 do if not SummaryMenu.isOpen() then break end U.tap(game, "b") U.wait(4) end SummaryMenu.openMenu(session.party, 1, { mode = "select_move", forgetMove = true, onSelectMove = function() end }) settle() shot("s3_forget_move_select") for _ = 1, 10 do if not SummaryMenu.isOpen() then break end U.tap(game, "b") U.wait(4) end SummaryMenu.openMenu(session.party, 2, {}) local peak = 0 for _ = 1, 12 do U.wait(1) if SummaryMenu._bounce.dy < peak then peak = SummaryMenu._bounce.dy end if peak <= -8 then break end end pass("s3 full hp pic bounces", peak <= -8, peak) shot("s3_plain_pic_bounce_peak") U.wait(60) pass("s3 bounce settles", SummaryMenu._bounce.dy == 0 and SummaryMenu._bounce.count >= 2) frame_calls() pass("s3 plain bg not shiny", called("drawBg3", function(a) return a[2] == false end)) shot("s3_plain_info_flipped_pic") local eps = SummaryChrome.manifest().eggPicShake pass("s3r egg shake tables from the cache", eps and #eps == 3 and #eps[3] == 15 and eps[3][7] == -2) U.tap(game, "down") settle() pass("s3 egg page", SummaryMenu._page == SummaryMenu.PAGE_EGG) pass("s3r egg shake vigor from friendship 5", SummaryMenu._bounce.egg and SummaryMenu._bounce.vigor == 2) shot("s3r_egg_state_box_text") local still, moved = true, false for i = 1, 90 do U.wait(1) if i < 50 and SummaryMenu._bounce.dx ~= 0 then still = false end if math.abs(SummaryMenu._bounce.dx) >= 2 then moved = true break end end pass("s3r egg holds still through the 60-frame delay", still) pass("s3r egg shakes", moved, SummaryMenu._bounce.dx) if moved then shot("s3r_egg_shake_midjiggle") end for _ = 1, 10 do if not SummaryMenu.isOpen() then break end U.tap(game, "b") U.wait(4) end SummaryMenu.openMenu(session.party, 1, {}) settle() local statused = SummaryMenu._bounce.count >= 2 and SummaryMenu._bounce.dy == 0 pass("s3 statused pic does not bounce", statused) for _ = 1, 10 do if not SummaryMenu.isOpen() then break end U.tap(game, "b") U.wait(4) end print(failures == 0 and "PASS game3_summary_pages_s3" or ("FAIL game3_summary_pages_s3 " .. failures)) love.event.quit(failures == 0 and 0 or 1) end return run