mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
221 lines
9.1 KiB
Lua
221 lines
9.1 KiB
Lua
#!/usr/bin/env luajit
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
require("tests.game3_cache").stubSpeciesNames()
|
|
require("tests.fixture_data.game3_items").install()
|
|
package.loaded["src.core.game3.rom_text"] = {
|
|
plain = function(key) return key end, box = function(key) return key end,
|
|
ascii = function(key) return key end, has = function() return true end,
|
|
key = function(n, i, j) return j and (n .. "[" .. i .. "][" .. j .. "]") or (n .. "[" .. i .. "]") end,
|
|
at = function(n, i, j) return j and (n .. "[" .. i .. "][" .. j .. "]") or (n .. "[" .. i .. "]") end,
|
|
count = function() return 0 end, list = function() return {} end,
|
|
lazy = function(map) return setmetatable({}, { __index = function(_, k) return map[k] end }) end,
|
|
}
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local function eq(a, b, msg)
|
|
check(a == b, string.format("%s (%s == %s)", msg, tostring(a), tostring(b)))
|
|
end
|
|
|
|
local TRADE_CENTER = "FR_TRADE_CENTER"
|
|
|
|
local function mon(species, level, personality, extra)
|
|
local m = {
|
|
species = species, level = level, hp = 30, maxHp = 30,
|
|
moves = { 33 }, pp = { 35 }, maxPp = { 35 },
|
|
personality = personality or (species * 7), nickname = "",
|
|
friendship = 120, otName = "RED", otId = 0x1234,
|
|
}
|
|
for k, v in pairs(extra or {}) do m[k] = v end
|
|
return m
|
|
end
|
|
|
|
local store = { flags = {}, vars = {} }
|
|
local session = {
|
|
store = store, map = TRADE_CENTER, x = 5, y = 8,
|
|
name = "RED", gender = 0, trainerId = 0x1234,
|
|
party = { mon(1, 10), mon(4, 12) },
|
|
bag = { pockets = { items = {} } },
|
|
}
|
|
local game = { data = { maps = {} }, session = session }
|
|
|
|
package.loaded["src.core.game3.runtime"] = {
|
|
getSession = function() return session end,
|
|
isActive = function() return true end,
|
|
_game = game,
|
|
_mod = nil,
|
|
}
|
|
package.loaded["src.core.game3.player"] = { cellX = 5, cellY = 8, facing = "up" }
|
|
package.loaded["src.core.game3.map"] = { load = function() end, current = TRADE_CENTER }
|
|
|
|
local ctx = { specialVars = {}, stringVars = {} }
|
|
local adapters = { log = function() end, playSe = function() end }
|
|
package.loaded["src.core.game3.scripting.space"] = {
|
|
store = store, mapId = TRADE_CENTER, vm = { ctx = ctx, adapters = adapters },
|
|
}
|
|
|
|
local Natives = require("src.core.game3.scripting.natives")
|
|
local NativesLink = require("src.core.game3.scripting.natives_link")
|
|
local Std = require("src.core.game3.scripting.stdscripts")
|
|
local Link = require("src.core.game3.link")
|
|
local LT = require("src.core.game3.link.trade")
|
|
local Union = require("src.core.game3.link.union_room")
|
|
local Status = require("src.core.game3.link.status")
|
|
local Trade = require("src.core.game3.scripting.natives_trade")
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
|
|
print("[test] 1. the trade specials answer to their pret index")
|
|
local EXPECTED = {
|
|
TryTradeLinkup = 0x1D,
|
|
EnterTradeSeat = 0x21,
|
|
StartWiredCableClubTrade = 0x22,
|
|
ShowWirelessCommunicationScreen = 0x16E,
|
|
}
|
|
for name, id in pairs(EXPECTED) do
|
|
eq(NativesLink.SPECIAL[name], id, "NativesLink.SPECIAL." .. name)
|
|
check(Natives.ALLOW["special:" .. id] ~= nil, name .. " is bound in Natives.ALLOW")
|
|
eq(Std.SPECIAL_NAME_BY_ID[id], name,
|
|
string.format("special 0x%X answers to its pret name", id))
|
|
end
|
|
-- pokefirered/include/link.h:73
|
|
eq(LT.LINKCMD.READY_TO_TRADE, 0xAABB, "LINKCMD_READY_TO_TRADE")
|
|
eq(LT.LINKCMD.INIT_BLOCK, 0xBBBB, "LINKCMD_INIT_BLOCK")
|
|
eq(LT.LINKCMD.START_TRADE, 0xCCDD, "LINKCMD_START_TRADE")
|
|
eq(LT.LINKCMD.CONFIRM_FINISH_TRADE, 0xDCBA, "LINKCMD_CONFIRM_FINISH_TRADE")
|
|
eq(LT.LINKCMD.SET_MONS_TO_TRADE, 0xDDDD, "LINKCMD_SET_MONS_TO_TRADE")
|
|
-- pokefirered/src/cable_club.c:527
|
|
eq(LT.LINKUP.linkType, 0x1133, "TryTradeLinkup asks for LINKTYPE_TRADE_SETUP")
|
|
eq(LT.LINKUP.min, 2, "and for exactly two players")
|
|
eq(LT.MSG.CONFIRM, "game3_trade_confirm", "the barrier confirm is game3_trade_confirm")
|
|
eq(LT.MSG.COMMIT, "trade_commit", "the relay answers trade_commit")
|
|
eq(LT.MSG.ABORT, "trade_abort", "or trade_abort")
|
|
|
|
print("[test] 2. the wireless communication status screen counts")
|
|
Link.reset()
|
|
LT.reset()
|
|
Union.reset()
|
|
local G = Status.GROUPTYPE
|
|
local counts = Status.counts({
|
|
{ activity = Union.ACTIVITY.TRADE },
|
|
{ activity = Union.ACTIVITY.BATTLE_SINGLE },
|
|
{ activity = Union.ACTIVITY.BATTLE_MULTI },
|
|
{ activity = Union.ACTIVITY.NONE + Union.IN_UNION_ROOM },
|
|
})
|
|
eq(counts[G.TRADE], 2, "a trading group is two people")
|
|
eq(counts[G.BATTLE], 6, "a single and a multi battle are six")
|
|
eq(counts[G.UNION], 1, "one player idling in the UNION ROOM")
|
|
eq(counts[G.TOTAL], 9, "and the total is trade plus battle plus union")
|
|
-- pokefirered/src/wireless_communication_status_screen.c:505
|
|
local wonder = Status.counts({ { activity = Union.ACTIVITY.WONDER_CARD } })
|
|
eq(wonder[G.TOTAL], 0,
|
|
"the retail total leaves WONDER CARD players out, as the cart does")
|
|
local chat = Status.counts({
|
|
{ activity = Union.ACTIVITY.CHAT + Union.IN_UNION_ROOM, members = 3 },
|
|
})
|
|
eq(chat[G.UNION], 3, "a chat group counts its own members")
|
|
local rows = Status.rows()
|
|
eq(#rows, 4, "the screen has four rows")
|
|
eq(rows[1].label, "sHeaderTexts[1]", "the first is the trading count (sHeaderTexts[GROUPTYPE_TRADE + 1])")
|
|
eq(rows[4].total, true, "and the last is the total")
|
|
|
|
print("[test] 3. the adapter answer and the screen the monitor opens")
|
|
Flags.setVar(store, ctx, Link.VAR_RESULT, 9)
|
|
local yieldW, value = Natives.special(ctx, NativesLink.SPECIAL.IsWirelessAdapterConnected, adapters)
|
|
eq(yieldW, false, "IsWirelessAdapterConnected does not yield")
|
|
eq(value, 0, "offline it answers FALSE, and the monitor says so")
|
|
local LinkMenu = require("src.ui.game3.link_menu")
|
|
eq(LinkMenu.isOpen(), false, "the status screen starts closed")
|
|
local closed = false
|
|
LinkMenu.show({ onClose = function() closed = true end })
|
|
eq(LinkMenu.isOpen(), true, "ShowWirelessCommunicationScreen puts it up")
|
|
eq(#LinkMenu.rows, 4, "with the four group counts on it")
|
|
LinkMenu.update(1 / 60)
|
|
eq(LinkMenu.palIdx, 0, "the wave palette does not move on the first frame")
|
|
for _ = 1, 6 do LinkMenu.update(1 / 60) end
|
|
eq(LinkMenu.palIdx, 1, "and steps once every six frames, as CyclePalette does")
|
|
eq(LinkMenu.countText(3), " 3", "counts are right aligned to two places")
|
|
LinkMenu.close()
|
|
eq(closed, true, "closing it hands the script back")
|
|
|
|
print("[test] 4. grid, HP-bar and level tile tables")
|
|
local Menu = require("src.ui.game3.link_trade_menu")
|
|
local full = {}
|
|
for i = 0, 12 do full[i] = true end
|
|
-- pokefirered/src/trade.c:349
|
|
eq(Menu.newCursorPosition(0, 4, full), 1, "0 RIGHT -> 1")
|
|
eq(Menu.newCursorPosition(1, 4, full), 6, "1 RIGHT -> 6")
|
|
eq(Menu.newCursorPosition(4, 2, full), 0, "4 DOWN wraps to 0")
|
|
eq(Menu.newCursorPosition(11, 2, full), 12, "11 DOWN -> CANCEL")
|
|
local twoEach = { [0] = true, [1] = true, [6] = true, [7] = true, [12] = true }
|
|
eq(Menu.newCursorPosition(12, 1, twoEach), 7, "CANCEL UP with two partner mons -> 7")
|
|
eq(Menu.newCursorPosition(5, 4, twoEach), 6, "an absent source still reads its row")
|
|
-- pokefirered/src/battle_interface.c:2165
|
|
eq(Menu.hpBarLevel(30, 30), 4, "full HP")
|
|
eq(Menu.hpBarLevel(20, 30), 3, "over half")
|
|
eq(Menu.hpBarLevel(10, 30), 2, "over a fifth")
|
|
eq(Menu.hpBarLevel(1, 100), 1, "one HP is still red")
|
|
eq(Menu.hpBarLevel(0, 30), 0, "fainted")
|
|
-- pokefirered/src/trade.c:2397
|
|
local lv5 = Menu.levelGenderTiles(mon(1, 5))
|
|
eq(lv5.tens, nil, "a one-digit level has no tens tile")
|
|
eq(lv5.ones, 0x75, "Lv5 ones tile")
|
|
local lv100 = Menu.levelGenderTiles(mon(1, 100))
|
|
eq(lv100.tens, 0x6A, "Lv100 uses the 10 tile")
|
|
eq(lv100.ones, 0x70, "and a 0")
|
|
check(lv100.symbol == 0x83 or lv100.symbol == 0x84 or lv100.symbol == 0x85, "gender tile is one of 0x83-0x85")
|
|
local egg = Menu.levelGenderTiles(mon(1, 5, nil, { isEgg = true }))
|
|
check(egg.egg and egg.ones == nil, "an egg prints no level")
|
|
eq(egg.symbol, 0x80, "and the egg symbol tile")
|
|
check(egg.symbolFlip, "drawn flipped")
|
|
-- pokefirered/src/trade.c:2339
|
|
eq(#Menu.movesLines(mon(1, 5)), 4, "four move rows")
|
|
eq(Menu.movesLines(mon(1, 5, nil, { isEgg = true }))[1], "gText_4Qmark", "an egg shows ????")
|
|
eq(LT.resumeMenu(), false, "resumeMenu only answers a canceled trade")
|
|
|
|
print("[test] 5. the barrier states keep the trade screen up until the commit")
|
|
Menu.reset()
|
|
LT.reset()
|
|
Menu.show()
|
|
Menu.cb = "idle"
|
|
for _, st in ipairs({ "exchange", "commit_wait" }) do
|
|
LT.state = st
|
|
Menu.update(0)
|
|
check(Menu.isOpen(), "the screen stays up in " .. st)
|
|
end
|
|
LT.state = "committed"
|
|
Menu.update(0)
|
|
check(not Menu.isOpen(), "trade_commit hands off to the trade scene")
|
|
Menu.reset()
|
|
LT.reset()
|
|
|
|
print("[test] 6. a received EGG is not entered in the POKeDEX")
|
|
do
|
|
local s = { party = { mon(1, 10), mon(4, 12) }, dex = { seen = {}, owned = {}, caught = {} } }
|
|
-- pokefirered/src/trade_scene.c:1036
|
|
Trade.tradeMons(s, 0, mon(152, 5, nil, { isEgg = true }))
|
|
eq(s.party[1].species, 152, "the egg is in the party")
|
|
check(not s.dex.seen[152], "its species is not seen")
|
|
check(not s.dex.owned[152] and not s.dex.caught[152], "and not caught")
|
|
Trade.tradeMons(s, 1, mon(155, 5))
|
|
check(s.dex.seen[155] == true, "a received mon still is")
|
|
end
|
|
|
|
Link.reset()
|
|
LT.reset()
|
|
Union.reset()
|
|
|
|
if failed == 0 then
|
|
print("[pass] link trade tables")
|
|
os.exit(0)
|
|
end
|
|
print("[FAIL] link trade tables: " .. failed .. " failed")
|
|
os.exit(1)
|