mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-03 16:16:38 -04:00
223 lines
9.8 KiB
Lua
223 lines
9.8 KiB
Lua
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
love = require("tests.love_stub")
|
|
|
|
local T = require("tests.harness")
|
|
local Game = require("src.core.Game")
|
|
local Game2 = require("src.core.Game2")
|
|
local Game3 = require("src.core.Game3")
|
|
local StateStack = require("src.core.StateStack")
|
|
local FixedStep = require("src.core.FixedStep")
|
|
local Stack3 = require("src.ui.game3.stack")
|
|
local battleActive = false
|
|
package.loaded["src.core.game3.battle"] = { isActive = function() return battleActive end }
|
|
|
|
local g = setmetatable({
|
|
save = { party = {}, player = { name = "RED" }, inventory = {},
|
|
flags = {}, pcItems = {}, pokedex = { seen = {}, owned = {} },
|
|
options = { speedOverworld = 4, speedBattle = 10, speedMenu = 2 } },
|
|
data = { pokemon = {}, items = {}, maps = {}, text = {}, field = {} },
|
|
input = { wasPressed = function() return false end },
|
|
}, { __index = Game })
|
|
g.stack = setmetatable({}, { __index = StateStack })
|
|
g.stack:init()
|
|
local overworld, battle = { isOverworld = true }, { isBattle = true }
|
|
g.stack:push(overworld)
|
|
|
|
g.data.pokemon.PIKACHU = { id = "PIKACHU", dex = 25 }
|
|
local constructors = {
|
|
StartMenu = {}, PartyMenu = {}, BagMenu = {}, OptionsMenu = {},
|
|
PokedexMenu = {}, TrainerCard = {}, BoxMenu = {}, PlayerPC = {},
|
|
LeaguePC = {}, NamingScreen = {}, FlyMenu = {}, TownMap = {},
|
|
DexEntryMenu = { "PIKACHU" }, SummaryMenu = { { species = "PIKACHU", moves = {} } },
|
|
PrizeCounter = { {} },
|
|
}
|
|
for name, args in pairs(constructors) do
|
|
local screen = require("src.ui." .. name).new(g, unpack(args))
|
|
T.eq(screen.isMenu, true, name .. " returned instance is a menu owner")
|
|
g.stack:push(screen)
|
|
T.eq(g:logicSpeed(), 2, name .. " uses MENU SPEED over the overworld")
|
|
g.stack:push({})
|
|
T.eq(g:logicSpeed(), 2, name .. " nested dialogue inherits MENU SPEED")
|
|
g.stack:pop()
|
|
g.stack:pop()
|
|
T.eq(g:logicSpeed(), 4, name .. " pop restores OVERWORLD SPEED")
|
|
end
|
|
|
|
local shop = require("src.ui.ShopMenu").new(g, {})
|
|
T.eq(shop.isMenu, true, "ShopMenu actual returned generic instance owns MENU SPEED")
|
|
T.eq(Game.speedCategoryInStack({ states = { overworld, shop, {} } }), "menu",
|
|
"shop greetings and nested item lists inherit the concrete menu owner")
|
|
|
|
local Menu = require("src.ui.Menu")
|
|
local OW = require("src.world.OverworldController")
|
|
local owGameIndex, owGame
|
|
for i = 1, 100 do
|
|
local name, value = debug.getupvalue(OW.openPC, i)
|
|
if not name then break end
|
|
if name == "Game" then owGameIndex, owGame = i, value; break end
|
|
end
|
|
assert(owGameIndex, "openPC Game binding absent")
|
|
debug.setupvalue(OW.openPC, owGameIndex, g)
|
|
local baseInput, pressed = g.input, nil
|
|
g.input = { wasPressed = function(_, key) return pressed == key end,
|
|
isDown = function() return false end }
|
|
local function tap(screen, key)
|
|
pressed = key
|
|
screen:update(1 / 60)
|
|
pressed = nil
|
|
end
|
|
local function advanceToMenu()
|
|
for _ = 1, 600 do
|
|
local top = g.stack:top()
|
|
if getmetatable(top) == Menu then return top end
|
|
tap(top, "a")
|
|
end
|
|
error("actual interactive PC menu was not reached")
|
|
end
|
|
|
|
OW:openPC()
|
|
T.eq(g:logicSpeed(), 4, "PC opening text retains OVERWORLD SPEED")
|
|
local pc = advanceToMenu()
|
|
T.eq(#pc.items >= 3 and pc.noSound, true, "actual main PC chooser is reached")
|
|
T.eq(pc.isMenu, true, "main PC chooser concrete instance owns MENU SPEED")
|
|
T.eq(Game.speedCategoryInStack(g.stack), "menu", "main PC chooser category is menu")
|
|
T.eq(g:logicSpeed(), 2, "actual main PC chooser uses MENU SPEED")
|
|
pc.index = 2
|
|
tap(pc, "a")
|
|
T.eq(g.stack:top().isTextBox, true, "main PC chooser opens actual player PC access text")
|
|
T.eq(g:logicSpeed(), 2, "player PC access text inherits MENU SPEED")
|
|
local playerPC = advanceToMenu()
|
|
T.eq(playerPC ~= pc and #playerPC.items == 4, true, "actual player PC submenu is reached")
|
|
T.eq(g:logicSpeed(), 2, "player PC submenu uses MENU SPEED")
|
|
tap(playerPC, "b")
|
|
T.eq(g.stack:top(), pc, "player PC back returns the same main chooser")
|
|
T.eq(g:logicSpeed(), 2, "returned main PC chooser retains MENU SPEED")
|
|
tap(pc, "b")
|
|
T.eq(g.stack:top(), overworld, "main PC cancel returns to field")
|
|
T.eq(g:logicSpeed(), 4, "main PC cancel restores OVERWORLD SPEED")
|
|
|
|
for i, id in ipairs({ "EEVEE", "FLAREON", "JOLTEON", "VAPOREON" }) do
|
|
g.data.pokemon[id] = { id = id, name = id, dex = 132 + i }
|
|
end
|
|
OW:billsHousePokemonList()
|
|
T.eq(g:logicSpeed(), 4, "Bill viewer opening text retains OVERWORLD SPEED")
|
|
local bill = advanceToMenu()
|
|
T.eq(#bill.items == 5 and bill.items[1].keepOpen, true, "actual Bill PC viewer list is reached")
|
|
T.eq(bill.isMenu, true, "Bill PC viewer concrete instance owns MENU SPEED")
|
|
T.eq(Game.speedCategoryInStack(g.stack), "menu", "Bill PC viewer category is menu")
|
|
T.eq(g:logicSpeed(), 2, "actual Bill PC viewer uses MENU SPEED")
|
|
tap(bill, "a")
|
|
T.eq(getmetatable(g.stack:top()), require("src.ui.DexEntryMenu"),
|
|
"Bill viewer selection opens the actual DexEntryMenu")
|
|
T.eq(g.save.pokedex.seen.EEVEE, true, "Bill viewer preserves the selected species seen flag")
|
|
T.eq(g:logicSpeed(), 2, "Bill viewer nested DexEntryMenu uses MENU SPEED")
|
|
for _ = 1, 600 do
|
|
if g.stack:top() == bill then break end
|
|
tap(g.stack:top(), "b")
|
|
end
|
|
T.eq(g.stack:top(), bill, "DexEntryMenu back returns the same Bill viewer")
|
|
T.eq(g:logicSpeed(), 2, "returned Bill PC viewer retains MENU SPEED")
|
|
tap(bill, "b")
|
|
T.eq(g.stack:top(), overworld, "Bill viewer cancel returns to field")
|
|
T.eq(g:logicSpeed(), 4, "Bill viewer cancel restores OVERWORLD SPEED")
|
|
|
|
g.input = baseInput
|
|
debug.setupvalue(OW.openPC, owGameIndex, owGame)
|
|
local generic = Menu.new(g, { { label = "CHOICE" } })
|
|
T.eq(generic.isMenu, nil, "generic Menu remains transparent")
|
|
g.stack:push(generic)
|
|
T.eq(g:logicSpeed(), 4, "unowned generic choice retains OVERWORLD SPEED")
|
|
g.stack:pop()
|
|
|
|
for _, name in ipairs({ "PartyMenu", "BagMenu" }) do
|
|
g.stack:push(battle)
|
|
local screen = require("src.ui." .. name).new(g, { battle = { playerParty = {} } })
|
|
g.stack:push(screen)
|
|
T.eq(g:logicSpeed(), 2, "battle " .. name .. " uses MENU SPEED")
|
|
g.stack:pop()
|
|
T.eq(g:logicSpeed(), 10, "battle " .. name .. " pop restores BATTLE SPEED")
|
|
g.stack:push({})
|
|
T.eq(g:logicSpeed(), 10, "battle dialogue stays at BATTLE SPEED")
|
|
g.stack:pop()
|
|
g.stack:pop()
|
|
end
|
|
|
|
local party = require("src.ui.PartyMenu").new(g)
|
|
g.stack:push(party)
|
|
local function ticks(speed)
|
|
g.save.options.speedMenu = speed
|
|
party.blink = 0
|
|
FixedStep.clock = function() return 0 end
|
|
FixedStep.refreshPeriod = nil
|
|
FixedStep:init(function(dt) party:update(dt) end)
|
|
local multiplier = g:logicSpeed()
|
|
FixedStep.maxAccum = FixedStep.catchupLimit(multiplier, 1 / 60)
|
|
for _ = 1, 60 do FixedStep:update(1 / 60, multiplier) end
|
|
return party.blink
|
|
end
|
|
T.eq(ticks(1), 60, "real party advances 60 logic ticks per second at MENU SPEED 1")
|
|
T.eq(ticks(4), 240, "real party advances 240 logic ticks per second at MENU SPEED 4")
|
|
g.speedOverride = 20
|
|
T.eq(g:logicSpeed(), 20, "run override still wins over a menu")
|
|
g.linkSession = true
|
|
T.eq(g:logicSpeed(), 1, "link lock still wins over menu and override")
|
|
g.linkSession = nil
|
|
g.stack:push({ isFixedSpeed = true })
|
|
T.eq(g:logicSpeed(), 1, "minigame lock still wins over menu and override")
|
|
g.stack:pop()
|
|
g.stack:pop()
|
|
|
|
local g3 = setmetatable({ phase = "field",
|
|
options = { speedOverworld = 4, speedBattle = 10, speedMenu = 2 } }, { __index = Game3 })
|
|
Stack3.clear()
|
|
for _, name in ipairs({ "start_menu", "party_menu", "bag_menu", "option_menu", "pokedex",
|
|
"trainer_card", "summary_menu", "box_storage_ui", "pc_menu", "item_pc",
|
|
"hall_of_fame_pc", "naming", "region_map", "tm_case", "berry_pouch", "save_menu",
|
|
"fame_checker", "controls_menu", "mod_manager", "rse.option_menu", "rse.item_storage",
|
|
"rse.mailbox", "shop_menu", "daycare_menu", "prize_corner", "move_relearner", "easy_chat",
|
|
"rse.move_relearner", "rse.pokeblock_case", "rse.berry_tag", "rse.frontier_pass", "rse.pyramid_bag" }) do
|
|
local mod = require("src.ui.game3." .. name)
|
|
Stack3.push(name, mod, { fullscreen = false })
|
|
T.eq(g3:speedCategory(), "menu", name .. " owns the actual non-fullscreen layer")
|
|
T.eq(g3:logicSpeed(), 2, name .. " uses MENU SPEED")
|
|
Stack3.push("dialogue", {}, { fullscreen = true })
|
|
T.eq(g3:logicSpeed(), 2, name .. " nested text inherits menu speed")
|
|
Stack3.pop("dialogue")
|
|
Stack3.pop(name)
|
|
T.eq(g3:logicSpeed(), 4, name .. " pop restores field speed")
|
|
end
|
|
for _, name in ipairs({ "pokedex", "region_map", "pokenav.init" }) do
|
|
local mod = require("src.ui.game3.rse." .. name).Host
|
|
Stack3.push(name, mod)
|
|
T.eq(g3:logicSpeed(), 2, "RSE " .. name .. " actual delegated Host owns MENU SPEED")
|
|
Stack3.pop(name)
|
|
end
|
|
for _, name in ipairs({ "party_menu", "bag_menu" }) do
|
|
battleActive = true
|
|
Stack3.push(name, require("src.ui.game3." .. name), { fullscreen = false })
|
|
T.eq(g3:logicSpeed(), 2, "Gen3 battle " .. name .. " uses MENU SPEED")
|
|
Stack3.pop(name)
|
|
T.eq(g3:logicSpeed(), 10, "Gen3 battle " .. name .. " pop restores BATTLE SPEED")
|
|
end
|
|
Stack3.push("battle_message", {}, { fullscreen = true })
|
|
T.eq(g3:logicSpeed(), 10, "Gen3 unmarked fullscreen battle text stays at BATTLE SPEED")
|
|
Stack3.clear()
|
|
battleActive = false
|
|
Stack3.push("scene", {}, { fullscreen = true })
|
|
T.eq(g3:logicSpeed(), 4, "Gen3 unmarked field scene stays at OVERWORLD SPEED")
|
|
Stack3.clear()
|
|
Stack3.push("party", require("src.ui.game3.party_menu"))
|
|
g3.speedOverride = 20
|
|
T.eq(g3:logicSpeed(), 20, "Gen3 run override wins over menu")
|
|
package.loaded["src.core.game3.link"] = { link = {} }
|
|
T.eq(g3:logicSpeed(), 1, "Gen3 link lock wins over menu and override")
|
|
package.loaded["src.core.game3.link"] = nil
|
|
package.loaded["src.core.game3.minigames.common"] = { isActive = function() return true end }
|
|
T.eq(g3:logicSpeed(), 1, "Gen3 minigame lock wins over menu and override")
|
|
package.loaded["src.core.game3.minigames.common"] = nil
|
|
Stack3.clear()
|
|
|
|
local g2 = setmetatable({ options = { speed = 4, speedOverworld = 1, speedMenu = 10 } }, { __index = Game2 })
|
|
T.eq(g2:logicSpeed(), 4, "Gen2 retains legacy GAME SPEED")
|
|
T.finish("menu speed bug 2578")
|