More Forge work.
This commit is contained in:
parent
2819449810
commit
79e5fce23e
158 changed files with 8509 additions and 883 deletions
55
CHANGELOG
55
CHANGELOG
|
|
@ -7,6 +7,61 @@ SINGE 3.00
|
||||||
API Changes
|
API Changes
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
- singeScreenshot takes an optional file name, so a script that makes
|
||||||
|
pictures on purpose can name them.
|
||||||
|
|
||||||
|
- guiDraw's place in a script's drawing now decides what is over the GUI:
|
||||||
|
what is drawn on the overlay after the call goes on a layer composited
|
||||||
|
over that document, so a gun's sight or a pointer drawn after the HUD
|
||||||
|
shows over it. Before, every GUI was drawn over the whole overlay.
|
||||||
|
|
||||||
|
- onTextInput, in MODE_FULL: the text a key press produced, shifted and
|
||||||
|
laid out as typed, since a keysym is the unshifted key and a script
|
||||||
|
reading keysyms could never type a capital or a quote.
|
||||||
|
|
||||||
|
- In MODE_FULL a pad or mouse button reaches the script as the switch it
|
||||||
|
is mapped to, as the manual always said; it arrived as a keysym of 0.
|
||||||
|
|
||||||
|
- guiSetHandler set again after a document's elements were rebuilt (a
|
||||||
|
list through inner_rml) now attaches to the new element with that id.
|
||||||
|
It kept the old listener, on an element that no longer existed, so a
|
||||||
|
rebuilt list's rows stopped answering clicks.
|
||||||
|
|
||||||
|
- TAB reaches a script even when a GUI document is up: RmlUi took it for
|
||||||
|
moving focus and never handed it back, so a game whose keys include
|
||||||
|
TAB lost it. It goes to the GUI only while a text field is being typed
|
||||||
|
in.
|
||||||
|
|
||||||
|
- Forge has tutorials: ten sittings at the front of Forge.pdf, each
|
||||||
|
ending with a game that plays, with the kit of pictures, sounds, a clip,
|
||||||
|
and a model they use packed in Forge.game, and the finished description
|
||||||
|
of each in the chooser. Each tutorial's scene presses the keys the text
|
||||||
|
names and checks the result, so the book cannot drift from the editor.
|
||||||
|
On the way the editor gained the game's own form (title, players, vars,
|
||||||
|
verbs, layers, and each layer's parameters), the digits as panel keys,
|
||||||
|
DELETE to empty a field, X to release a game with every file it names,
|
||||||
|
a file picker that keeps an unset field unset, and a panel that steps
|
||||||
|
aside while a polygon is drawn. What an entity is made from is now a
|
||||||
|
type, not a kind: types = { hero = ... } in a description, type = "hero"
|
||||||
|
on an entity and in an event's filter, and the Types panel. Forge's
|
||||||
|
launcher takes every key (MODE_FULL), so ENTER and TAB reach it, and
|
||||||
|
its panel's rows and fields take clicks. A value is edited in place:
|
||||||
|
it starts selected, so typing replaces it, and the arrows put a caret
|
||||||
|
into it. A field whose values are a fixed set opens a dropdown of them
|
||||||
|
-- true and false, the scancodes, the switches, the looks, the events,
|
||||||
|
the words a parameter takes, the game's own types, rooms, entities,
|
||||||
|
states, tracks, and nodes -- opened on the value it has, under its own
|
||||||
|
row, upward when there is no room below. The panel's list and fields
|
||||||
|
box scroll, with bars, and keep the chosen row in view. The game's
|
||||||
|
name at the top of the panel, or a press on empty canvas, brings the
|
||||||
|
game's own form back. A waves track (W in the tracks) spawns a type
|
||||||
|
by count and interval at a moment, a disc frame, or a rail camera's
|
||||||
|
stop, from an entity or a list of them in turn, or at a point; and
|
||||||
|
soundDone says when a clip playSound or a sound behaviour started has
|
||||||
|
ended. Flat
|
||||||
|
bodies are the size their looks are drawn at (they were half), and a
|
||||||
|
platformer stands on its point.
|
||||||
|
|
||||||
- spriteFlip mirrors a sprite left to right, top to bottom, or both, for
|
- spriteFlip mirrors a sprite left to right, top to bottom, or both, for
|
||||||
every draw of it, its frames included, so art that faces one way is
|
every draw of it, its frames included, so art that faces one way is
|
||||||
enough for a character that walks both ways.
|
enough for a character that walks both ways.
|
||||||
|
|
|
||||||
|
|
@ -309,11 +309,14 @@ if(LUA_INTERPRETER)
|
||||||
COMMENT "Writing the Forge vocabulary"
|
COMMENT "Writing the Forge vocabulary"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
# The book embeds the tutorials' pictures and includes their shipped descriptions, so any of
|
||||||
|
# those changing renders it again; the globs are re-run on every build.
|
||||||
|
file(GLOB_RECURSE FORGE_BOOK_PARTS CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/docs/images/tutorials/* ${CMAKE_SOURCE_DIR}/assets/Forge/tutorials/*.game)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${MANUAL_DIR}/Forge.pdf
|
OUTPUT ${MANUAL_DIR}/Forge.pdf
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${MANUAL_DIR}
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${MANUAL_DIR}
|
||||||
COMMAND ${ASCIIDOCTOR_PDF} -a revnumber=${PROJECT_VERSION} ${CMAKE_SOURCE_DIR}/docs/Forge.adoc -o ${MANUAL_DIR}/Forge.pdf
|
COMMAND ${ASCIIDOCTOR_PDF} -a revnumber=${PROJECT_VERSION} ${CMAKE_SOURCE_DIR}/docs/Forge.adoc -o ${MANUAL_DIR}/Forge.pdf
|
||||||
DEPENDS docs/Forge.adoc docs/ForgeVocabulary.adoc
|
DEPENDS docs/Forge.adoc docs/ForgeVocabulary.adoc ${FORGE_BOOK_PARTS}
|
||||||
COMMENT "Rendering Forge.pdf"
|
COMMENT "Rendering Forge.pdf"
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
-- The compiler: a game description to a Singe game (FORGE.md).
|
-- The compiler: a game description to a Singe game (FORGE.md).
|
||||||
--
|
--
|
||||||
-- A description is data -- kinds, rooms, and rules -- and what comes out is a Lua script that
|
-- A description is data -- types, rooms, and rules -- and what comes out is a Lua script that
|
||||||
-- calls the runtime in Author.singe. The rules become real functions: a condition is a Lua
|
-- calls the runtime in Author.singe. The rules become real functions: a condition is a Lua
|
||||||
-- expression, an action a statement, and a rule with an action that takes time a coroutine. The
|
-- expression, an action a statement, and a rule with an action that takes time a coroutine. The
|
||||||
-- description travels with the game so it can be opened again; nothing is lost in either
|
-- description travels with the game so it can be opened again; nothing is lost in either
|
||||||
|
|
@ -80,6 +80,19 @@ local OPERATORS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- The keys of a table in name order, so anything written from one is written the same way each time.
|
||||||
|
local function sortedKeys(t)
|
||||||
|
local keys = {}
|
||||||
|
|
||||||
|
for key in pairs(t or {}) do
|
||||||
|
keys[#keys + 1] = key
|
||||||
|
end
|
||||||
|
table.sort(keys, function(a, b) return tostring(a) < tostring(b) end)
|
||||||
|
|
||||||
|
return keys
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local function tokenize(text)
|
local function tokenize(text)
|
||||||
local tokens = {}
|
local tokens = {}
|
||||||
local at = 1
|
local at = 1
|
||||||
|
|
@ -348,11 +361,18 @@ local function fragment(kind, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- A part's parameters as Lua. One the author left empty takes the manifest's default for it,
|
||||||
|
-- and one with neither becomes nil, which the checker has already pointed out.
|
||||||
local function fragments(entry, item)
|
local function fragments(entry, item)
|
||||||
local out = {}
|
local out = {}
|
||||||
|
|
||||||
for key, kind in pairs(entry.params or {}) do
|
for key, kind in pairs(entry.params or {}) do
|
||||||
out[key] = fragment(kind, item[key])
|
local value = item[key]
|
||||||
|
|
||||||
|
if (value == nil) and entry.defaults then
|
||||||
|
value = entry.defaults[key]
|
||||||
|
end
|
||||||
|
out[key] = fragment(kind, value) or "nil"
|
||||||
end
|
end
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
@ -472,7 +492,10 @@ end
|
||||||
-- actions, compiled as a rule's are, with self and other absent.
|
-- actions, compiled as a rule's are, with self and other absent.
|
||||||
local function emitDialogue(out, name, dialogue)
|
local function emitDialogue(out, name, dialogue)
|
||||||
out[#out + 1] = INDENT .. string.format("[%q] = { start = %q, nodes = {", name, dialogue.start or "start")
|
out[#out + 1] = INDENT .. string.format("[%q] = { start = %q, nodes = {", name, dialogue.start or "start")
|
||||||
for nodeName, node in pairs(dialogue.nodes or {}) do
|
-- Nodes in name order, so the same description compiles to the same text every time.
|
||||||
|
for _, nodeName in ipairs(sortedKeys(dialogue.nodes or {})) do
|
||||||
|
local node = dialogue.nodes[nodeName]
|
||||||
|
|
||||||
out[#out + 1] = INDENT .. INDENT .. string.format("[%q] = { name = %q, who = %s, text = %s, seconds = %s, next = %s, choices = {",
|
out[#out + 1] = INDENT .. INDENT .. string.format("[%q] = { name = %q, who = %s, text = %s, seconds = %s, next = %s, choices = {",
|
||||||
nodeName, nodeName,
|
nodeName, nodeName,
|
||||||
node.who and string.format("%q", node.who) or "nil",
|
node.who and string.format("%q", node.who) or "nil",
|
||||||
|
|
@ -632,13 +655,13 @@ end
|
||||||
|
|
||||||
-- ===== Checking ===============================================================================
|
-- ===== Checking ===============================================================================
|
||||||
--
|
--
|
||||||
-- What the compiler can tell an author before the game runs: a kind that is not declared, a
|
-- What the compiler can tell an author before the game runs: a type that is not declared, a
|
||||||
-- condition the manifest does not have, an expression that does not parse. Returns a list of
|
-- condition the manifest does not have, an expression that does not parse. Returns a list of
|
||||||
-- messages, empty when the description is sound.
|
-- messages, empty when the description is sound.
|
||||||
|
|
||||||
function authorCheck(game)
|
function authorCheck(game)
|
||||||
local problems = {}
|
local problems = {}
|
||||||
local kinds = game.kinds or {}
|
local types = game.types or {}
|
||||||
|
|
||||||
local function problem(text)
|
local function problem(text)
|
||||||
problems[#problems + 1] = text
|
problems[#problems + 1] = text
|
||||||
|
|
@ -658,8 +681,10 @@ function authorCheck(game)
|
||||||
if not ok then
|
if not ok then
|
||||||
problem(where .. ": " .. tostring(err))
|
problem(where .. ": " .. tostring(err))
|
||||||
end
|
end
|
||||||
elseif (kind == "kind") and (item[key] ~= nil) and (kinds[item[key]] == nil) then
|
elseif (kind == "type") and (item[key] ~= nil) and (types[item[key]] == nil) then
|
||||||
problem(where .. ": no kind called '" .. tostring(item[key]) .. "'")
|
problem(where .. ": no type called '" .. tostring(item[key]) .. "'")
|
||||||
|
elseif (item[key] == nil) and (kind ~= "entity") and ((entry.defaults or {})[key] == nil) and not (entry.optional or {})[key] then
|
||||||
|
problem(where .. ": " .. key .. " is empty")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -676,32 +701,47 @@ function authorCheck(game)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for name, kind in pairs(kinds) do
|
for name, entityType in pairs(types) do
|
||||||
local look = kind.look and AUTHOR.looks[kind.look.kind] or nil
|
local look = entityType.look and AUTHOR.looks[entityType.look.kind] or nil
|
||||||
|
|
||||||
if kind.look and (look == nil) then
|
if entityType.look and (look == nil) then
|
||||||
problem("kind " .. name .. ": no look called '" .. tostring(kind.look.kind) .. "'")
|
problem("type " .. name .. ": no look called '" .. tostring(entityType.look.kind) .. "'")
|
||||||
elseif look then
|
elseif look then
|
||||||
checkFields(kind.look, look.params, { kind = true }, "kind " .. name .. "'s look")
|
checkFields(entityType.look, look.params, { kind = true }, "type " .. name .. "'s look")
|
||||||
end
|
end
|
||||||
for _, b in ipairs(kind.behaviours or {}) do
|
for _, b in ipairs(entityType.behaviours or {}) do
|
||||||
local behaviour = AUTHOR.behaviours[b.kind]
|
local behaviour = AUTHOR.behaviours[b.kind]
|
||||||
|
|
||||||
if behaviour == nil then
|
if behaviour == nil then
|
||||||
problem("kind " .. name .. ": no behaviour called '" .. tostring(b.kind) .. "'")
|
problem("type " .. name .. ": no behaviour called '" .. tostring(b.kind) .. "'")
|
||||||
else
|
else
|
||||||
checkFields(b, behaviour.params, { kind = true }, "kind " .. name .. "'s " .. b.kind)
|
checkFields(b, behaviour.params, { kind = true }, "type " .. name .. "'s " .. b.kind)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
checkFields(kind, { look = true, vars = true, behaviours = true }, {}, "kind " .. name)
|
checkFields(entityType, { look = true, vars = true, behaviours = true }, {}, "type " .. name)
|
||||||
end
|
end
|
||||||
if #(game.rooms or {}) == 0 then
|
if #(game.rooms or {}) == 0 then
|
||||||
problem("the game has no rooms")
|
problem("the game has no rooms")
|
||||||
end
|
end
|
||||||
for _, room in ipairs(game.rooms or {}) do
|
for _, room in ipairs(game.rooms or {}) do
|
||||||
for _, entry in ipairs(room.entities or {}) do
|
for _, entry in ipairs(room.entities or {}) do
|
||||||
if kinds[entry.kind] == nil then
|
if types[entry.type] == nil then
|
||||||
problem("room " .. tostring(room.name) .. ": no kind called '" .. tostring(entry.kind) .. "'")
|
problem("room " .. tostring(room.name) .. ": no type called '" .. tostring(entry.type) .. "'")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- A waves track's keys name a type, and are at a moment -- or at a stop, when keyed by one.
|
||||||
|
for _, track in ipairs(room.tracks or {}) do
|
||||||
|
for index, key in ipairs(track.spawns or {}) do
|
||||||
|
local where = "room " .. tostring(room.name) .. ", track " .. tostring(track.name) .. ", wave " .. index
|
||||||
|
|
||||||
|
if types[key.type] == nil then
|
||||||
|
problem(where .. ": no type called '" .. tostring(key.type) .. "'")
|
||||||
|
end
|
||||||
|
if (track.key == "stop") and (type(key.at) ~= "string") then
|
||||||
|
problem(where .. ": at should name a stop")
|
||||||
|
elseif (track.key ~= "stop") and (type(key.at) ~= "number") then
|
||||||
|
problem(where .. ": at should be a number")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -713,8 +753,8 @@ function authorCheck(game)
|
||||||
elseif AUTHOR.events[rule.on or "frame"] then
|
elseif AUTHOR.events[rule.on or "frame"] then
|
||||||
checkFields(rule, AUTHOR.events[rule.on or "frame"].filter, { note = true, on = true, each = true, room = true, when = true, act = true, controls = true, interrupt = true }, where)
|
checkFields(rule, AUTHOR.events[rule.on or "frame"].filter, { note = true, on = true, each = true, room = true, when = true, act = true, controls = true, interrupt = true }, where)
|
||||||
end
|
end
|
||||||
if rule.each and (kinds[rule.each] == nil) then
|
if rule.each and (types[rule.each] == nil) then
|
||||||
problem(where .. ": no kind called '" .. tostring(rule.each) .. "'")
|
problem(where .. ": no type called '" .. tostring(rule.each) .. "'")
|
||||||
end
|
end
|
||||||
checkItems(AUTHOR.conditions, rule.when, "condition", where)
|
checkItems(AUTHOR.conditions, rule.when, "condition", where)
|
||||||
checkItems(AUTHOR.conditions, rule.when and rule.when.any, "condition", where)
|
checkItems(AUTHOR.conditions, rule.when and rule.when.any, "condition", where)
|
||||||
|
|
@ -755,6 +795,7 @@ function authorCompile(game)
|
||||||
-- chunk actually running, either way.
|
-- chunk actually running, either way.
|
||||||
out[#out + 1] = 'local here = ((debug.getinfo(1, "S").source:gsub("^@", "")):match("^(.*[/\\\\])") or "")'
|
out[#out + 1] = 'local here = ((debug.getinfo(1, "S").source:gsub("^@", "")):match("^(.*[/\\\\])") or "")'
|
||||||
out[#out + 1] = 'dofile(here .. "Author.singe")'
|
out[#out + 1] = 'dofile(here .. "Author.singe")'
|
||||||
|
out[#out + 1] = "AUTHOR_DIR = here -- Files the description names are looked for here first."
|
||||||
out[#out + 1] = ""
|
out[#out + 1] = ""
|
||||||
out[#out + 1] = "-- The description, as the runtime wants it: everything but the rules, which follow as code."
|
out[#out + 1] = "-- The description, as the runtime wants it: everything but the rules, which follow as code."
|
||||||
out[#out + 1] = "authorBegin(" .. valueSource(data, 0) .. ")"
|
out[#out + 1] = "authorBegin(" .. valueSource(data, 0) .. ")"
|
||||||
|
|
@ -770,21 +811,22 @@ function authorCompile(game)
|
||||||
if game.dialogues then
|
if game.dialogues then
|
||||||
out[#out + 1] = "-- The dialogues: nodes of a line and choices, each choice's condition and actions as code."
|
out[#out + 1] = "-- The dialogues: nodes of a line and choices, each choice's condition and actions as code."
|
||||||
out[#out + 1] = "authorDialogues({"
|
out[#out + 1] = "authorDialogues({"
|
||||||
for name, dialogue in pairs(game.dialogues) do
|
for _, name in ipairs(sortedKeys(game.dialogues)) do
|
||||||
emitDialogue(out, name, dialogue)
|
emitDialogue(out, name, game.dialogues[name])
|
||||||
end
|
end
|
||||||
out[#out + 1] = "})"
|
out[#out + 1] = "})"
|
||||||
out[#out + 1] = ""
|
out[#out + 1] = ""
|
||||||
end
|
end
|
||||||
out[#out + 1] = "onKeyPressed = authorKeyDown"
|
out[#out + 1] = "onKeyPressed = authorKeyDown"
|
||||||
out[#out + 1] = "onKeyReleased = authorKeyUp"
|
out[#out + 1] = "onKeyReleased = authorKeyUp"
|
||||||
out[#out + 1] = "onInputPressed = authorSwitchDown"
|
out[#out + 1] = "onInputPressed = authorSwitchDown"
|
||||||
out[#out + 1] = "onInputReleased = authorSwitchUp"
|
out[#out + 1] = "onInputReleased = authorSwitchUp"
|
||||||
out[#out + 1] = "onMouseMoved = authorMouseMoved"
|
out[#out + 1] = "onMouseMoved = authorMouseMoved"
|
||||||
out[#out + 1] = "onCollision = authorCollision"
|
out[#out + 1] = "onCollision = authorCollision"
|
||||||
out[#out + 1] = "onTrigger = authorTrigger"
|
out[#out + 1] = "onTrigger = authorTrigger"
|
||||||
out[#out + 1] = "onNavArrived = authorNavArrived"
|
out[#out + 1] = "onNavArrived = authorNavArrived"
|
||||||
out[#out + 1] = "onMidiMessage = authorMidi"
|
out[#out + 1] = "onMidiMessage = authorMidi"
|
||||||
|
out[#out + 1] = "onSoundCompleted = authorSoundDone"
|
||||||
out[#out + 1] = ""
|
out[#out + 1] = ""
|
||||||
out[#out + 1] = "function onOverlayUpdate()"
|
out[#out + 1] = "function onOverlayUpdate()"
|
||||||
out[#out + 1] = INDENT .. "authorFrame()"
|
out[#out + 1] = INDENT .. "authorFrame()"
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,21 @@
|
||||||
<title>forge</title>
|
<title>forge</title>
|
||||||
<link type="text/rcss" href="Singe/gui.rcss"/>
|
<link type="text/rcss" href="Singe/gui.rcss"/>
|
||||||
<style>
|
<style>
|
||||||
body { pointer-events: none; font-family: FreeSans; font-size: 13px; color: #e6e6ee; }
|
/* The body is the whole overlay, so the panel's 100% is a height: without it the panel
|
||||||
#panel { pointer-events: auto; position: absolute; left: 0px; top: 0px; width: 190px; height: 100%; background-color: #161620ff; }
|
was nothing tall, everything in it overflow, and overflow: auto on it hid it all. */
|
||||||
|
body { pointer-events: none; width: 100%; height: 100%; font-family: FreeSans; font-size: 13px; color: #e6e6ee; }
|
||||||
|
/* Rows stay focusable: RmlUi delivers a click to the nearest focusable element under the
|
||||||
|
pointer, so a row that could not take focus could not be clicked either. ENTER and SPACE
|
||||||
|
on a focused element only become a click when its tab-index is auto, and no row's is. */
|
||||||
|
/* The panel is a column: the grip and the title, then the list and the fields box, which
|
||||||
|
share what is left and each scroll (the wheel, or the bar) rather than pushing the other
|
||||||
|
off the screen. */
|
||||||
|
#panel { pointer-events: auto; position: absolute; left: 0px; top: 0px; width: 190px; height: 100%; background-color: #161620ff; display: flex; flex-direction: column; }
|
||||||
|
#grip, #title { flex: 0 0 auto; }
|
||||||
|
#list { flex: 0 1 auto; min-height: 0px; overflow-y: auto; }
|
||||||
|
scrollbarvertical { width: 5px; }
|
||||||
|
scrollbarvertical slidertrack { background-color: #1b1b28ff; }
|
||||||
|
scrollbarvertical sliderbar { background-color: #6a5a9aff; }
|
||||||
#grip { pointer-events: auto; background-color: #2a2a3cff; padding: 6px 10px; color: #ffcf4a; font-size: 15px; }
|
#grip { pointer-events: auto; background-color: #2a2a3cff; padding: 6px 10px; color: #ffcf4a; font-size: 15px; }
|
||||||
#grip:hover { background-color: #3a3a52ff; }
|
#grip:hover { background-color: #3a3a52ff; }
|
||||||
#title { margin: 0px 10px 8px 10px; color: #9aa0b4; }
|
#title { margin: 0px 10px 8px 10px; color: #9aa0b4; }
|
||||||
|
|
@ -24,8 +37,19 @@
|
||||||
.thumb.dim { color: #6a6a80; }
|
.thumb.dim { color: #6a6a80; }
|
||||||
.thumb.swatch { height: 16px; width: 16px; margin-left: 4px; margin-right: 10px; }
|
.thumb.swatch { height: 16px; width: 16px; margin-left: 4px; margin-right: 10px; }
|
||||||
.part { margin: 1px 8px 1px 18px; padding: 2px 5px; background-color: #1b1b28ff; color: #aeb4c8; font-size: 12px; }
|
.part { margin: 1px 8px 1px 18px; padding: 2px 5px; background-color: #1b1b28ff; color: #aeb4c8; font-size: 12px; }
|
||||||
|
.part:hover { background-color: #2a2a40ff; color: #e6e6ee; }
|
||||||
|
.picked { background-color: #6a5a9aff; color: #ffffff; }
|
||||||
|
#title:hover { color: #ffcf4a; }
|
||||||
.part.here { background-color: #4a3a6aff; color: #ffffff; }
|
.part.here { background-color: #4a3a6aff; color: #ffffff; }
|
||||||
#detail { margin: 14px 8px; padding: 6px; background-color: #10101aff; color: #b9bfd4; }
|
/* A field's list, unfolded under its row and floating over the rows beneath, as a dropdown
|
||||||
|
does: absolute with no top or left takes the place it would have had in the flow. */
|
||||||
|
.drop { position: absolute; z-index: 2; clip: none; width: 140px; margin: 0px 0px 0px 26px; padding: 2px 0px; background-color: #0b0b12ff; border-width: 1px; border-color: #6a5a9aff; }
|
||||||
|
.choice { margin: 0px; padding: 2px 8px; color: #aeb4c8; font-size: 12px; }
|
||||||
|
.choice:hover { background-color: #32324aff; color: #e6e6ee; }
|
||||||
|
.choice.selected { background-color: #c03c96ff; color: #ffffff; }
|
||||||
|
.choice.more { color: #6a6a80; }
|
||||||
|
.choice.more:hover { background-color: #0b0b12ff; color: #6a6a80; }
|
||||||
|
#detail { flex: 0 1 auto; min-height: 0px; overflow-y: auto; margin: 14px 8px; padding: 6px; background-color: #10101aff; color: #b9bfd4; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body id="forge">
|
<body id="forge">
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
8
assets/Forge/kit/LICENSE
Normal file
8
assets/Forge/kit/LICENSE
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
The Forge tutorial kit.
|
||||||
|
|
||||||
|
Everything here except fox.glb was drawn or synthesised by util/forgeKit.py in the
|
||||||
|
Singe source tree and is released under CC0: use it in your own games as you like.
|
||||||
|
|
||||||
|
fox.glb is the Fox from the Khronos glTF sample models, CC-BY 4.0: model by PixelMannen,
|
||||||
|
rigging and animation by tomkranis, glTF conversion by AsoboStudio and scurest.
|
||||||
|
A game that ships it should carry this credit.
|
||||||
11
assets/Forge/kit/README.txt
Normal file
11
assets/Forge/kit/README.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
The Forge tutorial kit, addressed from a game as Forge/kit/<name>.
|
||||||
|
|
||||||
|
hero.png a sprite sheet, 8 columns of 32 x 48, facing right: idle, walk x4, jump, fall, hit
|
||||||
|
enemy.png a sheet, 4 columns of 32 x 32, flapping
|
||||||
|
tiles.png a tile sheet, 4 columns of 32 x 32: grass, dirt, stone, brick
|
||||||
|
coin.png key.png crate.png door.png spike.png ship.png shot.png rock.png target.png stills
|
||||||
|
yard.png hall.png painted rooms, 720 x 480, for the adventures
|
||||||
|
jump.wav coin.wav shot.wav hit.wav click.wav door.wav clips
|
||||||
|
loop.ogg eight seconds of music that loops
|
||||||
|
clip.mkv twelve seconds of 720 x 480 video at 24 frames a second: a door opens at 3 s, a target rises at 6 s, a hand reaches at 9 s
|
||||||
|
fox.glb an animated model (see LICENSE)
|
||||||
BIN
assets/Forge/kit/click.wav
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/click.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/clip.mkv
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/clip.mkv
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/coin.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/coin.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/coin.wav
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/coin.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/crate.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/crate.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/door.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/door.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/door.wav
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/door.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/enemy.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/enemy.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/fox.glb
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/fox.glb
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/hall.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/hall.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/hero.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/hero.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/hit.wav
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/hit.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/jump.wav
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/jump.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/key.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/key.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/loop.ogg
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/loop.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/rock.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/rock.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/ship.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/ship.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/shot.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/shot.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/shot.wav
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/shot.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/spike.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/spike.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/target.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/target.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/tiles.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/tiles.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/Forge/kit/yard.png
(Stored with Git LFS)
Normal file
BIN
assets/Forge/kit/yard.png
(Stored with Git LFS)
Normal file
Binary file not shown.
76
assets/Forge/tutorials/01-tenMinutes.game
Normal file
76
assets/Forge/tutorials/01-tenMinutes.game
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
-- Written by Forge/AuthorCompile.singe. Edit by hand or in the editor; either is fine.
|
||||||
|
return {
|
||||||
|
layers = {
|
||||||
|
{ gravity = 1500, kind = "world2d" }
|
||||||
|
},
|
||||||
|
rooms = {
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "ground", type = "ground", x = 360, y = 440 },
|
||||||
|
{ id = "hero", type = "hero", x = 200, y = 420 },
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 }
|
||||||
|
},
|
||||||
|
name = "start",
|
||||||
|
tracks = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules = {
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "run", direction = -1, entity = "hero" }
|
||||||
|
},
|
||||||
|
note = "Run left",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "keyHeld", key = "LEFT" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "run", direction = 1, entity = "hero" }
|
||||||
|
},
|
||||||
|
note = "Run right",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "keyHeld", key = "RIGHT" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "jump", entity = "hero" }
|
||||||
|
},
|
||||||
|
note = "Jump, with ground underfoot",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "keyHeld", key = "SPACE" },
|
||||||
|
{ "onGround", entity = "hero" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "readout", text = "\"score \" .. score" }
|
||||||
|
},
|
||||||
|
note = "The readout, every frame",
|
||||||
|
on = "frame"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = "New game",
|
||||||
|
types = {
|
||||||
|
ground = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "solid" }
|
||||||
|
},
|
||||||
|
look = { b = 90, g = 70, h = 40, kind = "box", r = 60, w = 720 }
|
||||||
|
},
|
||||||
|
hero = {
|
||||||
|
behaviours = {
|
||||||
|
{ jump = 620, kind = "platformer", speed = 260 }
|
||||||
|
},
|
||||||
|
look = { anchor = "feet", b = 240, g = 90, h = 44, kind = "box", r = 90, w = 24 }
|
||||||
|
},
|
||||||
|
readout = {
|
||||||
|
look = { b = 245, g = 235, kind = "text", r = 235, text = "score 0" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
vars = { score = 0 }
|
||||||
|
}
|
||||||
144
assets/Forge/tutorials/02-platformer.game
Normal file
144
assets/Forge/tutorials/02-platformer.game
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
-- Written by Forge/AuthorCompile.singe. Edit by hand or in the editor; either is fine.
|
||||||
|
return {
|
||||||
|
layers = {
|
||||||
|
{ gravity = 1500, kind = "world2d" }
|
||||||
|
},
|
||||||
|
rooms = {
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "ground", type = "ground", x = 360, y = 440 },
|
||||||
|
{ id = "hero", type = "hero", x = 200, y = 420 },
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "coin", type = "coin", x = 300, y = 392 },
|
||||||
|
{ id = "coin1", type = "coin", x = 420, y = 392 },
|
||||||
|
{ id = "coin2", type = "coin", x = 560, y = 300 },
|
||||||
|
{ id = "spike", type = "spike", x = 640, y = 420 },
|
||||||
|
{ id = "door", type = "door", x = 700, y = 420 }
|
||||||
|
},
|
||||||
|
name = "start",
|
||||||
|
tracks = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "ground", type = "ground", x = 360, y = 440 },
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "coin", type = "coin", x = 400, y = 392 }
|
||||||
|
},
|
||||||
|
name = "cave",
|
||||||
|
tracks = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules = {
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "run", direction = -1, entity = "hero" }
|
||||||
|
},
|
||||||
|
note = "Run left",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "keyHeld", key = "LEFT" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "run", direction = 1, entity = "hero" }
|
||||||
|
},
|
||||||
|
note = "Run right",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "keyHeld", key = "RIGHT" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "jump", entity = "hero" }
|
||||||
|
},
|
||||||
|
note = "Jump, with ground underfoot",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "keyHeld", key = "SPACE" },
|
||||||
|
{ "onGround", entity = "hero" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "readout", text = "\"score \" .. score" }
|
||||||
|
},
|
||||||
|
note = "The readout, every frame",
|
||||||
|
on = "frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "coin",
|
||||||
|
act = {
|
||||||
|
{ "addScore", amount = 10 },
|
||||||
|
{ "destroy", entity = "self" },
|
||||||
|
{ "playSound", file = "Forge/kit/coin.wav" }
|
||||||
|
},
|
||||||
|
b = "hero",
|
||||||
|
note = "Take a coin",
|
||||||
|
on = "enter",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "spike",
|
||||||
|
act = {
|
||||||
|
{ "moveTo", entity = "hero", x = 200, y = 380 },
|
||||||
|
{ "playSound", file = "Forge/kit/hit.wav" }
|
||||||
|
},
|
||||||
|
b = "hero",
|
||||||
|
note = "Spikes hurt",
|
||||||
|
on = "enter",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "door",
|
||||||
|
act = {
|
||||||
|
{ "goTo", entity = "hero", room = "cave", x = 60, y = 380 }
|
||||||
|
},
|
||||||
|
b = "hero",
|
||||||
|
note = "Through the door",
|
||||||
|
on = "enter",
|
||||||
|
when = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = "New game",
|
||||||
|
types = {
|
||||||
|
coin = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "trigger" }
|
||||||
|
},
|
||||||
|
look = { file = "Forge/kit/coin.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
door = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "trigger" }
|
||||||
|
},
|
||||||
|
look = { anchor = "feet", file = "Forge/kit/door.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
ground = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "solid" }
|
||||||
|
},
|
||||||
|
look = { b = 90, g = 70, h = 40, kind = "box", r = 60, w = 720 }
|
||||||
|
},
|
||||||
|
hero = {
|
||||||
|
behaviours = {
|
||||||
|
{ jump = 620, kind = "platformer", speed = 260 }
|
||||||
|
},
|
||||||
|
look = { anchor = "feet", b = 240, g = 90, h = 44, kind = "box", r = 90, w = 24 }
|
||||||
|
},
|
||||||
|
readout = {
|
||||||
|
look = { b = 245, g = 235, kind = "text", r = 235, text = "score 0" }
|
||||||
|
},
|
||||||
|
spike = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "trigger" }
|
||||||
|
},
|
||||||
|
look = { anchor = "feet", file = "Forge/kit/spike.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
vars = { score = 0 }
|
||||||
|
}
|
||||||
156
assets/Forge/tutorials/03-sprites.game
Normal file
156
assets/Forge/tutorials/03-sprites.game
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
-- Written by Forge/AuthorCompile.singe. Edit by hand or in the editor; either is fine.
|
||||||
|
return {
|
||||||
|
layers = {
|
||||||
|
{ gravity = 1500, kind = "world2d" }
|
||||||
|
},
|
||||||
|
rooms = {
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "ground", type = "ground", x = 360, y = 440 },
|
||||||
|
{ id = "hero", type = "hero", x = 200, y = 420 },
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "coin", type = "coin", x = 300, y = 392 },
|
||||||
|
{ id = "coin1", type = "coin", x = 420, y = 392 },
|
||||||
|
{ id = "coin2", type = "coin", x = 560, y = 300 },
|
||||||
|
{ id = "spike", type = "spike", x = 640, y = 420 },
|
||||||
|
{ id = "door", type = "door", x = 700, y = 420 }
|
||||||
|
},
|
||||||
|
name = "start",
|
||||||
|
tracks = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "ground", type = "ground", x = 360, y = 440 },
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "coin", type = "coin", x = 400, y = 392 }
|
||||||
|
},
|
||||||
|
name = "cave",
|
||||||
|
tracks = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules = {
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "run", direction = -1, entity = "hero" }
|
||||||
|
},
|
||||||
|
note = "Run left",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "keyHeld", key = "LEFT" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "run", direction = 1, entity = "hero" }
|
||||||
|
},
|
||||||
|
note = "Run right",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "keyHeld", key = "RIGHT" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "jump", entity = "hero" },
|
||||||
|
{ "playSound", file = "Forge/kit/jump.wav" }
|
||||||
|
},
|
||||||
|
note = "Jump, with ground underfoot",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "onGround", entity = "hero" },
|
||||||
|
{ "keyPressed", key = "SPACE" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "readout", text = "\"score \" .. score" }
|
||||||
|
},
|
||||||
|
note = "The readout, every frame",
|
||||||
|
on = "frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "coin",
|
||||||
|
act = {
|
||||||
|
{ "addScore", amount = 10 },
|
||||||
|
{ "destroy", entity = "self" },
|
||||||
|
{ "playSound", file = "Forge/kit/coin.wav" }
|
||||||
|
},
|
||||||
|
b = "hero",
|
||||||
|
note = "Take a coin",
|
||||||
|
on = "enter",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "spike",
|
||||||
|
act = {
|
||||||
|
{ "moveTo", entity = "hero", x = 200, y = 380 },
|
||||||
|
{ "playSound", file = "Forge/kit/hit.wav" }
|
||||||
|
},
|
||||||
|
b = "hero",
|
||||||
|
note = "Spikes hurt",
|
||||||
|
on = "enter",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "door",
|
||||||
|
act = {
|
||||||
|
{ "goTo", entity = "hero", room = "cave", x = 60, y = 380 }
|
||||||
|
},
|
||||||
|
b = "hero",
|
||||||
|
note = "Through the door",
|
||||||
|
on = "enter",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "playMusic", file = "Forge/kit/loop.ogg" }
|
||||||
|
},
|
||||||
|
note = "Music",
|
||||||
|
on = "roomStart",
|
||||||
|
when = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = "New game",
|
||||||
|
types = {
|
||||||
|
coin = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "trigger" },
|
||||||
|
{ kind = "spin", rate = 180 }
|
||||||
|
},
|
||||||
|
look = { file = "Forge/kit/coin.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
door = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "trigger" }
|
||||||
|
},
|
||||||
|
look = { anchor = "feet", file = "Forge/kit/door.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
ground = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "solid" }
|
||||||
|
},
|
||||||
|
look = { b = 90, g = 70, h = 40, kind = "box", r = 60, w = 720 }
|
||||||
|
},
|
||||||
|
hero = {
|
||||||
|
behaviours = {
|
||||||
|
{ jump = 620, kind = "platformer", speed = 260 },
|
||||||
|
{ fps = 10, kind = "frames", states = "idle=1-1, walk=2-5, jump=6-6, fall=7-7" }
|
||||||
|
},
|
||||||
|
look = { file = "Forge/kit/hero.png", frames = 8, kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
readout = {
|
||||||
|
look = { b = 245, g = 235, kind = "text", r = 235, text = "score 0" }
|
||||||
|
},
|
||||||
|
spike = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "trigger" }
|
||||||
|
},
|
||||||
|
look = { anchor = "feet", file = "Forge/kit/spike.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
vars = { score = 0 }
|
||||||
|
}
|
||||||
135
assets/Forge/tutorials/04-shmup.game
Normal file
135
assets/Forge/tutorials/04-shmup.game
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
-- Written by Forge/AuthorCompile.singe. Edit by hand or in the editor; either is fine.
|
||||||
|
return {
|
||||||
|
types = {
|
||||||
|
hive = {
|
||||||
|
behaviours = {
|
||||||
|
{ every = 0.6, kind = "spawner", max = 6, spawns = "rock", total = 12 }
|
||||||
|
},
|
||||||
|
look = { kind = "none" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
readout = {
|
||||||
|
look = { b = 245, g = 235, kind = "text", r = 235, text = "score 0" }
|
||||||
|
},
|
||||||
|
rock = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "drift", vy = 90 },
|
||||||
|
{ kind = "health", max = 2 },
|
||||||
|
{ death = "Forge/kit/hit.wav", kind = "sound" }
|
||||||
|
},
|
||||||
|
look = { file = "Forge/kit/rock.png", kind = "sprite" },
|
||||||
|
vars = { health = 2 }
|
||||||
|
},
|
||||||
|
ship = {
|
||||||
|
behaviours = {
|
||||||
|
{ down = "DOWN", fire = "SPACE", kind = "keys", left = "LEFT", right = "RIGHT", up = "UP" },
|
||||||
|
{ clamp = true, kind = "mover", speed = 260 },
|
||||||
|
{ kind = "shooter", offsetY = -14, rate = 0.15, spawns = "shot" },
|
||||||
|
{ keep = true, kind = "health", max = 1 },
|
||||||
|
{ hit = "Forge/kit/hit.wav", kind = "sound" }
|
||||||
|
},
|
||||||
|
look = { file = "Forge/kit/ship.png", kind = "sprite" },
|
||||||
|
vars = { health = 1 }
|
||||||
|
},
|
||||||
|
shot = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "projectile", life = 3, vy = -520 },
|
||||||
|
{ kind = "sound", spawn = "Forge/kit/shot.wav" }
|
||||||
|
},
|
||||||
|
look = { file = "Forge/kit/shot.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layers = {
|
||||||
|
{ kind = "overlay" }
|
||||||
|
},
|
||||||
|
rooms = {
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "ship", type = "ship", x = 360, y = 420 },
|
||||||
|
{ id = "hive", type = "hive", x = 360, y = 20 },
|
||||||
|
{ id = "hive1", type = "hive", x = 560, y = 20 }
|
||||||
|
},
|
||||||
|
name = "start",
|
||||||
|
tracks = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules = {
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "readout", text = "\"score \" .. score .. \" lives \" .. lives" }
|
||||||
|
},
|
||||||
|
note = "The readout, every frame",
|
||||||
|
on = "frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "shot",
|
||||||
|
act = {
|
||||||
|
{ "destroy", entity = "self" },
|
||||||
|
{ "damage", amount = 1, entity = "other" },
|
||||||
|
{ "addScore", amount = 10 }
|
||||||
|
},
|
||||||
|
b = "rock",
|
||||||
|
note = "A shot lands on a rock",
|
||||||
|
on = "collision",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "emit", b = 60, count = 24, entity = "self", g = 120, r = 255 },
|
||||||
|
{ "addScore", amount = 50 }
|
||||||
|
},
|
||||||
|
type = "rock",
|
||||||
|
note = "A rock dies",
|
||||||
|
on = "death",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "rock",
|
||||||
|
act = {
|
||||||
|
{ "destroy", entity = "self" },
|
||||||
|
{ "damage", amount = 1, entity = "other" }
|
||||||
|
},
|
||||||
|
b = "ship",
|
||||||
|
note = "A rock rams the ship",
|
||||||
|
on = "collision",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "addVar", amount = -1, name = "lives" },
|
||||||
|
{ "flash", b = 60, g = 60, r = 255, seconds = 0.3 },
|
||||||
|
{ "setVar", entity = "self", name = "health", value = "1" },
|
||||||
|
{ "moveTo", entity = "self", x = 360, y = 420 }
|
||||||
|
},
|
||||||
|
type = "ship",
|
||||||
|
note = "The ship is lost",
|
||||||
|
on = "death",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "gameOver" }
|
||||||
|
},
|
||||||
|
note = "Out of lives",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "lives <= 0" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "destroy", entity = "self" }
|
||||||
|
},
|
||||||
|
each = "rock",
|
||||||
|
note = "A rock slips past the bottom",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "self.y > 500" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = "Rocks",
|
||||||
|
vars = { lives = 3, score = 0 }
|
||||||
|
}
|
||||||
140
assets/Forge/tutorials/05-qte.game
Normal file
140
assets/Forge/tutorials/05-qte.game
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
-- Written by Forge/AuthorCompile.singe. Edit by hand or in the editor; either is fine.
|
||||||
|
return {
|
||||||
|
types = {
|
||||||
|
prompt = {
|
||||||
|
behaviours = {},
|
||||||
|
look = { b = 80, g = 220, kind = "text", r = 255 },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
readout = {
|
||||||
|
look = { b = 245, g = 235, kind = "text", r = 235, text = "score 0" }
|
||||||
|
},
|
||||||
|
verdict = {
|
||||||
|
behaviours = {},
|
||||||
|
look = { b = 180, g = 255, kind = "text", r = 160 },
|
||||||
|
vars = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layers = {
|
||||||
|
{ file = "Forge/kit/clip.mkv", kind = "disc" },
|
||||||
|
{ kind = "overlay" }
|
||||||
|
},
|
||||||
|
rooms = {
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "prompt", type = "prompt", x = 250, y = 60 },
|
||||||
|
{ id = "verdict", type = "verdict", x = 250, y = 100 }
|
||||||
|
},
|
||||||
|
name = "start",
|
||||||
|
tracks = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules = {
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "readout", text = "\"score \" .. score .. \" lives \" .. lives" }
|
||||||
|
},
|
||||||
|
note = "The readout, every frame",
|
||||||
|
on = "frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "prompt", text = "\"PRESS!\"" }
|
||||||
|
},
|
||||||
|
note = "Window one is open",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "discBetween", from = 72, to = 120 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setVar", name = "hitone", value = true },
|
||||||
|
{ "addScore", amount = 250 },
|
||||||
|
{ "setText", entity = "verdict", text = "\"HIT\"" }
|
||||||
|
},
|
||||||
|
note = "Window one answered in time",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "discBetween", from = 72, to = 120 },
|
||||||
|
{ "keyPressed", key = "SPACE" },
|
||||||
|
{ "once", tag = "one" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "addVar", amount = -1, name = "lives" },
|
||||||
|
{ "setText", entity = "verdict", text = "\"MISS\"" },
|
||||||
|
{ "setText", entity = "prompt", text = "\"\"" }
|
||||||
|
},
|
||||||
|
frame = 120,
|
||||||
|
note = "Window one closed unanswered",
|
||||||
|
on = "frameReached",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "not hitone" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "prompt", text = "\"UP!\"" }
|
||||||
|
},
|
||||||
|
note = "Window two is open",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "discBetween", from = 150, to = 200 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setVar", name = "hittwo", value = true },
|
||||||
|
{ "addScore", amount = 250 },
|
||||||
|
{ "setText", entity = "verdict", text = "\"HIT\"" }
|
||||||
|
},
|
||||||
|
note = "Window two answered in time",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "discBetween", from = 150, to = 200 },
|
||||||
|
{ "keyPressed", key = "UP" },
|
||||||
|
{ "once", tag = "two" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "addVar", amount = -1, name = "lives" },
|
||||||
|
{ "setText", entity = "verdict", text = "\"MISS\"" },
|
||||||
|
{ "setText", entity = "prompt", text = "\"\"" }
|
||||||
|
},
|
||||||
|
frame = 200,
|
||||||
|
note = "Window two closed unanswered",
|
||||||
|
on = "frameReached",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "not hittwo" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setVar", name = "hitone", value = false },
|
||||||
|
{ "setVar", name = "hittwo", value = false },
|
||||||
|
{ "setText", entity = "verdict", text = "\"\"" },
|
||||||
|
{ "discTo", frame = 1 }
|
||||||
|
},
|
||||||
|
frame = 280,
|
||||||
|
note = "The clip runs out: round again",
|
||||||
|
on = "frameReached",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "gameOver" }
|
||||||
|
},
|
||||||
|
note = "Out of lives",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "lives <= 0" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = "Moments",
|
||||||
|
vars = { lives = 3, score = 0 }
|
||||||
|
}
|
||||||
115
assets/Forge/tutorials/06-gun.game
Normal file
115
assets/Forge/tutorials/06-gun.game
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
-- Written by Forge/AuthorCompile.singe. Edit by hand or in the editor; either is fine.
|
||||||
|
return {
|
||||||
|
types = {
|
||||||
|
gun = {
|
||||||
|
behaviours = {
|
||||||
|
{ ammo = 6, kind = "gun", player = 1, reload = "offscreen" }
|
||||||
|
},
|
||||||
|
look = { kind = "none" },
|
||||||
|
vars = { ammo = 6 }
|
||||||
|
},
|
||||||
|
hand = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "hitbox", track = "hand" }
|
||||||
|
},
|
||||||
|
look = { kind = "none" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
readout = {
|
||||||
|
look = { b = 245, g = 235, kind = "text", r = 235, text = "score 0" }
|
||||||
|
},
|
||||||
|
target = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "hitbox", track = "target" },
|
||||||
|
{ kind = "health", max = 1 }
|
||||||
|
},
|
||||||
|
look = { kind = "none" },
|
||||||
|
vars = { health = 1 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layers = {
|
||||||
|
{ file = "Forge/kit/clip.mkv", kind = "disc" },
|
||||||
|
{ kind = "overlay" }
|
||||||
|
},
|
||||||
|
rooms = {
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "gun", type = "gun", x = 30, y = 450 },
|
||||||
|
{ id = "target", type = "target", x = 450, y = 210 },
|
||||||
|
{ id = "hand", type = "hand", x = 600, y = 210 }
|
||||||
|
},
|
||||||
|
name = "start",
|
||||||
|
tracks = {
|
||||||
|
{
|
||||||
|
boxes = {
|
||||||
|
{ at = 150, h = 90, w = 90, x = 405, y = 165 },
|
||||||
|
{ at = 210, h = 90, w = 90, x = 405, y = 165 }
|
||||||
|
},
|
||||||
|
key = "frame",
|
||||||
|
name = "target"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
boxes = {
|
||||||
|
{ at = 220, h = 105, w = 240, x = 480, y = 157 },
|
||||||
|
{ at = 260, h = 105, w = 240, x = 480, y = 157 }
|
||||||
|
},
|
||||||
|
key = "frame",
|
||||||
|
name = "hand"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules = {
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "readout", text = "\"score \" .. score .. \" ammo \" .. gun.ammo .. \" misses \" .. misses" }
|
||||||
|
},
|
||||||
|
note = "The readout, every frame",
|
||||||
|
on = "frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "addScore", amount = 100 },
|
||||||
|
{ "damage", amount = 1, entity = "self" },
|
||||||
|
{ "playSound", file = "Forge/kit/hit.wav" }
|
||||||
|
},
|
||||||
|
type = "target",
|
||||||
|
note = "The target is hit",
|
||||||
|
on = "hit",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "addScore", amount = -200 },
|
||||||
|
{ "flash", b = 40, g = 40, r = 255, seconds = 0.3 }
|
||||||
|
},
|
||||||
|
type = "hand",
|
||||||
|
note = "The hand is hit",
|
||||||
|
on = "hit",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "addVar", amount = 1, name = "misses" },
|
||||||
|
{ "playSound", file = "Forge/kit/shot.wav" }
|
||||||
|
},
|
||||||
|
note = "A shot at nothing",
|
||||||
|
on = "miss",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "not event.offscreen" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "say", seconds = 1, text = "\"DRAW!\"" }
|
||||||
|
},
|
||||||
|
frame = 150,
|
||||||
|
note = "Draw!",
|
||||||
|
on = "frameReached",
|
||||||
|
when = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = "Draw",
|
||||||
|
vars = { misses = 0, score = 0 }
|
||||||
|
}
|
||||||
244
assets/Forge/tutorials/07-adventure.game
Normal file
244
assets/Forge/tutorials/07-adventure.game
Normal file
|
|
@ -0,0 +1,244 @@
|
||||||
|
-- Written by Forge/AuthorCompile.singe. Edit by hand or in the editor; either is fine.
|
||||||
|
return {
|
||||||
|
dialogues = {
|
||||||
|
guard = {
|
||||||
|
nodes = {
|
||||||
|
ok = {
|
||||||
|
choices = {},
|
||||||
|
text = "Then go ahead.",
|
||||||
|
who = "Guard"
|
||||||
|
},
|
||||||
|
start = {
|
||||||
|
choices = {
|
||||||
|
{ next = "why", text = "Why not?" },
|
||||||
|
{ text = "Fine." }
|
||||||
|
},
|
||||||
|
text = "Nobody passes.",
|
||||||
|
who = "Guard"
|
||||||
|
},
|
||||||
|
why = {
|
||||||
|
choices = {
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setVar", name = "allowed", value = true }
|
||||||
|
},
|
||||||
|
next = "ok",
|
||||||
|
text = "I have a key.",
|
||||||
|
when = "has(\"key\")"
|
||||||
|
},
|
||||||
|
{ text = "I see." }
|
||||||
|
},
|
||||||
|
text = "The door is locked, and I have no key.",
|
||||||
|
who = "Guard"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
start = "start"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
types = {
|
||||||
|
backdrop = {
|
||||||
|
behaviours = {},
|
||||||
|
look = { file = "Forge/kit/yard.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
door = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "hotspot", name = "door", walkX = 590, walkY = 330 }
|
||||||
|
},
|
||||||
|
look = { anchor = "feet", file = "Forge/kit/door.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
guard = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "hotspot", name = "guard", walkX = 480, walkY = 360 }
|
||||||
|
},
|
||||||
|
look = { anchor = "feet", faces = "left", file = "Forge/kit/hero.png", frames = 8, kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
hero = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "walker", speed = 160 },
|
||||||
|
{ fps = 10, kind = "frames", states = "idle=1-1, walk=2-5" }
|
||||||
|
},
|
||||||
|
look = { anchor = "feet", file = "Forge/kit/hero.png", frames = 8, kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
key = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "hotspot", name = "key", walkX = 200, walkY = 400 }
|
||||||
|
},
|
||||||
|
look = { file = "Forge/kit/key.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
readout = {
|
||||||
|
look = { b = 245, g = 235, kind = "text", r = 235, text = "score 0" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layers = {
|
||||||
|
{ kind = "overlay" }
|
||||||
|
},
|
||||||
|
rooms = {
|
||||||
|
{
|
||||||
|
depthSort = true,
|
||||||
|
entities = {
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "backdrop", type = "backdrop", x = 360, y = 240 },
|
||||||
|
{ id = "hero", type = "hero", x = 150, y = 440 },
|
||||||
|
{ id = "door", type = "door", x = 590, y = 300 },
|
||||||
|
{ id = "key", type = "key", x = 200, y = 380 },
|
||||||
|
{ id = "guard", type = "guard", x = 520, y = 340 }
|
||||||
|
},
|
||||||
|
name = "yard",
|
||||||
|
scaleBy = {
|
||||||
|
{ scale = 0.6, y = 300 },
|
||||||
|
{ scale = 1.0, y = 460 }
|
||||||
|
},
|
||||||
|
tracks = {},
|
||||||
|
walk = {
|
||||||
|
{ 60, 320, 660, 320, 700, 460, 40, 460 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
depthSort = true,
|
||||||
|
entities = {
|
||||||
|
{ id = "backdrop", type = "backdrop", x = 360, y = 240 },
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 }
|
||||||
|
},
|
||||||
|
name = "hall",
|
||||||
|
tracks = {},
|
||||||
|
walk = {
|
||||||
|
{ 40, 300, 680, 300, 700, 460, 40, 460 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules = {
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "readout", text = "(sentence or \"\") .. \" score \" .. score" }
|
||||||
|
},
|
||||||
|
note = "The readout, every frame",
|
||||||
|
on = "frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "walkToPointer", entity = "hero", player = 1 }
|
||||||
|
},
|
||||||
|
interrupt = true,
|
||||||
|
note = "A click on the floor walks there",
|
||||||
|
on = "pressed",
|
||||||
|
switch = "SWITCH_BUTTON3",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "say", seconds = 1, text = "\"It is a \" .. event.target .. \".\"" }
|
||||||
|
},
|
||||||
|
note = "Look at anything",
|
||||||
|
on = "verb",
|
||||||
|
verb = "look",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "walkToHotspot", entity = "hero", target = "self" },
|
||||||
|
{ "give", item = "key" },
|
||||||
|
{ "addScore", amount = 1 },
|
||||||
|
{ "destroy", entity = "self" }
|
||||||
|
},
|
||||||
|
note = "Take the key",
|
||||||
|
on = "verb",
|
||||||
|
target = "key",
|
||||||
|
verb = "take",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "walkToHotspot", entity = "hero", target = "self" },
|
||||||
|
{ "face", entity = "hero", target = "self" },
|
||||||
|
{ "talk", dialogue = "guard" }
|
||||||
|
},
|
||||||
|
note = "Talk to the guard",
|
||||||
|
on = "verb",
|
||||||
|
target = "guard",
|
||||||
|
verb = "talk",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "say", seconds = 1, text = "\"The guard shakes his head.\"" }
|
||||||
|
},
|
||||||
|
note = "The door, while the guard objects",
|
||||||
|
on = "verb",
|
||||||
|
target = "door",
|
||||||
|
verb = "open",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "not allowed" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "walkToHotspot", entity = "hero", target = "self" },
|
||||||
|
{ "playSound", file = "Forge/kit/door.wav" },
|
||||||
|
{ "fade", out = true, seconds = 0.5 },
|
||||||
|
{ "goTo", entity = "hero", room = "hall", x = 120, y = 420 },
|
||||||
|
{ "fade", out = false, seconds = 0.5 },
|
||||||
|
{ "addScore", amount = 1 }
|
||||||
|
},
|
||||||
|
controls = false,
|
||||||
|
note = "The door opens",
|
||||||
|
on = "verb",
|
||||||
|
target = "door",
|
||||||
|
verb = "open",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "allowed" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "say", seconds = 1, text = "\"That does not work.\"" }
|
||||||
|
},
|
||||||
|
note = "Anything else",
|
||||||
|
on = "verb",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setVerb", verb = "look" }
|
||||||
|
},
|
||||||
|
key = "L",
|
||||||
|
note = "The verb keys",
|
||||||
|
on = "pressed",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setVerb", verb = "take" }
|
||||||
|
},
|
||||||
|
key = "T",
|
||||||
|
note = "Take",
|
||||||
|
on = "pressed",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setVerb", verb = "open" }
|
||||||
|
},
|
||||||
|
key = "O",
|
||||||
|
note = "Open",
|
||||||
|
on = "pressed",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setVerb", verb = "talk" }
|
||||||
|
},
|
||||||
|
key = "K",
|
||||||
|
note = "Talk",
|
||||||
|
on = "pressed",
|
||||||
|
when = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = "The Yard",
|
||||||
|
vars = { allowed = false, score = 0 },
|
||||||
|
verbs = { "walk", "look", "take", "use", "open", "talk" }
|
||||||
|
}
|
||||||
129
assets/Forge/tutorials/08-scene.game
Normal file
129
assets/Forge/tutorials/08-scene.game
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
-- Written by Forge/AuthorCompile.singe. Edit by hand or in the editor; either is fine.
|
||||||
|
return {
|
||||||
|
types = {
|
||||||
|
camera = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "camera", lag = 0.2, lookY = 0.6, mode = "follow", target = "hero", x = 0, y = 3, z = 7 }
|
||||||
|
},
|
||||||
|
look = { kind = "none" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
floor = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "solid" }
|
||||||
|
},
|
||||||
|
look = { b = 90, d = 12, g = 110, h = 0.4, kind = "mesh", r = 90, shape = "box", w = 30 },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
hero = {
|
||||||
|
behaviours = {
|
||||||
|
{ down = "DOWN", kind = "keys", left = "LEFT", right = "RIGHT", up = "UP" },
|
||||||
|
{ height = 0.9, jump = 6.5, kind = "character", radius = 0.3, speed = 4 },
|
||||||
|
{ idle = "Survey", kind = "animator", walk = "Walk" }
|
||||||
|
},
|
||||||
|
look = { d = 0.6, file = "Forge/kit/fox.glb", h = 0.9, kind = "model", scale = 0.008, w = 0.6 },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
ledge = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "solid" }
|
||||||
|
},
|
||||||
|
look = { b = 70, d = 4, g = 90, h = 0.4, kind = "mesh", r = 110, shape = "box", w = 4 },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
prize = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "trigger" }
|
||||||
|
},
|
||||||
|
look = { b = 60, g = 200, kind = "mesh", r = 255, shape = "sphere", w = 0.6 },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
readout = {
|
||||||
|
look = { b = 245, g = 235, kind = "text", r = 235, text = "score 0" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layers = {
|
||||||
|
{ fov = 55, kind = "scene3d" },
|
||||||
|
{ kind = "overlay" }
|
||||||
|
},
|
||||||
|
rooms = {
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "floor", type = "floor", x = 0.0, y = -0.2, z = 0.0 },
|
||||||
|
{ id = "ledge", type = "ledge", x = 6.0, y = 1.2, z = 0.0 },
|
||||||
|
{ id = "prize", type = "prize", x = 6.0, y = 2.0, z = 0.0 },
|
||||||
|
{ id = "hero", type = "hero", x = -4.0, y = 0.5, z = 0.0 },
|
||||||
|
{ id = "camera", type = "camera", x = -4.0, y = 3.0, z = 7.0 }
|
||||||
|
},
|
||||||
|
name = "start",
|
||||||
|
tracks = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules = {
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "readout", text = "\"score \" .. score" }
|
||||||
|
},
|
||||||
|
note = "The readout, every frame",
|
||||||
|
on = "frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setState", entity = "self", state = "walk" }
|
||||||
|
},
|
||||||
|
each = "hero",
|
||||||
|
note = "Walking is a state the animator plays",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "self.dx != 0 or self.dy != 0" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setState", entity = "self", state = "idle" }
|
||||||
|
},
|
||||||
|
each = "hero",
|
||||||
|
note = "Standing still",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "self.dx == 0 and self.dy == 0" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "jump", entity = "hero" }
|
||||||
|
},
|
||||||
|
note = "Jump, with ground underfoot",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "keyPressed", key = "SPACE" },
|
||||||
|
{ "onGround", entity = "hero" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "prize",
|
||||||
|
act = {
|
||||||
|
{ "destroy", entity = "self" },
|
||||||
|
{ "addScore", amount = 100 },
|
||||||
|
{ "playSound", file = "Forge/kit/coin.wav" }
|
||||||
|
},
|
||||||
|
b = "hero",
|
||||||
|
note = "The prize is taken",
|
||||||
|
on = "enter",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "moveTo", entity = "hero", x = -4, y = 0.5, z = 0 }
|
||||||
|
},
|
||||||
|
note = "Fallen off the world",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "hero.y < -5" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = "Field",
|
||||||
|
vars = { score = 0 }
|
||||||
|
}
|
||||||
215
assets/Forge/tutorials/09-rail.game
Normal file
215
assets/Forge/tutorials/09-rail.game
Normal file
|
|
@ -0,0 +1,215 @@
|
||||||
|
-- Written by Forge/AuthorCompile.singe. Edit by hand or in the editor; either is fine.
|
||||||
|
return {
|
||||||
|
types = {
|
||||||
|
camera = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "camera", mode = "rail", track = "rail" }
|
||||||
|
},
|
||||||
|
look = { kind = "none" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
floor = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "solid" }
|
||||||
|
},
|
||||||
|
look = { b = 90, d = 60, g = 75, h = 0.2, kind = "mesh", r = 70, shape = "box", w = 40 },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
gun = {
|
||||||
|
behaviours = {
|
||||||
|
{ ammo = 6, kind = "gun", player = 1, reload = "offscreen" }
|
||||||
|
},
|
||||||
|
look = { kind = "none" },
|
||||||
|
vars = { ammo = 6 }
|
||||||
|
},
|
||||||
|
painting = {
|
||||||
|
behaviours = {},
|
||||||
|
look = { b = 255, d = 0.2, g = 255, h = 16, kind = "mesh", r = 255, shape = "box", texture = "Forge/kit/yard.png", unlit = true, w = 24 },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
pillar = {
|
||||||
|
behaviours = {},
|
||||||
|
look = { d = 1.2, h = 8, kind = "mesh", occluder = true, shape = "box", w = 1.2 },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
readout = {
|
||||||
|
look = { b = 245, g = 235, kind = "text", r = 235, text = "score 0" }
|
||||||
|
},
|
||||||
|
zombie = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "health", linger = 2, max = 2, ragdoll = true },
|
||||||
|
{ kind = "seek", speed = 1.6, stopAt = 2.2, target = "camera" },
|
||||||
|
{ attack = "Run", idle = "Survey", kind = "animator", walk = "Walk" },
|
||||||
|
{ kind = "target" },
|
||||||
|
{ after = 1.5, kind = "timer", name = "bite", start = false }
|
||||||
|
},
|
||||||
|
look = { d = 1.4, file = "Forge/kit/fox.glb", h = 0.9, kind = "model", scale = 0.01, w = 0.8 },
|
||||||
|
vars = { health = 2 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layers = {
|
||||||
|
{ fov = 60, kind = "scene3d" },
|
||||||
|
{ kind = "overlay" }
|
||||||
|
},
|
||||||
|
rooms = {
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "floor", type = "floor", x = 0.0, y = -0.1, z = -20.0 },
|
||||||
|
{ id = "painting", type = "painting", x = 0.0, y = 6.0, z = -30.0 },
|
||||||
|
{ id = "pillar", type = "pillar", x = 0.0, y = 4.0, z = -22.0 },
|
||||||
|
{ id = "camera", type = "camera", x = 0.0, y = 1.6, z = 0.0 },
|
||||||
|
{ id = "gun", type = "gun", x = 0.0, y = 0.0, z = 0.0 }
|
||||||
|
},
|
||||||
|
name = "start",
|
||||||
|
tracks = {
|
||||||
|
{
|
||||||
|
key = "time",
|
||||||
|
name = "rail",
|
||||||
|
points = {
|
||||||
|
{
|
||||||
|
at = 0,
|
||||||
|
look = { 0, 1.2, -10 },
|
||||||
|
stop = "nil",
|
||||||
|
x = 0,
|
||||||
|
y = 1.6,
|
||||||
|
z = 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at = 4,
|
||||||
|
look = { 0, 1.2, -16 },
|
||||||
|
stop = "gate",
|
||||||
|
x = 0,
|
||||||
|
y = 1.6,
|
||||||
|
z = -6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at = 10,
|
||||||
|
look = { 2, 1.2, -24 },
|
||||||
|
stop = "pillar",
|
||||||
|
x = 2,
|
||||||
|
y = 1.6,
|
||||||
|
z = -14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
at = 14,
|
||||||
|
look = { 2, 1.2, -28 },
|
||||||
|
stop = "nil",
|
||||||
|
x = 2,
|
||||||
|
y = 1.6,
|
||||||
|
z = -18
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules = {
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "readout", text = "\"score \" .. score .. \" health \" .. health .. \" ammo \" .. gun.ammo" }
|
||||||
|
},
|
||||||
|
note = "The readout, every frame",
|
||||||
|
on = "frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "spawn", type = "zombie", x = -2, y = 0, z = -14 },
|
||||||
|
{ "spawn", type = "zombie", x = 2, y = 0, z = -15 }
|
||||||
|
},
|
||||||
|
name = "gate",
|
||||||
|
note = "The gate: two come out of the dark",
|
||||||
|
on = "stopped",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "spawn", type = "zombie", x = -1, y = 0, z = -23 },
|
||||||
|
{ "spawn", type = "zombie", x = 0, y = 0, z = -26 },
|
||||||
|
{ "spawn", type = "zombie", x = 4, y = 0, z = -24 }
|
||||||
|
},
|
||||||
|
name = "pillar",
|
||||||
|
note = "The pillar: three more, one from behind it",
|
||||||
|
on = "stopped",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setState", entity = "self", state = "walk" }
|
||||||
|
},
|
||||||
|
type = "zombie",
|
||||||
|
note = "A zombie walks the moment it is made",
|
||||||
|
on = "spawn",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "damage", amount = 1, entity = "self" },
|
||||||
|
{ "addScore", amount = 100 },
|
||||||
|
{ "playSound", file = "Forge/kit/hit.wav" }
|
||||||
|
},
|
||||||
|
type = "zombie",
|
||||||
|
note = "A shot lands",
|
||||||
|
on = "hit",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setState", entity = "self", state = "attack" },
|
||||||
|
{ "timerStart", after = 1.5, entity = "self", name = "bite" }
|
||||||
|
},
|
||||||
|
type = "zombie",
|
||||||
|
note = "It reaches the camera and rears up",
|
||||||
|
on = "arrived",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "addVar", amount = -1, name = "health" },
|
||||||
|
{ "flash", b = 40, g = 40, r = 255, seconds = 0.3 },
|
||||||
|
{ "shake", amount = 0.3, seconds = 0.4 },
|
||||||
|
{ "timerStart", after = 1.5, entity = "self", name = "bite" }
|
||||||
|
},
|
||||||
|
type = "zombie",
|
||||||
|
name = "bite",
|
||||||
|
note = "The bite lands unless it was killed in time",
|
||||||
|
on = "timer",
|
||||||
|
when = {
|
||||||
|
{ "inState", entity = "self", state = "attack" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "pathNext", entity = "camera" }
|
||||||
|
},
|
||||||
|
note = "The stop is clear: move on",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "waiting", entity = "camera" },
|
||||||
|
{ "test", expr = "count(\"zombie\") == 0" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "say", seconds = 2, text = "\"YOU ARE DEAD\"" },
|
||||||
|
{ "gameOver" }
|
||||||
|
},
|
||||||
|
note = "Out of health",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "health <= 0" },
|
||||||
|
{ "once", scope = "game", tag = "over" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "say", seconds = 2, text = "\"STAGE CLEAR\"" }
|
||||||
|
},
|
||||||
|
note = "The end of the rail",
|
||||||
|
on = "railEnd",
|
||||||
|
when = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = "The Dead Yard",
|
||||||
|
vars = { health = 3, score = 0 }
|
||||||
|
}
|
||||||
193
assets/Forge/tutorials/10-release.game
Normal file
193
assets/Forge/tutorials/10-release.game
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
-- Written by Forge/AuthorCompile.singe. Edit by hand or in the editor; either is fine.
|
||||||
|
return {
|
||||||
|
layers = {
|
||||||
|
{ gravity = 1500, kind = "world2d" },
|
||||||
|
{ kind = "bezel" }
|
||||||
|
},
|
||||||
|
rooms = {
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "ground", type = "ground", x = 360, y = 440 },
|
||||||
|
{ id = "hero", type = "hero", x = 200, y = 420 },
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "coin", type = "coin", x = 300, y = 392 },
|
||||||
|
{ id = "coin1", type = "coin", x = 420, y = 392 },
|
||||||
|
{ id = "coin2", type = "coin", x = 560, y = 300 },
|
||||||
|
{ id = "spike", type = "spike", x = 640, y = 420 },
|
||||||
|
{ id = "door", type = "door", x = 700, y = 420 }
|
||||||
|
},
|
||||||
|
name = "start",
|
||||||
|
tracks = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entities = {
|
||||||
|
{ id = "ground", type = "ground", x = 360, y = 440 },
|
||||||
|
{ id = "readout", type = "readout", x = 12, y = 12 },
|
||||||
|
{ id = "coin", type = "coin", x = 400, y = 392 }
|
||||||
|
},
|
||||||
|
name = "cave",
|
||||||
|
tracks = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules = {
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "run", direction = -1, entity = "hero" }
|
||||||
|
},
|
||||||
|
note = "Run left",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "keyHeld", key = "LEFT" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "run", direction = 1, entity = "hero" }
|
||||||
|
},
|
||||||
|
note = "Run right",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "keyHeld", key = "RIGHT" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "jump", entity = "hero" },
|
||||||
|
{ "playSound", file = "Forge/kit/jump.wav" }
|
||||||
|
},
|
||||||
|
note = "Jump, with ground underfoot",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "onGround", entity = "hero" },
|
||||||
|
{ "keyPressed", key = "SPACE" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "setText", entity = "readout", text = "\"score \" .. score .. \" lives \" .. lives" }
|
||||||
|
},
|
||||||
|
note = "The readout, every frame",
|
||||||
|
on = "frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "coin",
|
||||||
|
act = {
|
||||||
|
{ "addScore", amount = 10 },
|
||||||
|
{ "destroy", entity = "self" },
|
||||||
|
{ "playSound", file = "Forge/kit/coin.wav" }
|
||||||
|
},
|
||||||
|
b = "hero",
|
||||||
|
note = "Take a coin",
|
||||||
|
on = "enter",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "spike",
|
||||||
|
act = {
|
||||||
|
{ "moveTo", entity = "hero", x = 200, y = 380 },
|
||||||
|
{ "playSound", file = "Forge/kit/hit.wav" }
|
||||||
|
},
|
||||||
|
b = "hero",
|
||||||
|
note = "Spikes hurt",
|
||||||
|
on = "enter",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a = "door",
|
||||||
|
act = {
|
||||||
|
{ "goTo", entity = "hero", room = "cave", x = 60, y = 380 },
|
||||||
|
{ "addVar", amount = -1, name = "lives" }
|
||||||
|
},
|
||||||
|
b = "hero",
|
||||||
|
note = "Through the door",
|
||||||
|
on = "enter",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "playMusic", file = "Forge/kit/loop.ogg" }
|
||||||
|
},
|
||||||
|
note = "Music",
|
||||||
|
on = "roomStart",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "submitScore", board = "default" },
|
||||||
|
{ "say", seconds = 2, text = "\"GAME OVER\"" },
|
||||||
|
{ "gameOver" }
|
||||||
|
},
|
||||||
|
note = "Out of lives",
|
||||||
|
on = "frame",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "lives <= 0" },
|
||||||
|
{ "once", scope = "game", tag = "over" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "credit" }
|
||||||
|
},
|
||||||
|
note = "A coin",
|
||||||
|
on = "pressed",
|
||||||
|
switch = "SWITCH_COIN1",
|
||||||
|
when = {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
act = {
|
||||||
|
{ "addVar", amount = -1, name = "credits" },
|
||||||
|
{ "setVar", name = "lives", value = "3" },
|
||||||
|
{ "restart" }
|
||||||
|
},
|
||||||
|
note = "Continue",
|
||||||
|
on = "pressed",
|
||||||
|
switch = "SWITCH_START1",
|
||||||
|
when = {
|
||||||
|
{ "test", expr = "credits > 0 and lives <= 0" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title = "Coin Run",
|
||||||
|
types = {
|
||||||
|
coin = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "trigger" },
|
||||||
|
{ kind = "spin", rate = 180 }
|
||||||
|
},
|
||||||
|
look = { file = "Forge/kit/coin.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
door = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "trigger" }
|
||||||
|
},
|
||||||
|
look = { anchor = "feet", file = "Forge/kit/door.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
ground = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "solid" }
|
||||||
|
},
|
||||||
|
look = { b = 90, g = 70, h = 40, kind = "box", r = 60, w = 720 }
|
||||||
|
},
|
||||||
|
hero = {
|
||||||
|
behaviours = {
|
||||||
|
{ jump = 620, kind = "platformer", speed = 260 },
|
||||||
|
{ fps = 10, kind = "frames", states = "idle=1-1, walk=2-5, jump=6-6, fall=7-7" }
|
||||||
|
},
|
||||||
|
look = { file = "Forge/kit/hero.png", frames = 8, kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
},
|
||||||
|
readout = {
|
||||||
|
look = { b = 245, g = 235, kind = "text", r = 235, text = "score 0" }
|
||||||
|
},
|
||||||
|
spike = {
|
||||||
|
behaviours = {
|
||||||
|
{ kind = "trigger" }
|
||||||
|
},
|
||||||
|
look = { anchor = "feet", file = "Forge/kit/spike.png", kind = "sprite" },
|
||||||
|
vars = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
vars = { credits = 0, lives = 3, score = 0 }
|
||||||
|
}
|
||||||
|
|
@ -461,7 +461,10 @@ ExternalProject_Add(singe
|
||||||
# rendered by the engine's own build into .builddir, goes in beside the scripts: Forge copies it
|
# rendered by the engine's own build into .builddir, goes in beside the scripts: Forge copies it
|
||||||
# out to its data directory on its first run.
|
# out to its data directory on its first run.
|
||||||
if((KANGAROO_OS STREQUAL "linux") AND (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux"))
|
if((KANGAROO_OS STREQUAL "linux") AND (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux"))
|
||||||
file(GLOB forgeSources ${CMAKE_SOURCE_DIR}/assets/Forge/*)
|
# Everything under assets/Forge -- the scripts, the kit, the tutorials -- and re-globbed on
|
||||||
|
# every build, so a file added or changed anywhere in it repacks Forge.game without anyone
|
||||||
|
# having to remember.
|
||||||
|
file(GLOB_RECURSE forgeSources CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/assets/Forge/*)
|
||||||
set(forgePack ${CMAKE_SOURCE_DIR}/.builddir/Forge.game)
|
set(forgePack ${CMAKE_SOURCE_DIR}/.builddir/Forge.game)
|
||||||
set(forgeManual ${CMAKE_SOURCE_DIR}/.builddir/Forge.pdf)
|
set(forgeManual ${CMAKE_SOURCE_DIR}/.builddir/Forge.pdf)
|
||||||
set(forgeStage ${SB_PREFIX}/forgepack)
|
set(forgeStage ${SB_PREFIX}/forgepack)
|
||||||
|
|
|
||||||
1250
docs/Forge.adoc
1250
docs/Forge.adoc
File diff suppressed because it is too large
Load diff
|
|
@ -52,7 +52,7 @@
|
||||||
|
|
||||||
| `box`
|
| `box`
|
||||||
| A filled rectangle, centred on the instance -- or standing on it, with anchor feet.
|
| A filled rectangle, centred on the instance -- or standing on it, with anchor feet.
|
||||||
| `anchor` (string), `b` (number), `g` (number), `h` (number), `r` (number), `w` (number)
|
| `anchor` (feet), `b` (number), `g` (number), `h` (number), `r` (number), `w` (number)
|
||||||
|
|
||||||
| `grid`
|
| `grid`
|
||||||
| A map of tiles from a sheet, its top left at the instance: columns is the sheet's width in tiles, tile the tile's size, map the rows of tile numbers (1 is the first; 0 is empty), rows separated by semicolons.
|
| A map of tiles from a sheet, its top left at the instance: columns is the sheet's width in tiles, tile the tile's size, map the rows of tile numbers (1 is the first; 0 is empty), rows separated by semicolons.
|
||||||
|
|
@ -60,11 +60,11 @@
|
||||||
|
|
||||||
| `light`
|
| `light`
|
||||||
| A point or spot light, or a sun, on the instance.
|
| A point or spot light, or a sun, on the instance.
|
||||||
| `b` (number), `g` (number), `intensity` (number), `r` (number), `range` (number), `shadow` (boolean), `type` (string)
|
| `b` (number), `g` (number), `intensity` (number), `r` (number), `range` (number), `shadow` (boolean), `type` (point, spot, sun)
|
||||||
|
|
||||||
| `mesh`
|
| `mesh`
|
||||||
| A box, sphere, cylinder, or plane with a colour or a texture. Floors, walls, crates, targets. An occluder is not seen but hides what is behind it: a pillar that is only in the painting.
|
| A box, sphere, cylinder, or plane with a colour or a texture. Floors, walls, crates, targets. An occluder is not seen but hides what is behind it: a pillar that is only in the painting.
|
||||||
| `b` (number), `d` (number), `g` (number), `h` (number), `metallic` (number), `occluder` (boolean), `r` (number), `roughness` (number), `shape` (string), `texture` (file), `unlit` (boolean), `w` (number)
|
| `b` (number), `d` (number), `g` (number), `h` (number), `metallic` (number), `occluder` (boolean), `r` (number), `roughness` (number), `shape` (box, sphere, cylinder, plane), `texture` (file), `unlit` (boolean), `w` (number)
|
||||||
|
|
||||||
| `model`
|
| `model`
|
||||||
| A glTF model under the instance, scaled and turned, playing a clip. w, h, d say how big it counts as.
|
| A glTF model under the instance, scaled and turned, playing a clip. w, h, d say how big it counts as.
|
||||||
|
|
@ -80,7 +80,7 @@
|
||||||
|
|
||||||
| `sprite`
|
| `sprite`
|
||||||
| An image, centred on the instance -- or standing on it, with anchor feet. frames splits a sheet into that many columns; the var frame picks one. The var angle turns it, starting from the entity's rz. faces says which way the art looks (right unless said, or none): while the var facing is the other way the image is mirrored, so art drawn one way walks both.
|
| An image, centred on the instance -- or standing on it, with anchor feet. frames splits a sheet into that many columns; the var frame picks one. The var angle turns it, starting from the entity's rz. faces says which way the art looks (right unless said, or none): while the var facing is the other way the image is mirrored, so art drawn one way walks both.
|
||||||
| `anchor` (string), `faces` (string), `file` (file), `frames` (number)
|
| `anchor` (feet), `faces` (right, left, none), `file` (file), `frames` (number)
|
||||||
|
|
||||||
| `text`
|
| `text`
|
||||||
| A line of text, its top left at the instance. The var text is what it says.
|
| A line of text, its top left at the instance. The var text is what it says.
|
||||||
|
|
@ -104,7 +104,7 @@
|
||||||
|
|
||||||
| `body`
|
| `body`
|
||||||
| A thing physics moves: a crate, a ball, debris. Mass, bounce, friction, and buoyancy as Jolt takes them.
|
| A thing physics moves: a crate, a ball, debris. Mass, bounce, friction, and buoyancy as Jolt takes them.
|
||||||
| `bounce` (number), `buoyancy` (number), `friction` (number), `mass` (number), `shape` (string)
|
| `bounce` (number), `buoyancy` (number), `friction` (number), `mass` (number), `shape` (box, sphere)
|
||||||
|
|
||||||
| `branching`
|
| `branching`
|
||||||
| Dragon's Lair: a track of branches, each a disc frame window, the move it wants, and where the disc goes on success and on failure. Raises branchTaken and branchMissed.
|
| Dragon's Lair: a track of branches, each a disc frame window, the move it wants, and where the disc goes on success and on failure. Raises branchTaken and branchMissed.
|
||||||
|
|
@ -112,7 +112,7 @@
|
||||||
|
|
||||||
| `camera`
|
| `camera`
|
||||||
| The scene is drawn from this instance. fixed looks at a point; follow keeps an offset from a target; first sits on a target's eyes and the mouse looks; orbit circles a target; rail rides a track of points with stops.
|
| The scene is drawn from this instance. fixed looks at a point; follow keeps an offset from a target; first sits on a target's eyes and the mouse looks; orbit circles a target; rail rides a track of points with stops.
|
||||||
| `eye` (number), `lag` (number), `lookX` (number), `lookY` (number), `lookZ` (number), `mode` (string), `target` (string), `track` (track), `x` (number), `y` (number), `z` (number)
|
| `eye` (number), `lag` (number), `lookX` (number), `lookY` (number), `lookZ` (number), `mode` (fixed, follow, first, orbit, rail), `target` (string), `track` (track), `x` (number), `y` (number), `z` (number)
|
||||||
|
|
||||||
| `character`
|
| `character`
|
||||||
| Walks, falls, and jumps in the scene: the engine's character controller. Moves by the vars dx and dy, relative to the camera.
|
| Walks, falls, and jumps in the scene: the engine's character controller. Moves by the vars dx and dy, relative to the camera.
|
||||||
|
|
@ -128,7 +128,7 @@
|
||||||
|
|
||||||
| `gun`
|
| `gun`
|
||||||
| The pointer as a gun for one player: a press of the trigger raises hit on what is under it, or miss. Ammo counts down; a shot off the screen reloads. With aim centre it fires from the middle of the picture -- a first-person gun.
|
| The pointer as a gun for one player: a press of the trigger raises hit on what is under it, or miss. Ammo counts down; a shot off the screen reloads. With aim centre it fires from the middle of the picture -- a first-person gun.
|
||||||
| `aim` (string), `ammo` (number), `player` (number), `reload` (string), `trigger` (switch)
|
| `aim` (centre), `ammo` (number), `player` (number), `reload` (offscreen), `trigger` (switch)
|
||||||
|
|
||||||
| `health`
|
| `health`
|
||||||
| The var health; the damage action lowers it, and at zero the instance raises death and is destroyed unless keep is set. With ragdoll, a model falls limp instead and goes after linger seconds.
|
| The var health; the damage action lowers it, and at zero the instance raises death and is destroyed unless keep is set. With ragdoll, a model falls limp instead and goes after linger seconds.
|
||||||
|
|
@ -144,7 +144,7 @@
|
||||||
|
|
||||||
| `joint`
|
| `joint`
|
||||||
| Joins this body to another's -- or to the world, with no other -- by a hinge, a ball, or a slider through a world point along an axis.
|
| Joins this body to another's -- or to the world, with no other -- by a hinge, a ball, or a slider through a world point along an axis.
|
||||||
| `ax` (number), `ay` (number), `az` (number), `dx` (number), `dy` (number), `dz` (number), `other` (string), `type` (string)
|
| `ax` (number), `ay` (number), `az` (number), `dx` (number), `dy` (number), `dz` (number), `other` (string), `type` (hinge, ball, slider)
|
||||||
|
|
||||||
| `keys`
|
| `keys`
|
||||||
| Reads a player's keys into the vars dx and dy (-1 to 1) and fire, so rules and movers read intent rather than hardware.
|
| Reads a player's keys into the vars dx and dy (-1 to 1) and fire, so rules and movers read intent rather than hardware.
|
||||||
|
|
@ -159,7 +159,7 @@
|
||||||
| `loop` (boolean), `points` (table)
|
| `loop` (boolean), `points` (table)
|
||||||
|
|
||||||
| `platformer`
|
| `platformer`
|
||||||
| Runs, falls, and jumps: the engine's character controller in 2D. Rules say which way with run and jump.
|
| Runs, falls, and jumps: the engine's character controller in 2D. Rules say which way with run and jump. Its point is its feet, so its look stands on it. Sets the var facing, and the var state to idle, walk, jump, or fall unless a rule set another.
|
||||||
| `jump` (number), `speed` (number)
|
| `jump` (number), `speed` (number)
|
||||||
|
|
||||||
| `projectile`
|
| `projectile`
|
||||||
|
|
@ -175,12 +175,12 @@
|
||||||
| `fly` (boolean), `speed` (number), `stopAt` (number), `target` (string)
|
| `fly` (boolean), `speed` (number), `stopAt` (number), `target` (string)
|
||||||
|
|
||||||
| `shooter`
|
| `shooter`
|
||||||
| Spawns a kind from an offset while the var fire is set (or always, with auto), no faster than the rate.
|
| Spawns a type from an offset while the var fire is set (or always, with auto), no faster than the rate.
|
||||||
| `auto` (boolean), `offsetX` (number), `offsetY` (number), `rate` (number), `spawns` (kind)
|
| `auto` (boolean), `offsetX` (number), `offsetY` (number), `rate` (number), `spawns` (type)
|
||||||
|
|
||||||
| `soft`
|
| `soft`
|
||||||
| A mesh look made soft: a cloth, or a body inflated to a pressure.
|
| A mesh look made soft: a cloth, or a body inflated to a pressure.
|
||||||
| `mass` (number), `pressure` (number), `stiffness` (number), `type` (string)
|
| `mass` (number), `pressure` (number), `stiffness` (number), `type` (cloth, body)
|
||||||
|
|
||||||
| `solid`
|
| `solid`
|
||||||
| Immovable ground or a wall, in a world2d or a scene3d room. With moving, a body that follows wherever the instance is moved -- a paddle, a lift.
|
| Immovable ground or a wall, in a world2d or a scene3d room. With moving, a body that follows wherever the instance is moved -- a paddle, a lift.
|
||||||
|
|
@ -191,8 +191,8 @@
|
||||||
| `death` (file), `hit` (file), `pressed` (file), `spawn` (file), `volume` (number)
|
| `death` (file), `hit` (file), `pressed` (file), `spawn` (file), `volume` (number)
|
||||||
|
|
||||||
| `spawner`
|
| `spawner`
|
||||||
| Makes instances of a kind every so many seconds at its own position or at one of its points, up to max alive at once and total in all.
|
| Makes instances of a type every so many seconds at its own position or at one of its points, up to max alive at once and total in all.
|
||||||
| `every` (number), `max` (number), `pick` (string), `points` (table), `spawns` (kind), `total` (number)
|
| `every` (number), `max` (number), `pick` (turn, random), `points` (table), `spawns` (type), `total` (number)
|
||||||
|
|
||||||
| `spin`
|
| `spin`
|
||||||
| Turns steadily: the var angle in 2D (a sprite turns with it), the node about Y in 3D, in degrees a second.
|
| Turns steadily: the var angle in 2D (a sprite turns with it), the node about Y in 3D, in degrees a second.
|
||||||
|
|
@ -215,12 +215,12 @@
|
||||||
| --
|
| --
|
||||||
|
|
||||||
| `turret`
|
| `turret`
|
||||||
| Fires at the nearest instance of a kind within range, no faster than the rate: spawns a projectile aimed at it, or, with no projectile, does the damage itself.
|
| Fires at the nearest instance of a type within range, no faster than the rate: spawns a projectile aimed at it, or, with no projectile, does the damage itself.
|
||||||
| `damage` (number), `range` (number), `rate` (number), `spawns` (kind), `speed` (number), `targets` (kind)
|
| `damage` (number), `range` (number), `rate` (number), `spawns` (type), `speed` (number), `targets` (type)
|
||||||
|
|
||||||
| `vehicle`
|
| `vehicle`
|
||||||
| A car, motorcycle, tank, or boat on the engine's vehicle physics, driven by the vars dy (throttle, up is forward) and dx (steering) from keys. Wheels hang at the four corners the sizes say; a boat needs none.
|
| A car, motorcycle, tank, or boat on the engine's vehicle physics, driven by the vars dy (throttle, up is forward) and dx (steering) from keys. Wheels hang at the four corners the sizes say; a boat needs none.
|
||||||
| `mass` (number), `radius` (number), `suspension` (number), `thrust` (number), `torque` (number), `type` (string), `wheelX` (number), `wheelZ` (number), `width` (number)
|
| `mass` (number), `radius` (number), `suspension` (number), `thrust` (number), `torque` (number), `type` (car, motorcycle, tank, boat), `wheelX` (number), `wheelZ` (number), `width` (number)
|
||||||
|
|
||||||
| `walker`
|
| `walker`
|
||||||
| Walks the room's walk areas (2D) or its floors (3D) on the navigation mesh: walkTo sends it, a click on the floor can, follow keeps it after an entity (or the camera), and it raises arrived. Its state is walk or idle as it goes.
|
| Walks the room's walk areas (2D) or its floors (3D) on the navigation mesh: walkTo sends it, a click on the floor can, follow keeps it after an entity (or the camera), and it raises arrived. Its state is walk or idle as it goes.
|
||||||
|
|
@ -240,11 +240,11 @@
|
||||||
|
|
||||||
| `animationDone`
|
| `animationDone`
|
||||||
| A clip that does not loop ended on self; event.state says which state it was for.
|
| A clip that does not loop ended on self; event.state says which state it was for.
|
||||||
| `kind` (kind), `state` (state)
|
| `state` (state), `type` (type)
|
||||||
|
|
||||||
| `arrived`
|
| `arrived`
|
||||||
| A seeking instance reached its target.
|
| A seeking instance reached its target.
|
||||||
| `kind` (kind)
|
| `type` (type)
|
||||||
|
|
||||||
| `branchMissed`
|
| `branchMissed`
|
||||||
| The window closed without the move and the disc went to the fail frame.
|
| The window closed without the move and the disc went to the fail frame.
|
||||||
|
|
@ -259,16 +259,16 @@
|
||||||
| --
|
| --
|
||||||
|
|
||||||
| `collision`
|
| `collision`
|
||||||
| An instance of kind a began touching one of kind b (self is a, other is b).
|
| An instance of type a began touching one of type b (self is a, other is b).
|
||||||
| `a` (kind), `b` (kind)
|
| `a` (type), `b` (type)
|
||||||
|
|
||||||
| `death`
|
| `death`
|
||||||
| self's health reached zero.
|
| self's health reached zero.
|
||||||
| `kind` (kind)
|
| `type` (type)
|
||||||
|
|
||||||
| `enter`
|
| `enter`
|
||||||
| An instance of kind b entered a trigger of kind a (self is the trigger, other what entered).
|
| An instance of type b entered a trigger of type a (self is the trigger, other what entered).
|
||||||
| `a` (kind), `b` (kind)
|
| `a` (type), `b` (type)
|
||||||
|
|
||||||
| `frame`
|
| `frame`
|
||||||
| Every frame.
|
| Every frame.
|
||||||
|
|
@ -284,11 +284,11 @@
|
||||||
|
|
||||||
| `hit`
|
| `hit`
|
||||||
| A gun shot landed on self; other is the gun.
|
| A gun shot landed on self; other is the gun.
|
||||||
| `kind` (kind), `player` (number)
|
| `player` (number), `type` (type)
|
||||||
|
|
||||||
| `leave`
|
| `leave`
|
||||||
| An instance of kind b left a trigger of kind a.
|
| An instance of type b left a trigger of type a.
|
||||||
| `a` (kind), `b` (kind)
|
| `a` (type), `b` (type)
|
||||||
|
|
||||||
| `midi`
|
| `midi`
|
||||||
| A MIDI note came in on the port the game opened; event.pitch and event.velocity say which and how hard. (pitch, since note is what a rule's comment is called.)
|
| A MIDI note came in on the port the game opened; event.pitch and event.velocity say which and how hard. (pitch, since note is what a rule's comment is called.)
|
||||||
|
|
@ -300,7 +300,7 @@
|
||||||
|
|
||||||
| `patrolEnd`
|
| `patrolEnd`
|
||||||
| A patrolling instance reached the last of its points.
|
| A patrolling instance reached the last of its points.
|
||||||
| `kind` (kind)
|
| `type` (type)
|
||||||
|
|
||||||
| `pressed`
|
| `pressed`
|
||||||
| A key or a switch went down.
|
| A key or a switch went down.
|
||||||
|
|
@ -326,9 +326,13 @@
|
||||||
| A line was typed at the parser: its verb, noun, and second noun as the words table knows them, or unknown for a word it does not. The most specific rule wins.
|
| A line was typed at the parser: its verb, noun, and second noun as the words table knows them, or unknown for a word it does not. The most specific rule wins.
|
||||||
| `noun` (string), `second` (string), `verb` (string)
|
| `noun` (string), `second` (string), `verb` (string)
|
||||||
|
|
||||||
|
| `soundDone`
|
||||||
|
| A clip that playSound or a sound behaviour started has ended; event.file says which, and self is the instance that played it.
|
||||||
|
| `file` (file), `type` (type)
|
||||||
|
|
||||||
| `spawn`
|
| `spawn`
|
||||||
| self has just been made.
|
| self has just been made.
|
||||||
| `kind` (kind)
|
| `type` (type)
|
||||||
|
|
||||||
| `stopped`
|
| `stopped`
|
||||||
| A rail camera reached a stop; event.name says which. pathNext moves it on.
|
| A rail camera reached a stop; event.name says which. pathNext moves it on.
|
||||||
|
|
@ -336,7 +340,7 @@
|
||||||
|
|
||||||
| `timer`
|
| `timer`
|
||||||
| A timer on self went off; event.name says which.
|
| A timer on self went off; event.name says which.
|
||||||
| `kind` (kind), `name` (string)
|
| `name` (string), `type` (type)
|
||||||
|
|
||||||
| `verb`
|
| `verb`
|
||||||
| A verb was used on a hotspot (self), with an item or not: "use key on door". The most specific rule wins.
|
| A verb was used on a hotspot (self), with an item or not: "use key on door". The most specific rule wins.
|
||||||
|
|
@ -624,13 +628,13 @@
|
||||||
|
|
|
|
||||||
|
|
||||||
| `spawn`
|
| `spawn`
|
||||||
| Make an instance of a kind at a point.
|
| Make an instance of a type at a point.
|
||||||
| `kind` (kind), `x` (number), `y` (number), `z` (number)
|
| `type` (type), `x` (number), `y` (number), `z` (number)
|
||||||
|
|
|
|
||||||
|
|
||||||
| `spawnAtPointer`
|
| `spawnAtPointer`
|
||||||
| Make an instance of a kind where the player's pointer is: on the overlay in 2D, on the floor the ray meets in 3D.
|
| Make an instance of a type where the player's pointer is: on the overlay in 2D, on the floor the ray meets in 3D.
|
||||||
| `kind` (kind), `player` (number)
|
| `player` (number), `type` (type)
|
||||||
|
|
|
|
||||||
|
|
||||||
| `stopMusic`
|
| `stopMusic`
|
||||||
|
|
|
||||||
|
|
@ -7170,7 +7170,7 @@ guiDraw(gui, x, y)
|
||||||
guiDraw(gui, x, y, width, height)
|
guiDraw(gui, x, y, width, height)
|
||||||
----
|
----
|
||||||
|
|
||||||
Composites the GUI's texture over the overlay for this frame, in overlay coordinates, so it obeys the Sinden border and the overscan scale like everything else on the overlay: covering the whole overlay with one argument, at its own size with a corner at `x, y`, or scaled into the `width` by `height` rectangle. The call lasts one frame; make it from `onOverlayUpdate` (or `singeMain`) every frame the GUI should be visible. GUIs draw above the overlay in the order called (the last on top), under `PARTICLE_OVER` particles and the pause indicator, and the GUI drawn last under the pointer is the one that receives the mouse. Up to sixteen calls are honored per frame; more are ignored. Any other argument count raises `Expected 1, 3 or 5 arguments`.
|
Composites the GUI's texture over the overlay for this frame, in overlay coordinates, so it obeys the Sinden border and the overscan scale like everything else on the overlay: covering the whole overlay with one argument, at its own size with a corner at `x, y`, or scaled into the `width` by `height` rectangle. The call's place in the script's drawing decides what is under the GUI and what is over it: everything drawn on the overlay before it stays underneath, and everything drawn after it -- until the next `guiDraw`, or the script's next turn -- goes on a layer of its own composited over that GUI. A pointer drawn after the HUD is drawn over the HUD; a second document drawn after that sits over the pointer, with its own layer above. Up to sixteen such layers a frame; a call past that draws its GUI with nothing over it. `overlayClear` clears whichever layer is being drawn on, and `overlaySetMonochrome` greys the base overlay only. The call lasts one frame; make it from `onOverlayUpdate` (or `singeMain`) every frame the GUI should be visible. GUIs draw above the overlay in the order called (the last on top), under `PARTICLE_OVER` particles and the pause indicator, and the GUI drawn last under the pointer is the one that receives the mouse. Up to sixteen calls are honored per frame; more are ignored. Any other argument count raises `Expected 1, 3 or 5 arguments`.
|
||||||
|
|
||||||
*Parameters:*
|
*Parameters:*
|
||||||
|
|
||||||
|
|
@ -7183,11 +7183,14 @@ Composites the GUI's texture over the overlay for this frame, in overlay coordin
|
||||||
.Example
|
.Example
|
||||||
[source,lua]
|
[source,lua]
|
||||||
----
|
----
|
||||||
-- The HUD sits in the bottom right corner at a third of the overlay's width.
|
-- The HUD sits in the bottom right corner at a third of the overlay's width, and the gun's
|
||||||
|
-- sight is drawn after it, so the sight is never hidden by the panel.
|
||||||
function onOverlayUpdate()
|
function onOverlayUpdate()
|
||||||
overlayClear()
|
overlayClear()
|
||||||
guiSetValue(hud, hudPage, "lives", tostring(lives))
|
guiSetValue(hud, hudPage, "lives", tostring(lives))
|
||||||
guiDraw(hud, overlayGetWidth() * 0.66, overlayGetHeight() * 0.8, overlayGetWidth() * 0.33, overlayGetHeight() * 0.2)
|
guiDraw(hud, overlayGetWidth() * 0.66, overlayGetHeight() * 0.8, overlayGetWidth() * 0.33, overlayGetHeight() * 0.2)
|
||||||
|
local x, y = mouseGetPosition(0)
|
||||||
|
spriteDraw(sight, x, y, true)
|
||||||
return OVERLAY_UPDATED
|
return OVERLAY_UPDATED
|
||||||
end
|
end
|
||||||
----
|
----
|
||||||
|
|
@ -7457,7 +7460,7 @@ guiSetHandler(gui, document, id, event, function)
|
||||||
guiSetHandler(gui, document, id, event, nil)
|
guiSetHandler(gui, document, id, event, nil)
|
||||||
----
|
----
|
||||||
|
|
||||||
Calls `function(gui, document, id, event, value)` whenever the element with that `id` fires the named event: `"click"` for buttons and rows, `"change"` for form controls, `"submit"` for a form, or any other RmlUi event name (`"focus"`, `"mouseover"`, `"keydown"`, ...). `value` is the element's value at that moment as a string, as `guiGetValue` would return it (a range comes as RmlUi formats it, `"85.000000"`, so pass it through `tonumber`). One function is kept per element and event; setting another replaces it, and `nil` removes it. Handlers run as the events happen, between the game's own callbacks, and an error in one ends the game like an error in any callback. Ids are at most 63 characters. Raises `No element "id" in document N of GUI G` when the element does not exist, and `Argument 5 must be a function or nil` for anything else in that place.
|
Calls `function(gui, document, id, event, value)` whenever the element with that `id` fires the named event: `"click"` for buttons and rows, `"change"` for form controls, `"submit"` for a form, or any other RmlUi event name (`"focus"`, `"mouseover"`, `"keydown"`, ...). `value` is the element's value at that moment as a string, as `guiGetValue` would return it (a range comes as RmlUi formats it, `"85.000000"`, so pass it through `tonumber`). One function is kept per element and event; setting another replaces it, and `nil` removes it. The handler belongs to the `id`, not to one element: when the element is replaced -- a list rebuilt through `inner_rml` makes new elements -- set the handler again after the rebuild and it attaches to the element that carries the id now. Handlers run as the events happen, between the game's own callbacks, and an error in one ends the game like an error in any callback. Ids are at most 63 characters. Raises `No element "id" in document N of GUI G` when the element does not exist, and `Argument 5 must be a function or nil` for anything else in that place.
|
||||||
|
|
||||||
*Parameters:*
|
*Parameters:*
|
||||||
|
|
||||||
|
|
@ -7489,7 +7492,7 @@ end)
|
||||||
guiSetInput(gui, enabled)
|
guiSetInput(gui, enabled)
|
||||||
----
|
----
|
||||||
|
|
||||||
Whether the mouse and light gun, keys, typed text and the framework switches from a pad or mouse reach the GUI. A new GUI only displays, which suits a HUD or a sign; turn input on for a menu or a form. While it is on, the pointer reaches the GUI wherever it is drawn flat (the last drawn on top) or shown on a surface in the scene, every key goes to it, a text field with focus turns on SDL's text input, and the pad's directions arrive as arrow keys with `ACTION_1` as Return and `ACTION_2` as Escape. What an element uses never reaches `onInputPressed`, `onKeyPressed` or the mouse callbacks; what nothing used falls through to them as usual. Raises an error for a handle that is not valid.
|
Whether the mouse and light gun, keys, typed text and the framework switches from a pad or mouse reach the GUI. A new GUI only displays, which suits a HUD or a sign; turn input on for a menu or a form. While it is on, the pointer reaches the GUI wherever it is drawn flat (the last drawn on top) or shown on a surface in the scene, every key goes to it except `Tab`, which the GUI is given only while a text field is being typed in (RmlUi uses it to move focus and never hands it back, and a game whose keys include `Tab` would otherwise lose it), a text field with focus turns on SDL's text input, and the pad's directions arrive as arrow keys with `ACTION_1` as Return and `ACTION_2` as Escape. What an element uses never reaches `onInputPressed`, `onKeyPressed` or the mouse callbacks; what nothing used falls through to them as usual. Raises an error for a handle that is not valid.
|
||||||
|
|
||||||
*Since:* 3.00.
|
*Since:* 3.00.
|
||||||
*See also:* <<guisethandler,guiSetHandler>>, <<guidraw,guiDraw>>, <<sceneprobegui,sceneProbeGui>>
|
*See also:* <<guisethandler,guiSetHandler>>, <<guidraw,guiDraw>>, <<sceneprobegui,sceneProbeGui>>
|
||||||
|
|
@ -7994,7 +7997,7 @@ end
|
||||||
keyboardSetMode(mode)
|
keyboardSetMode(mode)
|
||||||
----
|
----
|
||||||
|
|
||||||
Switches between the two keyboard models. In `MODE_NORMAL` only keys mapped in `controls.cfg` reach the script, as `SWITCH_*` values, key repeat is dropped so each press arrives once, and the engine acts on its own switches (pause, quit, screenshot, mouse grab). In `MODE_FULL` every key reaches `onInputPressed` and `onInputReleased` as its keysym and `onKeyPressed` and `onKeyReleased` as keysym and scancode, key repeat is delivered for text entry, and keyboard mappings of the engine's own switches are ignored so that the game keeps every key; controller and mouse button mappings still act. Most games set the mode once at startup; a game with text entry switches to `MODE_FULL` for the duration and back. Any other value aborts the script.
|
Switches between the two keyboard models. In `MODE_NORMAL` only keys mapped in `controls.cfg` reach the script, as `SWITCH_*` values, key repeat is dropped so each press arrives once, and the engine acts on its own switches (pause, quit, screenshot, mouse grab). In `MODE_FULL` every key reaches `onInputPressed` and `onInputReleased` as its keysym and `onKeyPressed` and `onKeyReleased` as keysym and scancode, the text a press produces reaches `onTextInput`, key repeat is delivered for text entry, and keyboard mappings of the engine's own switches are ignored so that the game keeps every key; controller and mouse button mappings still act, and those buttons still reach the script as their `SWITCH_*` values, since they cannot be typed. Most games set the mode once at startup; a game with text entry switches to `MODE_FULL` for the duration and back. Any other value aborts the script. In `MODE_FULL` the keysyms of four keys are also switch numbers -- Backspace is `8` (`SWITCH_BUTTON3`), Tab `9` (`SWITCH_COIN1`), Return `13`, and Escape `27` -- so a script that reads `onInputPressed` for a pad or mouse switch and also expects those keys should check `keyboardIsDown` for the key before treating the value as the switch.
|
||||||
|
|
||||||
*Parameters:*
|
*Parameters:*
|
||||||
|
|
||||||
|
|
@ -14564,9 +14567,10 @@ end
|
||||||
[source,text]
|
[source,text]
|
||||||
----
|
----
|
||||||
singeScreenshot()
|
singeScreenshot()
|
||||||
|
singeScreenshot(name)
|
||||||
----
|
----
|
||||||
|
|
||||||
Requests a screenshot of the whole window, letterbox included, taken after the next frame is drawn and saved as a PNG in the game's data directory (see `singeGetDataPath`). Files are named `singe000.png` upward; each script run scans from zero for the first free name and later shots continue past the last one saved. The call forces a redraw so the shot is taken even while the display is idle. The switch mapped to `INPUT_SCREENSHOT` in `controls.cfg` does the same thing.
|
Requests a screenshot of the whole window, letterbox included, taken after the next frame is drawn and saved as a PNG in the game's data directory (see `singeGetDataPath`). Without a name, files are named `singe000.png` upward; each script run scans from zero for the first free name and later shots continue past the last one saved. With a name the shot goes to that file, `.png` added when the name has no extension, replacing any file of that name; a name with a directory in it aborts the script. Naming the shot is for scripts that produce pictures on purpose, such as the ones that illustrate the Forge tutorials, so a rerun replaces the picture rather than adding one. The call forces a redraw so the shot is taken even while the display is idle. The switch mapped to `INPUT_SCREENSHOT` in `controls.cfg` does the same thing.
|
||||||
|
|
||||||
*Since:* 1.x
|
*Since:* 1.x
|
||||||
*See also:* <<singegetdatapath,singeGetDataPath>>
|
*See also:* <<singegetdatapath,singeGetDataPath>>
|
||||||
|
|
@ -18966,6 +18970,20 @@ Called in `MODE_FULL` only, for every key going down or up, with both the logica
|
||||||
|
|
||||||
*See also:* <<keyboardsetmode,keyboardSetMode>>, <<keyboardgetmodifiers,keyboardGetModifiers>>, <<oninputpressedoninputreleased,onInputPressed>>
|
*See also:* <<keyboardsetmode,keyboardSetMode>>, <<keyboardgetmodifiers,keyboardGetModifiers>>, <<oninputpressedoninputreleased,onInputPressed>>
|
||||||
|
|
||||||
|
[#ontextinput]
|
||||||
|
==== onTextInput
|
||||||
|
|
||||||
|
[source,text]
|
||||||
|
----
|
||||||
|
function onTextInput(text)
|
||||||
|
end
|
||||||
|
----
|
||||||
|
|
||||||
|
Called in `MODE_FULL` only, with the text a key press produced -- a character or a few, in UTF-8 -- after the keyboard's shift state and layout have been applied, so a capital, a quote, or a letter from a non-English layout arrives as the person typed it. `onKeyPressed` gives the same press as its unshifted keysym and scancode and is the one to use for keys that are commands; this is the one to use for keys that are text. A GUI with a focused text field takes the text first, and the script hears nothing of it.
|
||||||
|
|
||||||
|
*Since:* 3.00.
|
||||||
|
*See also:* <<onkeypressedonkeyreleased,onKeyPressed>>, <<keyboardsetmode,keyboardSetMode>>
|
||||||
|
|
||||||
.Example
|
.Example
|
||||||
[source,lua]
|
[source,lua]
|
||||||
----
|
----
|
||||||
|
|
|
||||||
BIN
docs/images/tutorials/01-chooser.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/01-chooser.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/01-entities.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/01-entities.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/01-moved.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/01-moved.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/01-playing.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/01-playing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/01-recoloured.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/01-recoloured.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/01-rules.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/01-rules.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/01-saved.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/01-saved.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/01-types.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/01-types.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/02-cave.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/02-cave.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/02-coinType.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/02-coinType.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/02-coins.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/02-coins.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/02-placed.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/02-placed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/02-playing.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/02-playing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/02-rule.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/02-rule.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/02-rules.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/02-rules.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/03-coinSpin.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/03-coinSpin.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/03-heroType.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/03-heroType.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/03-jumpRule.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/03-jumpRule.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/03-music.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/03-music.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/03-playing.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/03-playing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/04-cleared.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/04-cleared.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/04-hitRule.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/04-hitRule.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/04-placed.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/04-placed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/04-playing.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/04-playing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/04-rules.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/04-rules.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/04-ship.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/04-ship.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/04-types.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/04-types.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/05-disc.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/05-disc.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/05-playing.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/05-playing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/05-prompts.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/05-prompts.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/05-rules.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/05-rules.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/05-window.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/05-window.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/06-firstKey.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/06-firstKey.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/06-playing.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/06-playing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/06-rules.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/06-rules.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/06-tracks.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/06-tracks.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/06-types.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/06-types.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/07-dialogue.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/07-dialogue.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/07-hall.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/07-hall.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/07-hotspots.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/07-hotspots.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/07-playing.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/07-playing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/07-verbRules.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/07-verbRules.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/07-walkArea.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/07-walkArea.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/08-hero.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/08-hero.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/08-meshes.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/08-meshes.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/08-playing.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/08-playing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/08-rules.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/08-rules.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/08-scene.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/08-scene.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/08-viewport.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/08-viewport.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/09-hitRule.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/09-hitRule.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/09-placed.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/09-placed.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/09-playing.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/09-playing.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/09-rail.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/09-rail.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/09-room.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/09-room.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
docs/images/tutorials/09-rules.png
(Stored with Git LFS)
Normal file
BIN
docs/images/tutorials/09-rules.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue