mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
170 lines
6.8 KiB
Lua
170 lines
6.8 KiB
Lua
-- Two things only a human can see, in one run.
|
|
--
|
|
-- POKEPORT_IDENTITY=gold-dev POKEPORT_GAME=gold \
|
|
-- POKEPORT_DRIVER=tests/drivers/gold_naming_and_trade_item.lua \
|
|
-- perl -e 'alarm 300; exec @ARGV' \
|
|
-- python3 -c "import pty; pty.spawn(['love','.'])"
|
|
--
|
|
-- Only the gold-dev identity has a complete Gold cache; another one is missing
|
|
-- data/generated/marts.lua, RomImporter never reports ready, and the driver
|
|
-- coroutine is simply never resumed (a silent hang with no output).
|
|
--
|
|
-- 1. The naming keyboard. Typing the LAST character does not close the screen:
|
|
-- `.a` is `call NamingScreen_TryAddCharacter / ret nc`, and
|
|
-- AdvanceCursor_CheckEndOfString answers CARRY once the buffer is full, so
|
|
-- the handler falls through into `.start` and parks the cursor on END with
|
|
-- the keyboard still up (engine/menus/naming_screen.asm:401-410). Only
|
|
-- `.end` stores the entry. The blank cells are typeable too: the NameInput*
|
|
-- rows are written into the tilemap and GetLastCharacter reads the tile
|
|
-- under the cursor back out, so the trailing spaces of "S T U V W X Y Z "
|
|
-- are real characters (data/text/name_input_chars.asm).
|
|
--
|
|
-- 2. Kyle's Onix (VioletKylesHouse, NPC_TRADE_KYLE) arrives holding
|
|
-- BITTER_BERRY. NPCTRADE_ITEM is an item id BYTE in the table
|
|
-- (data/events/npc_trades.asm:15) and DoNPCTrade copies it into
|
|
-- wPartyMon1Item; the port names it, so the summary's green page prints
|
|
-- BITTER BERRY and TAKE drops a real BITTER BERRY into the bag instead of
|
|
-- killing the game in Bag.isBadge.
|
|
--
|
|
-- Screenshots land in POKEPORT_SHOT_DIR (default /tmp/gold-naming-trade):
|
|
-- keyboard-parked-on-end.png full buffer, cursor bracketing END
|
|
-- keyboard-on-blank-cell.png the cursor sitting on the blank after Z
|
|
-- keyboard-typed-a-space.png a name with a space in the middle of it
|
|
-- onix-summary-item.png the green page's ITEM field
|
|
-- onix-item-taken.png "TOOK BITTER BERRY from ROCKY."
|
|
local U = require("tests.drivers.util")
|
|
|
|
local Mon = require("src.battle.gen2.Mon")
|
|
local NpcTrade = require("src.core.gen2.NpcTrade")
|
|
local Screens = require("src.ui.Screens")
|
|
local SummaryMenu = require("src.ui.gen2.SummaryMenu")
|
|
|
|
return function(game)
|
|
local out = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/gold-naming-trade"
|
|
local fails = 0
|
|
local function ok(cond, msg)
|
|
if cond then print("[naming] ok " .. msg)
|
|
else fails = fails + 1 print("[naming] FAIL " .. msg) end
|
|
return cond
|
|
end
|
|
|
|
local function tap(btn) U.tap(game, btn) U.wait(3) end
|
|
local function top() return game.stack:top() end
|
|
|
|
U.wait(45)
|
|
ok(game.world and game.world.map, "gold world booted")
|
|
|
|
-- ---------------------------------------------------------- the keyboard
|
|
local typed
|
|
Screens.push(game, "Gen2NamingScreen", {
|
|
type = "rival",
|
|
menuGfx = game.data.gen2MenuGfx,
|
|
-- The pop is the caller's, exactly as World:nameRival does it.
|
|
onDone = function(name) game.stack:pop() typed = name end,
|
|
})
|
|
U.wait(10)
|
|
local keyboard = top()
|
|
if not ok(keyboard and keyboard.text == "", "the rival keyboard opened") then
|
|
error("gold naming: no keyboard, cannot continue")
|
|
end
|
|
|
|
-- Seven A presses on the A key fill a 7-character rival name.
|
|
for _ = 1, keyboard.maxLength do tap("a") end
|
|
ok(top() == keyboard, "a full buffer leaves the keyboard up")
|
|
ok(typed == nil, "and hands nothing back yet")
|
|
ok(keyboard:cursorCharacter() == "END", "the cursor parked itself on END")
|
|
U.shot(game, out .. "/keyboard-parked-on-end.png")
|
|
|
|
-- The blank cell after Z types a space. Back off two characters so the
|
|
-- buffer has room for a space AND a letter after it (a name with a gap in
|
|
-- the middle is the only way to see the space at all), then walk up out of
|
|
-- the bottom row to row 2, column 8.
|
|
tap("b")
|
|
tap("b")
|
|
tap("up")
|
|
tap("up")
|
|
tap("right")
|
|
tap("right")
|
|
ok(keyboard:cursorCharacter() == " ", "the cell after Z is a space")
|
|
U.shot(game, out .. "/keyboard-on-blank-cell.png")
|
|
tap("a")
|
|
ok(keyboard.text:sub(-1) == " ", "and A types it into the name")
|
|
-- Up twice from (8,2) is the I key, so the field ends up reading "AAAAA I".
|
|
tap("up")
|
|
tap("up")
|
|
tap("a")
|
|
ok(keyboard.text == "AAAAA I", "the space really is in the stored name")
|
|
U.shot(game, out .. "/keyboard-typed-a-space.png")
|
|
|
|
-- Only A on END ends entry.
|
|
tap("start")
|
|
tap("a")
|
|
ok(typed ~= nil and #typed == keyboard.maxLength,
|
|
"A on END is what stores the entry")
|
|
U.wait(5)
|
|
|
|
-- ------------------------------------------------------- Kyle's Onix
|
|
-- data/generated/events.lua, which World loads as its own eventTables.
|
|
local row = NpcTrade.row(game.world.eventTables, 1)
|
|
if not ok(row and row.get == "ONIX", "the cache carries NPC_TRADE_KYLE") then
|
|
error("gold naming: no trade row, cannot continue")
|
|
end
|
|
local save = game.save
|
|
save.party = { Mon.new(game.data, "BELLSPROUT", 12) }
|
|
local _, onix = NpcTrade.perform(game.data, save, row, 1)
|
|
ok(onix and onix.nickname == "ROCKY", "the trade handed ROCKY over")
|
|
ok(onix and onix.item == "BITTER_BERRY",
|
|
"wearing a NAMED BITTER_BERRY, not the table's byte 83")
|
|
|
|
-- START > POKeMON > A > STATS, then the green page.
|
|
tap("start")
|
|
local menu = top()
|
|
for _ = 1, 10 do
|
|
if menu.list:current().value == "pokemon" then break end
|
|
tap("down")
|
|
end
|
|
tap("a")
|
|
local party = top()
|
|
if not ok(party and party.screenId == "Gen2PartyMenu",
|
|
"the party list opened") then
|
|
error("gold naming: no party list, cannot continue")
|
|
end
|
|
tap("a")
|
|
tap("a") -- STATS leads the submenu
|
|
local summary = top()
|
|
ok(summary and summary.screenId == "Gen2SummaryMenu", "STATS opened STATS")
|
|
tap("right") -- page 1 (pink) -> page 2 (green), which is the ITEM page
|
|
U.wait(5)
|
|
local placed = summary and summary:placements()
|
|
local text = {}
|
|
for _, p in ipairs(placed or {}) do text[#text + 1] = tostring(p.text or "") end
|
|
ok(table.concat(text, "|"):find("BITTER BERRY", 1, true) ~= nil,
|
|
"the green page prints BITTER BERRY, not 83")
|
|
U.shot(game, out .. "/onix-summary-item.png")
|
|
tap("b")
|
|
|
|
-- ITEM > TAKE. This is the press that used to crash in Bag.isBadge.
|
|
tap("a")
|
|
local submenu = party and party.submenu
|
|
for _ = 1, 8 do
|
|
if submenu and submenu.items[submenu.index]
|
|
and submenu.items[submenu.index].id == "ITEM" then break end
|
|
tap("down")
|
|
submenu = party and party.submenu
|
|
end
|
|
ok(submenu and submenu.items[submenu.index]
|
|
and submenu.items[submenu.index].id == "ITEM", "the cursor found ITEM")
|
|
tap("a")
|
|
local held = top()
|
|
ok(held and held.screenId == "Gen2HeldItemMenu", "GIVE / TAKE opened")
|
|
tap("down")
|
|
tap("a")
|
|
U.wait(5)
|
|
ok(save.party[1].item == nil, "TAKE pulled the berry off")
|
|
ok((save.inventory or {}).BITTER_BERRY == 1, "and it landed in the bag")
|
|
U.shot(game, out .. "/onix-item-taken.png")
|
|
|
|
print(("[naming] %d failure(s)"):format(fails))
|
|
love.event.quit()
|
|
end
|