-- The field presentations a test cannot see, through the real world: -- teleport_from's spin-and-rise, the fishing rod bob, the headbutt tree shake, -- FLY's take-off lift, and FLY's own destination picker. -- -- POKEPORT_IDENTITY=gold-dev POKEPORT_GAME=gold \ -- POKEPORT_DRIVER=tests/drivers/gold_field_anim_shots.lua love . -- POKEPORT_SHOT_DIR=/tmp/gold-field (default) -- -- Every beat is asserted as well as shot, so a run that only prints PASS is -- still worth something on a machine nobody is looking at. local U = require("tests.drivers.util") local FieldMoves = require("src.world.gen2.FieldMoves") local Movement = require("src.script.gen2.Movement") local Pokegear = require("src.ui.gen2.Pokegear") return function(game) local out = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/gold-field" local failures = 0 local function ok(label, condition, detail) if condition then print("[field] ok " .. label) else failures = failures + 1 print("[field] FAIL " .. label .. " " .. tostring(detail)) end end U.wait(45) local world = game.world assert(world and world.map, "gold world did not boot") world:setMap("ROUTE_30", 10, 10, "down") U.wait(10) -- ------------------------------------------------------------- teleport -- -- LakeOfRageLanceTeleportIntoSkyMovement is `teleport_from / step_end`: -- StepFunction_TeleportFrom spins the object for sixteen frames and then -- lifts it off the tile over sixteen more. The byte used to decode as a nop, -- so Lance simply blinked out. local npc = world.npcs and world.npcs[1] -- applymovement's operand is the object_const_def index, which starts at 2 -- (World:objectEntity takes it back off), not the pooled NPC's own id. local objectId = npc and npc.def and npc.def.index and (npc.def.index + 1) if npc and objectId then local finished = false world:beginMovement(objectId, { Movement.TELEPORT_FROM, Movement.STEP_END }, function() finished = true end) local facings, deepest = {}, 0 for frame = 1, 34 do U.wait(1) facings[npc.facing] = true deepest = math.min(deepest, npc.spriteYOffset or 0) if frame == 20 then U.shot(game, out .. "/01-teleport-spin.png") end if frame == 30 then U.shot(game, out .. "/02-teleport-rise.png") end end ok("teleport_from spins the object", facings.up and facings.down and facings.left and facings.right) ok("and lifts it off its tile", deepest <= -0x50, deepest) ok("and the movement stream waits it out", finished) ok("and the object never left its cell", npc.spriteYOffset == 0) else print("[field] SKIP teleport: no object on this map") end -- ------------------------------------------------------------- fishing -- -- Script_GotABite's four fish_got_bite bobs: StepFunction_GotBite flips -- OBJECT_SPRITE_Y_OFFSET between 0 and 1 once a frame. local Mon = require("src.battle.gen2.Mon") local wild = Mon.new(game.data, "MAGIKARP", 10) world:beginFishing("battle", wild) local offsets = {} for frame = 1, 90 do U.wait(1) offsets[world.player.spriteYOffset or 0] = true if frame == 40 then U.shot(game, out .. "/03-fishing.png") end if world.textbox then break end end ok("the rod bobs the player one pixel", offsets[1] == true) world.fishing = nil world.player.spriteYOffset = 0 U.wait(5) while game.stack:top() do game.stack:pop() end U.wait(5) -- ------------------------------------------------------------- headbutt -- -- ShakeHeadbuttTree runs a 32-frame wobble under SFX_SANDSTORM. world:runHeadbutt(10, 9, { species = "SPEAROW", nickname = "SPEAROW" }) U.wait(2) -- The line is a text box; A takes it down and the shake starts on its close. for _ = 1, 20 do if world.headbutt then break end U.tap(game, "a") U.wait(2) end ok("the headbutt shake is armed", world.headbutt ~= nil) ok("and the frame shakes with it", world.shake ~= nil) U.wait(4) U.shot(game, out .. "/04-headbutt.png") for _ = 1, 120 do if not world.headbutt then break end U.tap(game, "a") U.wait(2) end while game.stack:top() do game.stack:pop() end U.wait(5) -- ------------------------------------------------------------- fly -- -- Every flypoint visited, so the picker has a full map to walk. local save = game.save save.engineFlags = save.engineFlags or {} for _, row in ipairs(FieldMoves.FLYPOINTS) do save.engineFlags[row.flag] = true end ok("openFlyMap opens a screen", world:openFlyMap() == true) U.wait(4) local picker = game.stack:top() ok("and it is the town-map picker, not a yes/no box", getmetatable(picker) == Pokegear and picker.fly ~= nil) ok("with the cursor on a flypoint", picker and picker.flyRow and picker:flyRow() ~= nil) U.shot(game, out .. "/05-flymap.png") U.tap(game, "up") U.wait(4) U.shot(game, out .. "/06-flymap-moved.png") -- A takes the destination: the fade out lifts the player off the map first. U.tap(game, "a") local lifted = 0 for frame = 1, 40 do U.wait(1) lifted = math.min(lifted, (world.player and world.player.spriteYOffset) or 0) if frame == 4 then U.shot(game, out .. "/07-fly-takeoff.png") end end ok("FLY lifts the player under the fade", lifted < 0, lifted) U.wait(30) ok("and lands them back on the tile", (world.player.spriteYOffset or 0) == 0) U.shot(game, out .. "/08-fly-landed.png") -- --------------------------------------------------- tilt and the void -- -- Zoomed out with TILT on is where both nitpicks live: the billboard clip -- (no NPCs standing past where the ground is drawn) and the border-block -- dissolve across a map boundary. local Tilt = require("src.render.Tilt") local Zoom = require("src.render.Zoom") Zoom.offset = -3 world:rebuildNeighbors() world:rebuildPeople({ seamless = true }) Tilt.setLevel(3) for _ = 1, 40 do Tilt.update(1 / 60) U.wait(1) end U.shot(game, out .. "/09-tilt-survey.png") -- Cross into the next map: the void fill dissolves from one border block to -- the other rather than cutting. world:setMap("ROUTE_31", 10, 10, "down") U.wait(2) U.shot(game, out .. "/10-void-crossfade.png") U.wait(10) U.shot(game, out .. "/11-void-settled.png") ok("the border fill is mid-dissolve on arrival", world.borderFade == nil or world.borderFade >= 1) Tilt.setLevel(0) Zoom.offset = 0 if failures > 0 then print(("[driver] FAIL gold field anims: %d check(s)"):format(failures)) return end print("[driver] PASS gold field anims in " .. out) end