mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
179 lines
6.0 KiB
Lua
179 lines
6.0 KiB
Lua
#!/usr/bin/env luajit
|
|
-- pokefirered/src/event_object_movement.c:6772 MovementAction_FacePlayer_Step0
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local function eq(a, b, msg)
|
|
check(a == b, string.format("%s (%s == %s)", msg, tostring(a), tostring(b)))
|
|
end
|
|
|
|
local function done()
|
|
if failed > 0 then
|
|
print("[test] FAILED " .. failed)
|
|
os.exit(1)
|
|
end
|
|
print("[test] all passed")
|
|
os.exit(0)
|
|
end
|
|
|
|
require("src.core.GameVersion").set("firered")
|
|
|
|
local Cache = require("tests.game3_cache")
|
|
local cacheRoot = Cache.mount("scripts/events.lua", { native = true })
|
|
if not cacheRoot then
|
|
print("[skip] game3_stitchcoll_move_kinds_test: " .. tostring(Cache.reason))
|
|
done()
|
|
end
|
|
|
|
local Dataset = require("src.core.game3.dataset")
|
|
local MapCatalog = require("src.import.gba.map_catalog")
|
|
local Collision = require("src.core.game3.collision")
|
|
local Objects = require("src.core.game3.objects")
|
|
local Player = require("src.core.game3.player")
|
|
local Field = require("src.core.game3.field")
|
|
local Space = require("src.core.game3.scripting.space")
|
|
|
|
local MAP = MapCatalog.pretToEngine("PalletTown")
|
|
local PX, PY = 12, 20
|
|
|
|
local game = { data = {} }
|
|
Dataset.hydrate(game)
|
|
local session = { map = MAP, flags = {}, vars = {}, party = {} }
|
|
game.session = session
|
|
|
|
local def = game.data.maps[MAP]
|
|
check(def ~= nil, tostring(MAP) .. " is in the cache")
|
|
if not def then done() end
|
|
|
|
Field._game = game
|
|
Field._session = session
|
|
Field.running = true
|
|
Field.locked = false
|
|
Space.activate(nil, MAP, game, nil)
|
|
Collision.bindMap(game, MAP, def)
|
|
Objects.loadMap(game, MAP, def)
|
|
Player.reset(PX, PY, "down")
|
|
|
|
local eo, lid
|
|
for i = 1, 16 do
|
|
local o = Objects.find(i)
|
|
if o and o.cellX and not Objects.isPlayer(i) then eo, lid = o, i break end
|
|
end
|
|
check(eo ~= nil, "Pallet Town has an object to drive")
|
|
if not eo then done() end
|
|
|
|
local function run(bytes, maxFrames)
|
|
Objects.clearMovements()
|
|
eo.moving = false
|
|
local finished = false
|
|
Objects.applyMovement(lid, bytes, function() finished = true end)
|
|
local frames = 0
|
|
while not finished and frames < (maxFrames or 300) do
|
|
Objects.update(game)
|
|
frames = frames + 1
|
|
end
|
|
return frames, finished
|
|
end
|
|
|
|
local function place(x, y, facing)
|
|
Objects.setObjectXY(lid, x, y)
|
|
eo.facingLocked = false
|
|
eo.inanimate = false
|
|
eo.facing = facing
|
|
end
|
|
|
|
print("[test] 1. face_player (0x4A) turns the object toward the player")
|
|
place(PX + 1, PY, "down")
|
|
local _, finished = run({ 0x4A, 0xFE })
|
|
check(finished, "the face_player stream finished")
|
|
eq(eo.facing, "left", "an object east of the player faces west")
|
|
place(PX - 1, PY, "down")
|
|
run({ 0x4A, 0xFE })
|
|
eq(eo.facing, "right", "an object west of the player faces east")
|
|
place(PX, PY + 1, "left")
|
|
run({ 0x4A, 0xFE })
|
|
eq(eo.facing, "up", "an object south of the player, same column, faces north")
|
|
place(PX, PY - 1, "left")
|
|
run({ 0x4A, 0xFE })
|
|
eq(eo.facing, "down", "an object north of the player, same column, faces south")
|
|
|
|
print("[test] 2. GetDirectionToFace is x first, not the largest delta")
|
|
-- pokefirered/src/event_object_movement.c:4789 GetDirectionToFace
|
|
place(PX + 1, PY - 9, "down")
|
|
run({ 0x4A, 0xFE })
|
|
eq(eo.facing, "left", "one cell east and nine cells north still faces west")
|
|
place(PX - 1, PY + 9, "down")
|
|
run({ 0x4A, 0xFE })
|
|
eq(eo.facing, "right", "one cell west and nine cells south still faces east")
|
|
|
|
print("[test] 3. face_away_player (0x4B) takes the opposite direction")
|
|
-- pokefirered/src/event_object_movement.c:6784 MovementAction_FaceAwayPlayer_Step0
|
|
place(PX + 1, PY, "down")
|
|
run({ 0x4B, 0xFE })
|
|
eq(eo.facing, "right", "an object east of the player faces further east")
|
|
place(PX, PY - 1, "left")
|
|
run({ 0x4B, 0xFE })
|
|
eq(eo.facing, "up", "an object north of the player faces further north")
|
|
|
|
print("[test] 4. lock_facing (0x4C / 0x4D) walks the object without turning it")
|
|
place(PX + 4, PY, "down")
|
|
local startX = eo.cellX
|
|
run({ 0x4C, 0x12, 0xFE }, 120)
|
|
eq(eo.facing, "down", "the locked object still faces the way it started")
|
|
eq(eo.cellX, startX - 1, "and it still moved one cell west")
|
|
check(eo.facingLocked == true, "the lock is still on after the stream")
|
|
run({ 0x4D, 0x12, 0xFE }, 120)
|
|
eq(eo.facingLocked, false, "0x4D unlocks it")
|
|
eq(eo.facing, "left", "and the next walk turns it again")
|
|
|
|
print("[test] 5. disable / restore animation (0x5E / 0x5F)")
|
|
place(PX + 4, PY, "down")
|
|
Objects.clearMovements()
|
|
local fin = false
|
|
Objects.applyMovement(lid, { 0x5E, 0x12, 0x5F, 0x12, 0xFE }, function() fin = true end)
|
|
local phaseWhileOff, phaseWhileOn = 0, 0
|
|
local walks, wasMoving, disabledDuringFirstWalk = 0, false, false
|
|
for _ = 1, 200 do
|
|
if fin then break end
|
|
Objects.update(game)
|
|
if eo.moving and not wasMoving then walks = walks + 1 end
|
|
wasMoving = eo.moving and true or false
|
|
if eo.moving then
|
|
local p = Objects.walkPhase(eo)
|
|
if walks == 1 then
|
|
if eo.inanimate then disabledDuringFirstWalk = true end
|
|
if p == 1 then phaseWhileOff = phaseWhileOff + 1 end
|
|
elseif walks == 2 and p == 1 then
|
|
phaseWhileOn = phaseWhileOn + 1
|
|
end
|
|
end
|
|
end
|
|
check(fin, "the animation stream finished")
|
|
eq(walks, 2, "the stream walked twice")
|
|
check(disabledDuringFirstWalk, "0x5E marks the object inanimate for the first walk")
|
|
eq(phaseWhileOff, 0, "the walk frame never advances while the animation is disabled")
|
|
check(phaseWhileOn > 0,
|
|
"and it advances again once restored (" .. phaseWhileOn .. " frames on phase 1)")
|
|
eq(eo.inanimate, false, "0x5F restores the object's own animation")
|
|
|
|
print("[test] 6. remove_obstacle (0x68 / 0x69) burns its animation frames")
|
|
-- pokefirered/src/event_object_movement.c:7135 MovementAction_RockSmashBreak_Step0
|
|
place(PX + 4, PY, "down")
|
|
local smashFrames = run({ 0x68, 0xFE }, 300)
|
|
eq(smashFrames, 64, "rock_smash_break holds the track for its 64 frames")
|
|
-- pokefirered/src/event_object_movement.c:7163 MovementAction_CutTree_Step0
|
|
local cutFrames = run({ 0x69, 0xFE }, 300)
|
|
eq(cutFrames, 56, "cut_tree holds the track for its 56 frames")
|
|
|
|
done()
|