178 lines
5.6 KiB
Text
178 lines
5.6 KiB
Text
-- The event sheet (FORGE.md): rules edited, not just entities moved.
|
|
--
|
|
-- Driven by keys, which is how the editor is meant to be used and how the bundled menu's document
|
|
-- has always been driven. What is asserted is that an edit made through the rule editor reaches
|
|
-- the compiled game -- adding a condition has to change what the game actually does.
|
|
-- As a library: the tail of Forge.singe that launches it is skipped, because this scene
|
|
-- drives it rather than being it.
|
|
FORGE_LIBRARY = true
|
|
dofile("Forge/Forge.singe")
|
|
|
|
local font = fontLoad("Singe/FreeSansBold.ttf", 15)
|
|
local out = singeGetDataPath()
|
|
local work = out .. "rules.game"
|
|
|
|
fontSelect(font)
|
|
fontQuality(FONT_QUALITY_BLENDED)
|
|
overlaySetResolution(720, 480)
|
|
|
|
local source = assert(io.open("testScripts/author/platformer.game", "r"))
|
|
local copy = assert(io.open(work, "w"))
|
|
|
|
copy:write(source:read("a"))
|
|
source:close()
|
|
copy:close()
|
|
|
|
if not forgeBegin(work) then
|
|
debugPrint("RULES FAIL could not open " .. work)
|
|
singeQuit()
|
|
end
|
|
|
|
local frames = 0
|
|
local stage = 0
|
|
local before = ""
|
|
|
|
|
|
-- The engine hands onKeyPressed two integers, so the test does too. Passing the SCANCODE table
|
|
-- instead made every comparison in forgeKey false and the test still passed, which is worse than
|
|
-- failing: the keyboard did nothing for a real user and nothing said so.
|
|
local function key(code, character)
|
|
forgeKey(character or 0, code.value)
|
|
end
|
|
|
|
|
|
local function compiled()
|
|
FORGE.game.source = work
|
|
|
|
return authorCompile(FORGE.game)
|
|
end
|
|
|
|
|
|
local function step()
|
|
if stage == 1 then
|
|
key(SCANCODE.TAB) -- entities to types,
|
|
key(SCANCODE.TAB) -- types to rules.
|
|
debugPrint("RULES mode is now " .. FORGE.mode .. ", rules " .. #FORGE.game.rules)
|
|
|
|
elseif stage == 2 then
|
|
-- Walk to the second rule the way the arrow keys do.
|
|
key(SCANCODE.DOWN)
|
|
key(SCANCODE.DOWN)
|
|
key(SCANCODE.DOWN)
|
|
debugPrint("RULES at rule " .. FORGE.rule .. " part " .. FORGE.part)
|
|
|
|
elseif stage == 3 then
|
|
before = compiled()
|
|
-- A new rule, then a condition and an action on it, all from the manifest.
|
|
forgeRuleNew("jump with the up arrow too")
|
|
forgeRuleAdd("when", "keyHeld")
|
|
forgePartSet("key", "UP")
|
|
forgeRuleAdd("when", "onGround")
|
|
forgePartSet("entity", "hero")
|
|
forgeRuleAdd("act", "jump")
|
|
forgePartSet("entity", "hero")
|
|
debugPrint("RULES built a rule with " .. #forgeParts(FORGE.game.rules[FORGE.rule]) .. " parts")
|
|
|
|
elseif stage == 4 then
|
|
local after = compiled()
|
|
|
|
if after == before then
|
|
debugPrint("RULES FAIL the new rule did not reach the compiled game")
|
|
elseif after:find('authorKeyHeld%(SCANCODE%.UP%.value%)') and after:find('authorOnGround%(authorEntity%("hero"%)%)') and after:find('authorJump%(authorEntity%("hero"%)%)') then
|
|
debugPrint("RULES the compiled game carries the new rule")
|
|
else
|
|
debugPrint("RULES FAIL the compiled game is missing part of the new rule")
|
|
end
|
|
|
|
elseif stage == 5 then
|
|
-- And deleting a part has to take it back out again.
|
|
FORGE.part = 1
|
|
forgePartDelete()
|
|
local after = compiled()
|
|
|
|
if after:find('authorKeyHeld%(SCANCODE%.UP%.value%)') then
|
|
debugPrint("RULES FAIL the deleted condition is still compiled")
|
|
else
|
|
debugPrint("RULES the deleted condition is gone from the compiled game")
|
|
end
|
|
|
|
elseif stage == 6 then
|
|
-- Type a value the way a person does: ENTER opens the first parameter, characters go in,
|
|
-- ENTER commits. Rule 1 is "Run left", whose only condition is keyHeld with key = LEFT.
|
|
FORGE.rule = 1
|
|
FORGE.part = 1
|
|
key(SCANCODE.RETURN)
|
|
for c in string.gmatch("RIGHT", ".") do
|
|
key(SCANCODE.A, string.byte(c))
|
|
end
|
|
key(SCANCODE.RETURN)
|
|
local typed = FORGE.game.rules[1].when[1]
|
|
|
|
if typed.key == "RIGHT" then
|
|
debugPrint("RULES typed a value in: key = " .. tostring(typed.key))
|
|
else
|
|
debugPrint("RULES FAIL typing did not reach the rule: key = " .. tostring(typed.key))
|
|
end
|
|
|
|
elseif stage == 7 then
|
|
-- A number has to come back a number: "100" and 100 compile to different source, so a
|
|
-- retyped value that turned into a string would stop the description round-tripping.
|
|
-- Rule 4 is "Take the prize", on a collision; its first part is addScore, whose value is
|
|
-- amount.
|
|
FORGE.rule = 4
|
|
FORGE.part = 1
|
|
key(SCANCODE.RETURN)
|
|
for c in string.gmatch("250", ".") do
|
|
key(SCANCODE.A, string.byte(c))
|
|
end
|
|
key(SCANCODE.RETURN)
|
|
local amount = FORGE.game.rules[4].act[1].amount
|
|
|
|
if amount == 250 and type(amount) == "number" then
|
|
debugPrint("RULES a typed number is a number: " .. tostring(amount))
|
|
else
|
|
debugPrint("RULES FAIL amount is " .. type(amount) .. " " .. tostring(amount))
|
|
end
|
|
|
|
-- And ESC has to put back what was there: the second part is destroy, on other.
|
|
FORGE.part = 2
|
|
key(SCANCODE.RETURN)
|
|
key(SCANCODE.A, string.byte("Z"))
|
|
key(SCANCODE.ESCAPE)
|
|
if FORGE.game.rules[4].act[2].entity == "other" then
|
|
debugPrint("RULES escape put the value back")
|
|
else
|
|
debugPrint("RULES FAIL escape left " .. tostring(FORGE.game.rules[4].act[2].entity))
|
|
end
|
|
|
|
elseif stage == 8 then
|
|
key(SCANCODE.S)
|
|
local reloaded = authorLoad(work)
|
|
local last = reloaded.rules[#reloaded.rules]
|
|
|
|
debugPrint("RULES saved; last rule is now '" .. tostring(last.note) .. "' with " .. #(last.when or {}) .. " conditions")
|
|
debugPrint("RULES RESULT done")
|
|
end
|
|
end
|
|
|
|
|
|
function onOverlayUpdate()
|
|
frames = frames + 1
|
|
if frames % 14 == 0 and stage < 9 then
|
|
stage = stage + 1
|
|
step()
|
|
end
|
|
|
|
forgeDraw(nil, nil)
|
|
colorForeground(255, 255, 255, 255)
|
|
fontPrint(210, 455, "event sheet, stage " .. stage)
|
|
|
|
if frames == 16 or frames == 44 or frames == 62 or frames == 96 then
|
|
singeScreenshot()
|
|
end
|
|
if frames > 150 then
|
|
singeQuit()
|
|
end
|
|
|
|
return OVERLAY_UPDATED
|
|
end
|