#!/usr/bin/env luajit -- ../pokefirered/src/pokedex_screen.c:407-435, :1031-1035 package.path = "./?.lua;./?/init.lua;" .. package.path require("tests.game3_cache").mountOrSkip("dex table of contents") local failed = 0 local function eq(a, b, msg) if a == b then print("[ok] " .. msg) else failed = failed + 1 print(string.format("[FAIL] %s (%s ~= %s)", msg, tostring(a), tostring(b))) end end local function check(cond, msg) eq(cond and true or false, true, msg) end require("src.core.GameVersion").set("firered") package.loaded["src.core.game3.audio"] = { playCry = function() end, playSe = function() end, playSong = function() end, stopAll = function() end, } local Dex = require("src.core.game3.dex") local Pokemon = require("src.core.game3.pokemon") local Pokedex = require("src.ui.game3.pokedex") local PokedexChrome = require("src.ui.game3.pokedex_chrome") local FrlgFont = require("src.ui.game3.frlg_font") Pokemon.install(nil) local MAX_SHOWED = 9 local realLove = love love = { graphics = { setColor = function() end, rectangle = function() end, polygon = function() end, circle = function() end, line = function() end, draw = function() end, print = function() end, getScissor = function() return nil end, setScissor = function() end, }, } local saved = { paper = PokedexChrome.drawPaperBg, header = PokedexChrome.drawHeader, control = PokedexChrome.drawControlInfo, icon = PokedexChrome.drawCategoryIcon, up = PokedexChrome.drawUpArrow, down = PokedexChrome.drawDownArrow, font = FrlgFont.draw, } local arrows, icons PokedexChrome.drawPaperBg = function() end PokedexChrome.drawHeader = function() end PokedexChrome.drawControlInfo = function() end FrlgFont.draw = function() end PokedexChrome.drawCategoryIcon = function(key, x, y) icons[#icons + 1] = { key = key, x = x, y = y } end PokedexChrome.drawUpArrow = function(x, y) arrows[#arrows + 1] = { dir = "up", x = x, y = y } end PokedexChrome.drawDownArrow = function(x, y) arrows[#arrows + 1] = { dir = "down", x = x, y = y } end local function restore() PokedexChrome.drawPaperBg = saved.paper PokedexChrome.drawHeader = saved.header PokedexChrome.drawControlInfo = saved.control PokedexChrome.drawCategoryIcon = saved.icon PokedexChrome.drawUpArrow = saved.up PokedexChrome.drawDownArrow = saved.down FrlgFont.draw = saved.font love = realLove end local function render() arrows, icons = {}, {} Pokedex.draw() local up, down for _, a in ipairs(arrows) do if a.dir == "up" then up = a else down = a end end return up, down end local input = { _pressed = {}, wasPressed = function(self, key) return self._pressed[key] == true end, press = function(self, key) self._pressed = { [key] = true } end, } local function openToc() local dex = Dex.new() Pokedex.show(dex, { session = { dex = dex } }) return dex end print("[test] 1. The table of contents opens at the top of the list") do openToc() eq(Pokedex.screen, "mode_select", "the pokedex opens on the table of contents") eq(Pokedex.modeScroll, 0, "the list starts unscrolled") check(#Pokedex.MODES > MAX_SHOWED, "the table of contents is longer than the window") end print("[test] 2. At the top of the list only the down arrow is drawn") do local up, down = render() eq(up, nil, "no up arrow at scroll 0") check(down ~= nil, "the down arrow is drawn at scroll 0") eq(down and down.x, 200, "the down arrow sits at secondX 200") eq(down and down.y, 141, "the down arrow sits at secondY 141") end print("[test] 3. The category icon keeps its pret window origin") do render() local icon = icons[1] check(icon ~= nil, "the selected mode draws a category icon") eq(icon and icon.x, 168, "sWindowTemplate_SelectionIcon tilemapLeft 21 is x 168") eq(icon and icon.y, 88, "sWindowTemplate_SelectionIcon tilemapTop 11 is y 88") end print("[test] 4. Scrolling into the middle draws both arrows") do local guard = 0 while Pokedex.modeScroll == 0 and guard < 64 do input:press("down") Pokedex.handleInput(input) guard = guard + 1 end check(Pokedex.modeScroll > 0, "the cursor scrolled the list") local up, down = render() check(up ~= nil, "the up arrow appears once the list has scrolled") eq(up and up.x, 200, "the up arrow sits at firstX 200") eq(up and up.y, 19, "the up arrow sits at firstY 19") check(down ~= nil, "the down arrow is still drawn mid-list") end print("[test] 5. At the bottom of the list only the up arrow is drawn") do local guard = 0 while Pokedex.modeScroll < #Pokedex.MODES - MAX_SHOWED and guard < 64 do input:press("down") Pokedex.handleInput(input) guard = guard + 1 end eq(Pokedex.modeScroll, #Pokedex.MODES - MAX_SHOWED, "the list is scrolled to the end") local up, down = render() check(up ~= nil, "the up arrow is drawn at the end of the list") eq(down, nil, "no down arrow at the fullyDown threshold") end print("[test] 6. No arrow is ever drawn inside the category icon window") do openToc() local inside, frames = 0, 0 for _ = 1, 64 do render() frames = frames + 1 for _, a in ipairs(arrows) do if a.x >= 168 and a.x < 232 and a.y >= 88 and a.y < 136 then inside = inside + 1 end end input:press("down") Pokedex.handleInput(input) end check(frames > 0, "the table of contents was walked top to bottom") eq(inside, 0, "no scroll arrow lands inside the 64x48 icon window") end print("[test] 7. The Kanto table of contents carries pret's 19 rows") do -- ../pokefirered/src/pokedex_screen.c:319-340, :363-384, :407-419 openToc() eq(#Pokedex.MODES, 19, "sListMenuItems_KantoDexModeSelect has 19 rows") eq(#Pokedex.MODES - MAX_SHOWED, 10, "fullyDownThreshold is 10 on a Kanto save") local labels, ids = {}, {} for _, m in ipairs(Pokedex.MODES) do labels[#labels + 1] = tostring(m.label) if m.id then ids[m.id] = m end end eq(labels[1], "POKéMON LIST", "row 1 is the POKéMON LIST header") eq(labels[2], "NUMERICAL MODE", "the Kanto list has a single NUMERICAL MODE row") eq(labels[3], "POKéMON HABITATS", "row 3 is the POKéMON HABITATS header") eq(labels[13], "SEARCH", "row 13 is the SEARCH header") eq(labels[18], "OTHER", "row 18 is the OTHER header") eq(labels[19], "CLOSE POKéDEX", "row 19 closes the pokedex") -- ../pokefirered/src/pokedex_screen.c:1191-1196 greys locked categories only for _, id in ipairs({ "atoz", "type", "lightest", "smallest" }) do check(ids[id] ~= nil, "the Kanto list keeps the " .. id .. " row") eq(ids[id] and ids[id].unlocked, true, "and prints it unlocked") end eq(ids.grassland and ids.grassland.unlocked, false, "a locked habitat is still greyed") local dex = Dex.new() dex.nationalUnlocked = true Pokedex.show(dex, { session = { dex = dex } }) eq(#Pokedex.MODES, 20, "sListMenuItems_NatDexModeSelect has 20 rows") eq(#Pokedex.MODES - MAX_SHOWED, 11, "fullyDownThreshold is 11 with the national dex") Pokedex.close() end print("[test] 8. The list scrolls on pret's midpoint rule and walks back to the top") do -- ../pokefirered/src/list_menu.c:438-516 openToc() local outside = 0 local function inWindow() if Pokedex.modeCursor < Pokedex.modeScroll + 1 or Pokedex.modeCursor > Pokedex.modeScroll + MAX_SHOWED then outside = outside + 1 end end eq(Pokedex.modeScroll, 0, "the list opens at scroll 0") for _ = 1, 3 do input:press("down") Pokedex.handleInput(input) inWindow() end eq(Pokedex.modeScroll, 0, "the first three steps stay above the midpoint row") eq(Pokedex.modeCursor, 6, "the cursor reached row 6 of the window") input:press("down") Pokedex.handleInput(input) inWindow() eq(Pokedex.modeScroll, 1, "the fourth step scrolls instead of moving the cursor down") eq(Pokedex.modeCursor, 7, "and the cursor holds the midpoint row") for _ = 1, 40 do input:press("down") Pokedex.handleInput(input) inWindow() end eq(Pokedex.modeCursor, 19, "walking down lands on CANCEL") eq(Pokedex.modeScroll, 10, "and parks the list at the fullyDown threshold") local up, down = render() check(up ~= nil, "the up arrow is drawn at the bottom") eq(down, nil, "the down arrow is gone at the bottom") for _ = 1, 40 do input:press("up") Pokedex.handleInput(input) inWindow() end eq(Pokedex.modeScroll, 0, "walking back up returns the list to scroll 0") eq(Pokedex.modeCursor, 2, "and the cursor to NUMERICAL MODE") eq(outside, 0, "the cursor never leaves the nine visible rows") up, down = render() eq(up, nil, "no up arrow once the header is back on screen") check(down ~= nil, "the down arrow is back") end Pokedex.close() restore() if failed > 0 then print(string.format("\n[FAILED] %d check(s) failed", failed)) os.exit(1) end print("\n[test] all passed")