208 lines
5.5 KiB
Text
208 lines
5.5 KiB
Text
-- Forge tutorial 5, "A quick-time event": the kit's clip as the disc, two windows that want a
|
|
-- key, a hit and a miss for each, lives, and the clip looping. Starts from New game.
|
|
TUTORIAL = { number = 5, name = "05-qte", tag = "TUTORIAL5" }
|
|
dofile("testScripts/tutorialDrive.singe")
|
|
|
|
local frames = 0
|
|
local stage = 0
|
|
local game = nil
|
|
local pressed = false
|
|
local shot = false
|
|
|
|
tutorialBegin(nil)
|
|
|
|
|
|
local function lightType(name)
|
|
local names = {}
|
|
local from, to = 1, 1
|
|
|
|
for typeName in pairs(FORGE.game.types) do
|
|
names[#names + 1] = typeName
|
|
end
|
|
table.sort(names)
|
|
for at, typeName in ipairs(names) do
|
|
if typeName == FORGE.typeName then
|
|
from = at
|
|
end
|
|
if typeName == name then
|
|
to = at
|
|
end
|
|
end
|
|
for _ = 1, math.abs(to - from) do
|
|
key((to > from) and SCANCODE.DOWN or SCANCODE.UP)
|
|
end
|
|
end
|
|
|
|
|
|
local function ruleGo(index, part)
|
|
local guard = 0
|
|
|
|
while ((FORGE.rule ~= index) or (FORGE.part ~= (part or 0))) and (guard < 60) do
|
|
local past = (FORGE.rule > index) or ((FORGE.rule == index) and (FORGE.part > (part or 0)))
|
|
|
|
key(past and SCANCODE.UP or SCANCODE.DOWN)
|
|
guard = guard + 1
|
|
end
|
|
end
|
|
|
|
|
|
local function place(x, y)
|
|
key(SCANCODE.MAIN_1)
|
|
key(SCANCODE.A)
|
|
local entry = forgeRoom().entities[FORGE.selected]
|
|
|
|
forgePress(entry.x, entry.y)
|
|
forgeDrag(x, y)
|
|
forgeRelease()
|
|
end
|
|
|
|
|
|
local function rule(note, on, filters)
|
|
key(SCANCODE.N)
|
|
form("note", note)
|
|
key(SCANCODE.E)
|
|
pick(on)
|
|
for _, pair in ipairs(filters or {}) do
|
|
form(pair[1], pair[2])
|
|
end
|
|
end
|
|
|
|
|
|
local function part(partKey, name, fields)
|
|
key(partKey)
|
|
pick(name)
|
|
for _, pair in ipairs(fields or {}) do
|
|
form(pair[1], pair[2])
|
|
end
|
|
end
|
|
|
|
|
|
-- One window: the prompt while it is open, the hit once, and the miss when it closes unanswered.
|
|
local function window(name, from, to, keyName, prompt)
|
|
rule("Window " .. name .. " is open", "frame", {})
|
|
part(SCANCODE.C, "discBetween", { { "from", from }, { "to", to } })
|
|
part(SCANCODE.T, "setText", { { "entity", "prompt" }, { "text", '"' .. prompt .. '"' } })
|
|
rule("Window " .. name .. " answered in time", "frame", {})
|
|
part(SCANCODE.C, "discBetween", { { "from", from }, { "to", to } })
|
|
part(SCANCODE.C, "keyPressed", { { "key", keyName } })
|
|
part(SCANCODE.C, "once", { { "tag", name } })
|
|
part(SCANCODE.T, "setVar", { { "name", "hit" .. name }, { "value", "true" } })
|
|
clear("entity")
|
|
part(SCANCODE.T, "addScore", { { "amount", 250 } })
|
|
part(SCANCODE.T, "setText", { { "entity", "verdict" }, { "text", '"HIT"' } })
|
|
rule("Window " .. name .. " closed unanswered", "frameReached", { { "frame", to } })
|
|
part(SCANCODE.C, "test", { { "expr", "not hit" .. name } })
|
|
part(SCANCODE.T, "addVar", { { "name", "lives" }, { "amount", -1 } })
|
|
clear("entity")
|
|
part(SCANCODE.T, "setText", { { "entity", "verdict" }, { "text", '"MISS"' } })
|
|
part(SCANCODE.T, "setText", { { "entity", "prompt" }, { "text", '""' } })
|
|
end
|
|
|
|
|
|
local function step()
|
|
if stage == 1 then
|
|
key(SCANCODE.MAIN_1)
|
|
selectEntity("hero")
|
|
key(SCANCODE.DELETE)
|
|
selectEntity("ground")
|
|
key(SCANCODE.DELETE)
|
|
key(SCANCODE.MAIN_2)
|
|
lightType("hero")
|
|
key(SCANCODE.DELETE)
|
|
lightType("ground")
|
|
key(SCANCODE.DELETE)
|
|
key(SCANCODE.MAIN_3)
|
|
ruleGo(1, 0)
|
|
key(SCANCODE.DELETE)
|
|
key(SCANCODE.DELETE)
|
|
key(SCANCODE.DELETE)
|
|
key(SCANCODE.MAIN_1)
|
|
forgeSelect(nil)
|
|
form("title", "Moments")
|
|
form("vars", "score=0, lives=3")
|
|
form("layers", "disc, overlay")
|
|
form("disc.file", "clip.mkv")
|
|
tutorialShot("disc")
|
|
|
|
elseif stage == 2 then
|
|
key(SCANCODE.MAIN_2)
|
|
key(SCANCODE.A)
|
|
form("name", "prompt")
|
|
form("look", "text")
|
|
form("look.r", 255)
|
|
form("look.g", 220)
|
|
form("look.b", 80)
|
|
place(250, 60)
|
|
key(SCANCODE.MAIN_2)
|
|
key(SCANCODE.A)
|
|
form("name", "verdict")
|
|
form("look", "text")
|
|
form("look.r", 160)
|
|
form("look.g", 255)
|
|
form("look.b", 180)
|
|
place(250, 100)
|
|
tutorialShot("prompts")
|
|
|
|
elseif stage == 3 then
|
|
key(SCANCODE.MAIN_3)
|
|
window("one", 72, 120, "SPACE", "PRESS!")
|
|
tutorialShot("window")
|
|
elseif stage == 4 then
|
|
window("two", 150, 200, "UP", "UP!")
|
|
rule("The clip runs out: round again", "frameReached", { { "frame", 280 } })
|
|
part(SCANCODE.T, "setVar", { { "name", "hitone" }, { "value", "false" } })
|
|
clear("entity")
|
|
part(SCANCODE.T, "setVar", { { "name", "hittwo" }, { "value", "false" } })
|
|
clear("entity")
|
|
part(SCANCODE.T, "setText", { { "entity", "verdict" }, { "text", '""' } })
|
|
part(SCANCODE.T, "discTo", { { "frame", 1 } })
|
|
rule("Out of lives", "frame", {})
|
|
part(SCANCODE.C, "test", { { "expr", "lives <= 0" } })
|
|
part(SCANCODE.T, "gameOver", {})
|
|
ruleGo(1, 1)
|
|
form("text", '"score " .. score .. " lives " .. lives')
|
|
tutorialShot("rules")
|
|
|
|
elseif stage == 5 then
|
|
key(SCANCODE.S)
|
|
local built = tutorialEnd()
|
|
local mine = onOverlayUpdate
|
|
|
|
dofile(built)
|
|
game = onOverlayUpdate
|
|
onOverlayUpdate = mine
|
|
end
|
|
end
|
|
|
|
|
|
function onOverlayUpdate()
|
|
frames = frames + 1
|
|
if frames % 12 == 0 and stage < 5 then
|
|
stage = stage + 1
|
|
step()
|
|
end
|
|
if game ~= nil then
|
|
local frame = discGetFrame()
|
|
|
|
if (frame >= 84) and not pressed then
|
|
pressed = true
|
|
authorKeyDown(0, SCANCODE.SPACE.value)
|
|
end
|
|
if (frame >= 100) and not shot then
|
|
shot = true
|
|
tutorialShot("playing")
|
|
end
|
|
if frame >= 210 then
|
|
debugPrint(string.format("%s at frame %d the score is %s with %s lives", TUTORIAL.tag, frame, tostring(AUTHOR_VARS.score), tostring(AUTHOR_VARS.lives)))
|
|
if (AUTHOR_VARS.score ~= 250) or (AUTHOR_VARS.lives ~= 2) then
|
|
debugPrint(TUTORIAL.tag .. " FAIL window one should be hit and window two missed")
|
|
end
|
|
debugPrint(TUTORIAL.tag .. " RESULT done")
|
|
singeQuit()
|
|
end
|
|
return game()
|
|
end
|
|
forgeDraw(nil, nil)
|
|
|
|
return OVERLAY_UPDATED
|
|
end
|