mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 05:32:07 -04:00
237 lines
8.7 KiB
Lua
237 lines
8.7 KiB
Lua
#!/usr/bin/env luajit
|
|
-- Game3 bag: pret ItemSlot pockets, items pack, checkitem APIs, save migrate.
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
require("tests.game3_cache").requireData("game3_bag_test")
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local ItemsData = require("src.core.game3.items_data")
|
|
local Bag = require("src.core.game3.bag")
|
|
local Schema = require("src.core.game3.save_schema_firered")
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
local Ops = require("src.core.game3.scripting.ops_a")
|
|
local Vm = require("src.core.game3.scripting.vm")
|
|
|
|
print("[test] 1. Items pack load")
|
|
ItemsData.install(nil)
|
|
local potion = ItemsData.info(13)
|
|
check(potion ~= nil and potion.name == "POTION", "POTION id 13 from pack/fallback")
|
|
check(ItemsData.pocketOf(13) == "ITEMS", "POTION pocket ITEMS")
|
|
check(ItemsData.pocketResult(13) == 1, "pocketResult ITEMS=1")
|
|
check(ItemsData.pocketResult(4) == 3, "POKE_BALL pocketResult=3")
|
|
check(ItemsData.CAPACITY.ITEMS == 42, "ITEMS capacity 42")
|
|
check(ItemsData.CAPACITY.KEY_ITEMS == 30, "KEY capacity 30")
|
|
check(ItemsData.displayName(364) == "TM CASE" or ItemsData.displayName(364):find("TM"), "TM CASE name")
|
|
|
|
print("[test] 2. Bag.add / canAdd / has / listPocket")
|
|
local bag = Bag.new()
|
|
check(Bag.canAdd(bag, 13, 1) == true, "empty bag can add POTION")
|
|
local ok = select(1, Bag.add(bag, 13, 5))
|
|
check(ok == true, "add 5 POTION")
|
|
check(Bag.get(bag, 13) == 5, "get POTION qty 5")
|
|
check(Bag.has(bag, 13, 5) == true, "has 5 POTION")
|
|
check(Bag.has(bag, 13, 6) == false, "not has 6 POTION")
|
|
local rows = Bag.listPocket(bag, "ITEMS")
|
|
check(#rows == 1 and rows[1].id == 13 and rows[1].qty == 5, "listPocket ITEMS slot order")
|
|
|
|
print("[test] 3. Capacity 42 + TM Case auto-grant")
|
|
bag = Bag.new()
|
|
for i = 1, 42 do
|
|
Bag.add(bag, 12 + i, 1) -- 13..54
|
|
end
|
|
check(#bag.pockets.ITEMS == 42, "filled 42 ITEMS slots")
|
|
check(Bag.canAdd(bag, 55, 1) == false, "43rd unique ITEMS item fails")
|
|
check(select(1, Bag.add(bag, 13, 1)) == true, "stack into existing POTION still ok")
|
|
|
|
bag = Bag.new()
|
|
ok = select(1, Bag.add(bag, 289, 1)) -- TM01
|
|
check(ok == true, "add TM01")
|
|
check(Bag.has(bag, ItemsData.ITEM_TM_CASE, 1) == true, "TM CASE auto-granted to KEY_ITEMS")
|
|
check(#Bag.listPocket(bag, "TM_CASE") == 1, "TM in TM_CASE pocket")
|
|
|
|
print("[test] 4. Migrate stacks + schema newGame")
|
|
local legacy = { stacks = { POTION = 3, [4] = 2 } }
|
|
local mig = Bag.migrate(legacy)
|
|
check(Bag.get(mig, 13) >= 3 or Bag.get(mig, "POTION") >= 3, "migrate POTION stacks")
|
|
check(mig.pockets and mig.pockets.ITEMS, "migrate has pockets")
|
|
|
|
local session = Schema.newGame()
|
|
check(session.bag and session.bag.pockets and session.bag.pockets.ITEMS, "newGame bag pockets")
|
|
local loaded = Schema.fromSaveTable({
|
|
bag = { stacks = { POTION = 7 } },
|
|
name = "ASH",
|
|
})
|
|
check(Bag.get(loaded.bag, 13) == 7 or Bag.get(loaded.bag, "POTION") == 7, "fromSaveTable migrates stacks")
|
|
|
|
print("[test] 5. checkitem / checkitemtype ops")
|
|
-- Mock Runtime session for adapters / ops fallbacks
|
|
local Runtime = { _session = { bag = Bag.new() } }
|
|
function Runtime.getSession() return Runtime._session end
|
|
package.loaded["src.core.game3.runtime"] = Runtime
|
|
Bag.add(Runtime._session.bag, 13, 2)
|
|
|
|
local store = Flags.newStore()
|
|
local vm = Vm.new({
|
|
store = store,
|
|
scripts = {
|
|
t_check = {
|
|
{ op = "checkitem", [1] = 13, [2] = 2 },
|
|
{ op = "copyvar", [1] = 0x4000, [2] = 0x800D }, -- persist past end wipe
|
|
{ op = "end" },
|
|
},
|
|
t_type = {
|
|
{ op = "checkitemtype", [1] = 13 },
|
|
{ op = "copyvar", [1] = 0x4001, [2] = 0x800D },
|
|
{ op = "end" },
|
|
},
|
|
t_space = {
|
|
{ op = "checkitemspace", [1] = 13, [2] = 1 },
|
|
{ op = "copyvar", [1] = 0x4002, [2] = 0x800D },
|
|
{ op = "end" },
|
|
},
|
|
},
|
|
})
|
|
|
|
vm:start("t_check")
|
|
for _ = 1, 20 do
|
|
if not vm:isRunning() then break end
|
|
vm:tick()
|
|
end
|
|
check(Flags.getVar(store, vm.ctx, 0x4000) == 1, "checkitem POTION x2 → true")
|
|
|
|
vm:start("t_type")
|
|
for _ = 1, 20 do
|
|
if not vm:isRunning() then break end
|
|
vm:tick()
|
|
end
|
|
check(Flags.getVar(store, vm.ctx, 0x4001) == 1, "checkitemtype POTION → POCKET_ITEMS(1)")
|
|
|
|
vm:start("t_space")
|
|
for _ = 1, 20 do
|
|
if not vm:isRunning() then break end
|
|
vm:tick()
|
|
end
|
|
check(Flags.getVar(store, vm.ctx, 0x4002) == 1, "checkitemspace POTION → true")
|
|
|
|
print("[test] 6. bufferitemname")
|
|
vm.ctx.stringVars = { [1] = "", [2] = "", [3] = "" }
|
|
Ops.dispatch(vm, { op = "bufferitemname", dest = 1, src = 13 })
|
|
check(vm.ctx.stringVars[2] == "POTION", "bufferitemname STR_VAR_2 = POTION")
|
|
|
|
print("[test] 7. Pass 2 — give / medicine / TM / escape / register")
|
|
local ItemUse = require("src.core.game3.item_use")
|
|
local Pokemon = require("src.core.game3.pokemon")
|
|
Pokemon.install(nil)
|
|
|
|
-- medicineKind
|
|
check(ItemsData.medicineKind(14) == "status", "ANTIDOTE → status")
|
|
check(ItemsData.medicineKind(24) == "revive", "REVIVE → revive")
|
|
check(ItemsData.fieldUseKind(13) == "heal", "POTION fieldUseKind heal")
|
|
|
|
-- give held item
|
|
local sess = {
|
|
name = "RED",
|
|
map = "FR_MT_MOON_1F",
|
|
healMap = "FR_PEWTER_CITY_POKEMON_CENTER_1F",
|
|
healX = 7,
|
|
healY = 4,
|
|
party = {
|
|
{ species = 1, name = "BULBASAUR", hp = 10, maxHp = 20, moves = { 33 }, pp = { 35 }, status = "PSN" },
|
|
},
|
|
bag = Bag.new(),
|
|
}
|
|
Bag.add(sess.bag, 13, 2)
|
|
local gOk = select(1, ItemUse.giveToMon(sess, sess.bag, 13, 1))
|
|
check(gOk == true, "give POTION to mon")
|
|
check(Bag.get(sess.bag, 13) == 1, "give consumed one from bag")
|
|
check(tonumber(sess.party[1].item) == 13 or sess.party[1].item == 13, "mon holds POTION")
|
|
|
|
-- status cure
|
|
Bag.add(sess.bag, 14, 1)
|
|
local sOk = select(1, ItemUse.useField(sess, sess.bag, 14, 1))
|
|
check(sOk == true, "ANTIDOTE clears poison")
|
|
check(sess.party[1].status == nil, "status cleared")
|
|
|
|
-- heal
|
|
sess.party[1].hp = 5
|
|
Bag.add(sess.bag, 13, 1)
|
|
local hOk = select(1, ItemUse.useField(sess, sess.bag, 13, 1))
|
|
check(hOk == true, "POTION heals")
|
|
check(sess.party[1].hp > 5, "HP increased")
|
|
|
|
-- TM01 → Focus Punch (264); Bulbasaur learnset bit 0
|
|
local move = Pokemon.moveFromTmItem(289)
|
|
check(move == 264, "TM01 → move 264 Focus Punch (got " .. tostring(move) .. ")")
|
|
local can = Pokemon.canLearnTmItem(1, 289)
|
|
-- Bulbasaur may or may not learn TM01; just ensure API returns boolean
|
|
check(type(can) == "boolean", "canLearnTmItem returns boolean")
|
|
|
|
-- Escape rope indoors → heal warp (Warp.request needs mod/game; just can_escape path)
|
|
Bag.add(sess.bag, 85, 1)
|
|
-- Without Runtime mod/game, useEscapeRope still removes + attempts warp
|
|
local Runtime = package.loaded["src.core.game3.runtime"] or {}
|
|
Runtime._mod = nil
|
|
Runtime._game = nil
|
|
package.loaded["src.core.game3.runtime"] = Runtime
|
|
local eOk, eWhy = ItemUse.useField(sess, sess.bag, 85, nil)
|
|
check(eOk == true or eWhy == "escape", "escape rope attempted on indoor map")
|
|
|
|
-- outdoor refuse
|
|
sess.map = "FR_ROUTE_1"
|
|
Bag.add(sess.bag, 85, 1)
|
|
local e2 = select(1, ItemUse.useField(sess, sess.bag, 85, nil))
|
|
check(e2 == false, "escape rope refused outdoors")
|
|
|
|
-- register
|
|
sess.registeredItem = 360
|
|
check(sess.registeredItem == 360, "registered BICYCLE")
|
|
|
|
print("[test] 8. Berry & TM pocket segregation and 3-pocket Bag UI")
|
|
local testBag = Bag.new()
|
|
Bag.add(testBag, "POTION", 2)
|
|
Bag.add(testBag, "BERRY", 3)
|
|
Bag.add(testBag, "ORAN_BERRY", 2)
|
|
Bag.add(testBag, "CHESTO_BERRY", 1)
|
|
Bag.add(testBag, "TM01", 1)
|
|
Bag.add(testBag, "HM01", 1)
|
|
|
|
local itemRows = Bag.listPocket(testBag, "ITEMS")
|
|
local keyRows = Bag.listPocket(testBag, "KEY_ITEMS")
|
|
local tmRows = Bag.listPocket(testBag, "TM_CASE")
|
|
local berryRows = Bag.listPocket(testBag, "BERRY_POUCH")
|
|
|
|
check(#itemRows == 1 and itemRows[1].name == "POTION", "ITEMS pocket only contains general items")
|
|
check(Bag.has(testBag, ItemsData.ITEM_TM_CASE, 1), "TM CASE key item present in KEY_ITEMS")
|
|
check(Bag.has(testBag, ItemsData.ITEM_BERRY_POUCH, 1), "BERRY POUCH key item present in KEY_ITEMS")
|
|
check(#tmRows == 2, "TM_CASE pocket contains 2 machines")
|
|
check(#berryRows == 2, "BERRY_POUCH pocket contains 2 berry kinds")
|
|
check(Bag.get(testBag, 139) == 5, "BERRY + ORAN_BERRY merged to 5 Oran berries")
|
|
|
|
local BagMenu = require("src.ui.game3.bag_menu")
|
|
BagMenu.show(nil, testBag)
|
|
BagMenu.settle()
|
|
check(BagMenu.currentPocket() == "ITEMS", "BagMenu initial pocket is ITEMS")
|
|
BagMenu.handleInput({ wasPressed = function(s, k) return k == "right" end })
|
|
check(BagMenu.currentPocket() == "KEY_ITEMS", "BagMenu second pocket is KEY_ITEMS")
|
|
BagMenu.handleInput({ wasPressed = function(s, k) return k == "right" end })
|
|
check(BagMenu.currentPocket() == "POKE_BALLS", "BagMenu third pocket is POKE_BALLS")
|
|
BagMenu.handleInput({ wasPressed = function(s, k) return k == "right" end })
|
|
check(BagMenu.currentPocket() == "POKE_BALLS", "BagMenu does not wrap past POKE_BALLS (3 pockets only)")
|
|
BagMenu.close()
|
|
|
|
if failed > 0 then
|
|
print(string.format("\n%d FAILED", failed))
|
|
os.exit(1)
|
|
end
|
|
print("\nAll bag tests passed.")
|
|
os.exit(0)
|