Files
gen1recomp/tests/gen2_moomoo_test.lua
T

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()