Files
gen1recomp/tests/drivers/gold_variablesprite_identity.lua
bryanthaboi ae6cac89e1 G2 support
2026-08-11 11:53:30 -04:00

88 lines
3.8 KiB
Lua

-- `variablesprite` mid-script must repaint an object, not replace it.
--
-- POKEPORT_GAME=gold POKEPORT_DRIVER=tests/drivers/gold_variablesprite_identity.lua love .
--
-- Two of the four map scripts that run `variablesprite` do it with the object
-- standing right there, mid-conversation, and with the VM holding a reference
-- to it as LAST_TALKED:
--
-- LassAliceScript (maps/FuchsiaGym.asm:61-66) is
-- `applymovement FUCHSIAGYM_FUCHSIA_GYM_1, Movement_NinjaSpin / faceplayer /
-- variablesprite SPRITE_FUCHSIA_GYM_1, SPRITE_LASS / special
-- LoadUsedSpritesGFX / faceplayer` -- the ninja spins, unmasks, and the very
-- next command turns the SAME object back to the player;
-- CopycatsHouse2F.asm:23-48 does the same for the Copycat.
--
-- On the cart nothing about the object struct moves: Script_variablesprite
-- writes ONE byte of wVariableSprites (scripting.asm:869) and LoadUsedSpritesGFX
-- reloads the tiles behind it. The object keeps its coordinates, its facing,
-- its FROZEN_F and its place as wLastTalked.
--
-- So the port must keep the same NPC table. Building a new one strands
-- World.talkNpc, .trainerNpc, .followState and any live moveState on an object
-- that is no longer on the map, and drops the object back to its map-def home
-- cell and default facing in the middle of the scene.
local U = require("tests.drivers.util")
return function(game)
U.wait(45)
local world = game.world
assert(world and world.map, "gold world did not boot")
-- Route 36's Sudowoodo is the port's one live object on a SPRITE_VARS byte
-- outside Kanto (maps/Route36.asm:486, SPRITE_WEIRD_TREE = slot 4).
world:setMap("ROUTE_36", 34, 9, "right")
U.wait(20)
local tree, treeId
for _, npc in ipairs(world.npcs) do
if npc.def and npc.def.sprite == 0xf0 + 4 then
tree, treeId = npc, (npc.def.index or 0) + 1
break
end
end
assert(tree, "no SPRITE_WEIRD_TREE object on ROUTE_36")
-- The state a mid-script `variablesprite` has to survive: the object is the
-- one being talked to, it has been turned, and it has been frozen.
world.talkNpc = tree
world.trainerNpc = tree
tree.facing = "left"
tree.frozen = true
local beforeX, beforeY = tree.cellX, tree.cellY
-- `variablesprite SPRITE_WEIRD_TREE, SPRITE_TWIN`, the same slot write
-- WateredWeirdTreeScript makes (maps/Route36.asm:58).
world:setVariableSprite(4, 38)
U.wait(2)
local after = world:objectEntity(treeId)
print(("[driver] object identity kept: %s"):format(tostring(after == tree)))
print(("[driver] talkNpc still on the map: %s")
:format(tostring(after == world.talkNpc)))
print(("[driver] facing %s -> %s, frozen %s -> %s, cell (%s,%s) -> (%s,%s)")
:format(tostring(tree.facing), tostring(after and after.facing),
tostring(tree.frozen), tostring(after and after.frozen),
tostring(beforeX), tostring(beforeY),
tostring(after and after.cellX), tostring(after and after.cellY)))
print(("[driver] sheet now %s (SPRITE_TWIN wanted)")
:format(tostring(after and after.spriteDef and after.spriteDef.id)))
assert(after, "the object vanished from the map entirely")
assert(after.spriteDef and after.spriteDef.id == "SPRITE_TWIN",
"the slot write did not repaint the object: it is "
.. tostring(after.spriteDef and after.spriteDef.id))
assert(after == tree,
"variablesprite REPLACED the object -- World.talkNpc / .trainerNpc and any "
.. "live movement now point at an NPC that is no longer on the map")
assert(after.facing == "left",
"the object lost the facing a `faceplayer` had just given it: "
.. tostring(after.facing))
assert(after.frozen == true, "the object came back unfrozen mid-script")
assert(after.cellX == beforeX and after.cellY == beforeY,
"the object moved on a slot write")
print("[driver] PASS gold variablesprite keeps the object")
love.event.quit()
end