mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
166 lines
5.3 KiB
Lua
166 lines
5.3 KiB
Lua
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local S = require("tests.harness").suite("gen2 moomoo")
|
|
local check, eq = S.check, S.eq
|
|
|
|
love = require("tests.love_stub")
|
|
|
|
local Vm = require("src.script.gen2.Vm")
|
|
local Events = require("src.world.gen2.Events")
|
|
local FlagNames = require("src.core.gen2.FlagNames")
|
|
local Ser = require("src.core.SaveSerializer")
|
|
local Save = require("src.core.gen2.Save")
|
|
|
|
-- pokecrystal constants/event_flags.asm:70
|
|
local HEALED = FlagNames.events.EVENT_HEALED_MOOMOO
|
|
local TALKED = FlagNames.events.EVENT_TALKED_TO_FARMER_ABOUT_MOOMOO
|
|
-- pokecrystal ram/wram.asm:3142 wMooMooBerries
|
|
local BERRIES = 0xd962
|
|
local BERRY_ITEM = 173
|
|
|
|
eq(HEALED, 61, "EVENT_HEALED_MOOMOO is flag 61")
|
|
eq(TALKED, 63, "EVENT_TALKED_TO_FARMER_ABOUT_MOOMOO is flag 63")
|
|
|
|
do
|
|
local events = Events.new()
|
|
events:set(HEALED, true)
|
|
events:set(0, true)
|
|
events:resetMapBuffer()
|
|
check(events:get(HEALED), "a map reload cannot clear flag 61")
|
|
check(not events:get(0), "the map buffer byte is the one that is wiped")
|
|
end
|
|
|
|
local cache = os.getenv("CRYSTAL_CACHE")
|
|
if not cache then
|
|
cache = (os.getenv("HOME") or "")
|
|
.. "/Library/Application Support/LOVE/crystal-dev/crystal"
|
|
end
|
|
|
|
local scriptsPath = cache .. "/data/generated/scripts.lua"
|
|
local probe = io.open(scriptsPath, "r")
|
|
if not probe then
|
|
check(true, "crystal cache absent : SKIP")
|
|
S.finish()
|
|
return
|
|
end
|
|
probe:close()
|
|
|
|
local function loadLua(rel)
|
|
local chunk = loadfile(cache .. "/" .. rel)
|
|
if not chunk then return nil end
|
|
local ok, value = pcall(chunk)
|
|
return ok and value or nil
|
|
end
|
|
|
|
local scripts = loadLua("data/generated/scripts.lua")
|
|
local texts = loadLua("data/generated/text.lua")
|
|
local maps = loadLua("data/generated/maps.lua")
|
|
check(scripts ~= nil, "scripts.lua loads")
|
|
check(texts ~= nil, "text.lua loads")
|
|
check(maps ~= nil, "maps.lua loads")
|
|
|
|
local barn = (maps or {}).ROUTE_39_BARN
|
|
check(barn ~= nil, "the cache carries ROUTE_39_BARN")
|
|
|
|
-- pokecrystal maps/Route39Barn.asm:47 MoomooScript
|
|
local miltank
|
|
for _, obj in ipairs((barn or {}).objects or {}) do
|
|
if obj.sprite == "SPRITE_TAUROS" then miltank = obj end
|
|
end
|
|
check(miltank ~= nil, "the Miltank object is on the map")
|
|
local moomooKey = miltank and (miltank.scriptKey or miltank.script)
|
|
eq(moomooKey, "27:4caa", "and it points at MoomooScript")
|
|
|
|
local seven
|
|
for _, row in ipairs((scripts or {})["27:4d04"] or {}) do
|
|
if row.op == "setevent" then seven = row.event end
|
|
end
|
|
-- pokecrystal maps/Route39Barn.asm:106
|
|
eq(seven, HEALED, ".SevenBerries ends on setevent EVENT_HEALED_MOOMOO")
|
|
|
|
local hasClear = false
|
|
for key, rows in pairs(scripts or {}) do
|
|
if type(rows) == "table" and type(key) == "string" then
|
|
for _, row in ipairs(rows) do
|
|
if row.op == "clearevent" and row.event == HEALED then hasClear = true end
|
|
end
|
|
end
|
|
end
|
|
check(not hasClear, "nothing in the cache ever clears flag 61")
|
|
|
|
local events = Events.new()
|
|
events:set(TALKED, true)
|
|
|
|
local bag = { [BERRY_ITEM] = 10 }
|
|
local seen = {}
|
|
local vm = Vm.new(scripts, texts, events, {
|
|
showText = function(body, onDone)
|
|
seen[#seen + 1] = tostring(body)
|
|
if onDone then onDone() end
|
|
end,
|
|
yesorno = function(onChoose) onChoose(true) end,
|
|
hasItem = function(item) return (bag[item] or 0) > 0 end,
|
|
takeItem = function(item, qty)
|
|
local have = bag[item] or 0
|
|
if have < (qty or 1) then return false end
|
|
bag[item] = have - (qty or 1)
|
|
return true
|
|
end,
|
|
})
|
|
|
|
local function drain()
|
|
for _ = 1, 600 do
|
|
if not vm:running() then break end
|
|
vm:update()
|
|
end
|
|
return not vm:running()
|
|
end
|
|
|
|
for i = 1, 7 do
|
|
check(vm:start(moomooKey), ("talk %d starts MoomooScript"):format(i))
|
|
check(drain(), ("talk %d runs to end"):format(i))
|
|
eq(vm.mem[BERRIES], i, ("berry %d counted into wMooMooBerries"):format(i))
|
|
if i < 7 then
|
|
check(not events:get(HEALED),
|
|
("berry %d does not heal MOOMOO"):format(i))
|
|
end
|
|
end
|
|
|
|
check(events:get(HEALED), "EVENT_HEALED_MOOMOO is set on the seventh berry")
|
|
eq(bag[BERRY_ITEM], 3, "seven BERRIES left the bag")
|
|
|
|
local function saw(fragment)
|
|
for _, body in ipairs(seen) do
|
|
if body:find(fragment, 1, true) then return true end
|
|
end
|
|
return false
|
|
end
|
|
check(saw("little healthier"), "the third berry prints the 3-berry line")
|
|
check(saw("quite healthy"), "the fifth berry prints the 5-berry line")
|
|
check(saw("totally healthy"), "the seventh berry prints the 7-berry line")
|
|
|
|
-- pokecrystal maps/Route39Barn.asm:121
|
|
seen = {}
|
|
check(vm:start(moomooKey), "the next talk starts")
|
|
check(drain(), "and runs to end")
|
|
check(saw("Mooo!"), "a healed MOOMOO takes the .HappyCow arm")
|
|
eq(vm.mem[BERRIES], 7, "and does not take another berry")
|
|
|
|
local snapshot = { scriptMem = vm:serializeMem(), events = events:serialize() }
|
|
eq(snapshot.scriptMem[BERRIES], 7, "the counter reaches serializeMem")
|
|
|
|
local encoded = Ser.encode(snapshot)
|
|
check(type(encoded) == "string", "the snapshot encodes")
|
|
local decoded, err = Ser.decode(encoded)
|
|
check(decoded ~= nil, "and decodes (" .. tostring(err) .. ")")
|
|
|
|
local report = Save.validate(decoded or {})
|
|
check(Save.emptyReport(report), "validate quarantines nothing")
|
|
|
|
local back = Vm.new({}, {}, Events.new(), {}):restoreMem((decoded or {}).scriptMem)
|
|
eq(back.mem[BERRIES], 7, "the counter survives a save round trip")
|
|
local backEvents = Events.new():restore((decoded or {}).events)
|
|
check(backEvents:get(HEALED), "and so does EVENT_HEALED_MOOMOO")
|
|
|
|
S.finish()
|