mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
G2 support
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
-- The egg hatch cutscene's clock, sprite lifetimes and pic placement.
|
||||
--
|
||||
-- luajit tests/gen2_egg_hatch_anim_test.lua
|
||||
--
|
||||
-- Everything here is geometry or bookkeeping the ASM states outright, so it
|
||||
-- runs with no cache and no window: EggHatchAnim only reaches love.graphics
|
||||
-- from its draw path, and the stub below is enough for that.
|
||||
--
|
||||
-- What it pins:
|
||||
--
|
||||
-- * AnimSeq_RevealNewMon's `cp $80 / jr nc, .finish_EggShell` really does
|
||||
-- retire the shell fragment (engine/sprite_anims/functions.asm:1270-1305).
|
||||
-- They used to keep drawing, frozen at their last offset, for the ~113
|
||||
-- frames left in Hatch_ShellFragmentLoop.
|
||||
-- * .OAMData_1x1_Palette0's own -4 on each axis is in the screen position
|
||||
-- (data/sprite_anims/oam.asm:112-114).
|
||||
-- * The pic sits where PadFrontpic put it (engine/gfx/load_pics.asm:342),
|
||||
-- which for a 6-wide pic is a whole tile in, not half of one.
|
||||
-- * hSCX and wGlobalAnimXOffset move the background and the objects the SAME
|
||||
-- way during a wobble (engine/pokemon/breeding.asm:707-719), so a crack
|
||||
-- does not slide across the shell it is sitting on.
|
||||
-- * The EGG has a palette row of its own (data/pokemon/palettes.asm:530).
|
||||
package.path = "./?.lua;./?/init.lua;" .. package.path
|
||||
|
||||
local S = require("tests.harness").suite("gen2 egg hatch anim")
|
||||
local check, eq = S.check, S.eq
|
||||
|
||||
local EggHatchAnim = require("src.ui.gen2.EggHatchAnim")
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- A love.graphics that records instead of drawing. No newShader, so
|
||||
-- GbcPalette.available() is false and the palette shader stays out of the way.
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
local draws = {}
|
||||
local ox, oy = 0, 0
|
||||
local saved = {}
|
||||
local function fakeImage(w, h)
|
||||
return {
|
||||
getWidth = function() return w end,
|
||||
getHeight = function() return h end,
|
||||
getDimensions = function() return w, h end,
|
||||
}
|
||||
end
|
||||
|
||||
_G.love = {
|
||||
graphics = {
|
||||
setColor = function() end,
|
||||
rectangle = function() end,
|
||||
push = function() saved[#saved + 1] = { ox, oy } end,
|
||||
pop = function()
|
||||
local t = table.remove(saved)
|
||||
ox, oy = t[1], t[2]
|
||||
end,
|
||||
translate = function(x, y) ox = ox + (x or 0) oy = oy + (y or 0) end,
|
||||
scale = function() end,
|
||||
newQuad = function(x, y, w, h) return { x = x, y = y, w = w, h = h } end,
|
||||
draw = function(_image, a, b, c)
|
||||
if type(a) == "table" then
|
||||
-- G.draw(image, quad, x, y, ...): a sprite object.
|
||||
draws[#draws + 1] = { kind = "sprite", quad = a, x = ox + b, y = oy + c }
|
||||
else
|
||||
draws[#draws + 1] = { kind = "pic", x = ox + a, y = oy + b }
|
||||
end
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
local function render(anim)
|
||||
draws = {}
|
||||
anim:drawPanel()
|
||||
local out = { pic = nil, sprites = {} }
|
||||
for _, d in ipairs(draws) do
|
||||
if d.kind == "pic" then out.pic = d
|
||||
else out.sprites[#out.sprites + 1] = d end
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- A game with a 5x5 egg pic, a 6x6 hatchling and the two-tile shell sheet.
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
local EGG_COLORS = { { 240, 208, 88 }, { 184, 128, 0 } }
|
||||
local MON_COLORS = { { 100, 100, 100 }, { 40, 40, 40 } }
|
||||
|
||||
local function newAnim()
|
||||
local data = {
|
||||
-- SENTRET's frontpic is 48px, the width the old centring rule got wrong.
|
||||
pokemon = { SENTRET = { spriteFront = "sentret.png" } },
|
||||
gen2MenuGfx = { eggHatch = {
|
||||
egg = "egg.png", shell = "shell.png", shellTiles = 2,
|
||||
} },
|
||||
gen2Palettes = { pokemon = {
|
||||
EGG = { normal = EGG_COLORS, shiny = EGG_COLORS },
|
||||
SENTRET = { normal = MON_COLORS, shiny = MON_COLORS },
|
||||
} },
|
||||
}
|
||||
local anim = EggHatchAnim.new({ data = data }, {
|
||||
mon = { species = "SENTRET", shiny = false },
|
||||
species = "SENTRET",
|
||||
})
|
||||
anim.picCache["egg.png"] = fakeImage(40, 40)
|
||||
anim.picCache["sentret.png"] = fakeImage(48, 48)
|
||||
anim.picCache["shell.png"] = fakeImage(8, 16)
|
||||
return anim
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- Sprite lifetimes
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
local anim = newAnim()
|
||||
|
||||
-- Hatch_InitShellFragments lays ten `shell_fragment` rows, and `.done` has
|
||||
-- already run ClearSprites over the cracks by then.
|
||||
local frames, spawned, cleared = 0, nil, nil
|
||||
while not anim.done and frames < 5000 do
|
||||
anim:update(1 / 60)
|
||||
frames = frames + 1
|
||||
if not spawned and #anim.sprites == 10 and anim.showMon then
|
||||
spawned = frames
|
||||
end
|
||||
if spawned and not cleared and #anim.sprites == 0 then cleared = frames end
|
||||
end
|
||||
|
||||
eq(frames, 482, "the whole sequence is 482 frames of DelayFrames operands")
|
||||
check(spawned ~= nil, "the ten shell fragments go up at `.done`")
|
||||
check(cleared ~= nil, "and every one of them leaves the screen again")
|
||||
-- var1 starts at 0 and gains 8 a frame; the seventeenth frame is the first to
|
||||
-- see $80 at the top of AnimSeq_RevealNewMon and take .finish_EggShell.
|
||||
eq(cleared and (cleared - spawned), 17,
|
||||
"sixteen frames of flight, then DeinitializeSprite")
|
||||
eq(#anim.sprites, 0, "and nothing is left drawing when the loop ends")
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- Screen positions
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
anim = newAnim()
|
||||
|
||||
-- The egg at hlcoord 7, 4 with PadFrontpic's `.five` offset of (1, 2) tiles.
|
||||
local frame = render(anim)
|
||||
check(frame.pic ~= nil, "the egg pic draws while the shell is up")
|
||||
eq(frame.pic and frame.pic.x, 7 * 8 + 8, "the 5-wide egg's x")
|
||||
eq(frame.pic and frame.pic.y, 4 * 8 + 16, "the 5-wide egg's y")
|
||||
|
||||
-- EggHatch_CrackShell's first surviving round: `ld e, 11 * TILE_WIDTH` and
|
||||
-- `add 9 * TILE_WIDTH`, less the -8 / -16 OAM bias and the oamset's own -4.
|
||||
anim:crackShell(2)
|
||||
eq(#anim.sprites, 1, "round 2 is the first round to crack the shell")
|
||||
frame = render(anim)
|
||||
eq(#frame.sprites, 1, "and the crack draws")
|
||||
eq(frame.sprites[1] and frame.sprites[1].x, 11 * 8 - 8 - 4, "the crack's x")
|
||||
eq(frame.sprites[1] and frame.sprites[1].y, 9 * 8 - 16 - 4, "the crack's y")
|
||||
|
||||
-- A wobble half moves BOTH layers two pixels left, so the crack keeps its
|
||||
-- place on the shell instead of sliding across it.
|
||||
local still = frame
|
||||
anim.shakeX = 2
|
||||
local shaken = render(anim)
|
||||
eq(shaken.pic.x - still.pic.x, -2, "hSCX = +2 slides the background left")
|
||||
eq(shaken.sprites[1].x - still.sprites[1].x, -2,
|
||||
"and wGlobalAnimXOffset = -2 takes the crack with it")
|
||||
eq(shaken.pic.y, still.pic.y, "the wobble is horizontal only")
|
||||
anim.shakeX = 0
|
||||
|
||||
-- The hatchling at hlcoord 6, 3 with `.six`'s offset of (1, 1) tiles: a whole
|
||||
-- blank column, then one blank tile above each pic column.
|
||||
anim.showMon = true
|
||||
frame = render(anim)
|
||||
eq(frame.pic and frame.pic.x, 6 * 8 + 8, "the 6-wide hatchling's x")
|
||||
eq(frame.pic and frame.pic.y, 3 * 8 + 8, "the 6-wide hatchling's y")
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- Palettes
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
anim = newAnim()
|
||||
local colors = anim:picColors()
|
||||
check(colors ~= nil, "the egg has a palette of its own, not flat GB greys")
|
||||
eq(colors and colors[2] and colors[2][1], EGG_COLORS[1][1],
|
||||
"and it is the EGG row _CGB_Evolution loads for wPlayerHPPal = EGG")
|
||||
anim.showMon = true
|
||||
colors = anim:picColors()
|
||||
eq(colors and colors[2] and colors[2][1], MON_COLORS[1][1],
|
||||
"the hatchling brings its own once the pic swaps")
|
||||
|
||||
-- A cache built before the extractor grew the EGG row still runs.
|
||||
anim = newAnim()
|
||||
anim.palettes.pokemon.EGG = nil
|
||||
eq(anim:picColors(), nil, "an older cache simply draws in the raw shades")
|
||||
|
||||
S.finish()
|
||||
Reference in New Issue
Block a user