148 lines
4.7 KiB
Text
148 lines
4.7 KiB
Text
-- The timeline (FORGE.md milestone 1): hitbox tracks keyed to disc frames, edited in Forge. The
|
|
-- cursor is stepped, keys are made at it, one is picked up off the canvas and dragged, one is
|
|
-- deleted, and the compiled game carries what was drawn. The description names its video, so the
|
|
-- editor has a frame to show under the cursor.
|
|
FORGE_LIBRARY = true
|
|
dofile("Forge/Forge.singe")
|
|
|
|
local font = fontLoad("Singe/FreeSansBold.ttf", 15)
|
|
local out = singeGetDataPath()
|
|
local work = out .. "timeline.game"
|
|
|
|
fontSelect(font)
|
|
fontQuality(FONT_QUALITY_BLENDED)
|
|
overlaySetResolution(720, 480)
|
|
|
|
local source = assert(io.open("testScripts/author/gunvideo.game", "r"))
|
|
local copy = assert(io.open(work, "w"))
|
|
|
|
copy:write(source:read("a"))
|
|
source:close()
|
|
copy:close()
|
|
|
|
if not forgeBegin(work) then
|
|
debugPrint("TIMELINE FAIL could not open " .. work)
|
|
singeQuit()
|
|
end
|
|
|
|
local frames = 0
|
|
local stage = 0
|
|
|
|
|
|
local function key(code, character)
|
|
forgeKey(character or 0, code.value)
|
|
end
|
|
|
|
|
|
local function step()
|
|
local track = forgeRoom().tracks[1]
|
|
|
|
if stage == 1 then
|
|
debugPrint("TIMELINE video loaded: " .. tostring(FORGE.video ~= nil) .. "; track '" .. track.name .. "' has " .. #track.boxes .. " keys")
|
|
key(SCANCODE.TAB)
|
|
key(SCANCODE.TAB)
|
|
key(SCANCODE.TAB)
|
|
if FORGE.mode ~= "tracks" then
|
|
debugPrint("TIMELINE FAIL three tabs did not reach the tracks: " .. FORGE.mode)
|
|
end
|
|
|
|
elseif stage == 2 then
|
|
-- Step and leap the cursor to frame 170, halfway between the bandit's two keys.
|
|
for _ = 1, 17 do
|
|
key(SCANCODE.RIGHTBRACKET)
|
|
end
|
|
local box = forgeCursorBox()
|
|
|
|
debugPrint(string.format("TIMELINE cursor at %d, the bandit box is at x=%.0f (halfway from 100 to 400)", FORGE.cursor, box.x))
|
|
if math.abs(box.x - 250) > 1 then
|
|
debugPrint("TIMELINE FAIL interpolation at the cursor")
|
|
end
|
|
|
|
elseif stage == 3 then
|
|
-- A key at the cursor takes the interpolated box, and the list stays sorted.
|
|
key(SCANCODE.K)
|
|
if #track.boxes == 3 and track.boxes[2].at == 170 and track.boxes[2].x == 250 then
|
|
debugPrint("TIMELINE a key at 170 went in between the two, at x=250")
|
|
else
|
|
debugPrint("TIMELINE FAIL after K the track has " .. #track.boxes .. " keys; second at " .. tostring(track.boxes[2] and track.boxes[2].at))
|
|
end
|
|
|
|
elseif stage == 4 then
|
|
-- Pick the box up off the canvas and drag it, the way a pointer would.
|
|
local box = forgeCursorBox()
|
|
|
|
forgePress(box.x + 5, box.y + 5)
|
|
forgeDrag(box.x + 65, box.y + 25)
|
|
forgeRelease()
|
|
if track.boxes[2].x == 310 and track.boxes[2].y == 220 then
|
|
debugPrint("TIMELINE dragged the key to " .. track.boxes[2].x .. "," .. track.boxes[2].y)
|
|
else
|
|
debugPrint("TIMELINE FAIL the drag left the key at " .. tostring(track.boxes[2].x) .. "," .. tostring(track.boxes[2].y))
|
|
end
|
|
|
|
elseif stage == 5 then
|
|
-- Type the key's height, then step back a frame: the box between keys follows the new one.
|
|
key(SCANCODE.RETURN) -- at
|
|
key(SCANCODE.RETURN) -- x
|
|
key(SCANCODE.RETURN) -- y
|
|
key(SCANCODE.RETURN) -- w
|
|
key(SCANCODE.RETURN) -- h
|
|
for c in string.gmatch("40", ".") do
|
|
key(SCANCODE.A, string.byte(c))
|
|
end
|
|
key(SCANCODE.RETURN)
|
|
key(SCANCODE.ESCAPE)
|
|
key(SCANCODE.COMMA)
|
|
local box = forgeCursorBox()
|
|
|
|
debugPrint(string.format("TIMELINE key height typed to %d; at frame %d the box is %.0f tall", track.boxes[2].h, FORGE.cursor, box.h))
|
|
|
|
elseif stage == 6 then
|
|
-- Undo the typing and the drag, then delete the key. Undo puts a copy of the description
|
|
-- in place, so the track is looked up again afterwards.
|
|
key(SCANCODE.U)
|
|
key(SCANCODE.U)
|
|
track = forgeRoom().tracks[1]
|
|
if track.boxes[2].x ~= 250 then
|
|
debugPrint("TIMELINE FAIL undo did not bring the key back to x=250: " .. tostring(track.boxes[2].x))
|
|
end
|
|
FORGE.key = 2
|
|
key(SCANCODE.DELETE)
|
|
debugPrint("TIMELINE after two undos and a delete the track has " .. #track.boxes .. " keys")
|
|
|
|
elseif stage == 7 then
|
|
-- And a new key in a new track reaches the compiled game.
|
|
key(SCANCODE.N)
|
|
key(SCANCODE.K)
|
|
key(SCANCODE.S)
|
|
local built = forgeBuild(out .. "timeline.singe")
|
|
local text = assert(io.open(built, "r")):read("a")
|
|
|
|
if text:find('name = "track3"') and text:find("at = " .. FORGE.cursor) then
|
|
debugPrint("TIMELINE the compiled game carries the new track and its key")
|
|
else
|
|
debugPrint("TIMELINE FAIL the new track is missing from the compiled game")
|
|
end
|
|
debugPrint("TIMELINE RESULT done")
|
|
end
|
|
end
|
|
|
|
|
|
function onOverlayUpdate()
|
|
frames = frames + 1
|
|
if frames % 14 == 0 and stage < 8 then
|
|
stage = stage + 1
|
|
step()
|
|
end
|
|
forgeDraw(nil, nil)
|
|
colorForeground(255, 255, 255, 255)
|
|
fontPrint(210, 8, "timeline, stage " .. stage)
|
|
if frames == 44 or frames == 72 or frames == 100 then
|
|
singeScreenshot()
|
|
end
|
|
if frames > 130 then
|
|
singeQuit()
|
|
end
|
|
|
|
return OVERLAY_UPDATED
|
|
end
|