Initial Guidebook code

This commit is contained in:
Noah 2020-03-09 22:21:59 -07:00
parent b4922edf5d
commit 7142c76b86
14 changed files with 463 additions and 0 deletions

2
.gitignore vendored
View File

@ -3,6 +3,8 @@ fonts/
maps/
bin/
dist/
dev-assets/guidebook/venv
dev-assets/guidebook/compiled/pages
wasm/assets/
*.wasm
*.doodad

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -0,0 +1,73 @@
#!/usr/bin/env python3
import codecs
import glob
import os
import markdown
import jinja2
import re
def main():
if not os.path.isdir("./compiled"):
print("Make output directory: ./compiled")
os.mkdir("./compiled")
os.mkdir("./compiled/pages")
# Render the main index.html template.
with codecs.open("./pages/index.html", "r", "utf-8") as fh:
html = fh.read()
html = render_template(html)
with open("./compiled/index.html", "w") as outfh:
outfh.write(html)
# Load the Markdown wrapper HTML template.
html_wrapper = "$CONTENT"
with codecs.open("./pages/markdown.html", "r", "utf-8") as fh:
html_wrapper = fh.read()
for md in glob.glob("./pages/*.md"):
filename = md.split(os.path.sep)[-1]
htmlname = filename.replace(".md", ".html")
print("Compile Markdown: {} -> {}".format(filename, htmlname))
with codecs.open(md, 'r', 'utf-8') as fh:
data = fh.read()
rendered = markdown.markdown(data,
extensions=["codehilite", "fenced_code"],
)
html = html_wrapper.replace("$CONTENT", rendered)
html = render_template(html,
title=title_from_markdown(data),
)
with open(os.path.join("compiled", "pages", htmlname), "w") as outfh:
outfh.write(html)
jinja_env = jinja2.Environment()
def render_template(input, *args, **kwargs):
templ = jinja_env.from_string(input)
return templ.render(
app_name="Project: Doodle",
app_version=get_app_version(),
*args, **kwargs
)
def title_from_markdown(text):
"""Retrieve the title from the first Markdown header."""
for line in text.split("\n"):
if line.startswith("# "):
return line[2:]
def get_app_version():
"""Get the app version from pkg/branding/branding.go in Doodle"""
ver = re.compile(r'Version\s*=\s*"(.+?)"')
with codecs.open("../../pkg/branding/branding.go", "r", "utf-8") as fh:
text = fh.read()
for line in text.split("\n"):
m = ver.search(line)
if m:
return m[1]
if __name__ == "__main__":
main()

16
dev-assets/guidebook/build.sh Executable file
View File

@ -0,0 +1,16 @@
#!/bin/bash
if [[ ! -d "./venv" ]]; then
echo Creating Python virtualenv...
python3 -m venv ./venv
source ./venv/bin/activate
pip install -r requirements.txt
else
source ./venv/bin/activate
fi
python build.py
# Copy static files in.
mkdir -p compiled/pages/res
cp -r pages/res/*.* compiled/pages/res/

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>Project: Doodle Guidebook</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="pages/res/main.css">
</head>
<body>
<div id="sidebar">
<nav>
<h3>Navigation</h3>
<ul>
<li><a href="pages/Home.html" target="frame">Home</a></li>
</ul>
</nav>
</div>
<div id="content">
<div>
<iframe name="frame" src="pages/Home.html"></iframe>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,130 @@
# Doodad Scripts
Doodads are programmed using JavaScript which gives them their behavior
and ability to interact with the player and other doodads.
An example Doodad script looks like the following:
```javascript
// The main function is called when the doodad is initialized in Play Mode
// at the start of the level.
function main() {
// Important global variables:
// - Self: information about the current Doodad running this script.
// - Events: handle events raised during gameplay.
// - Message: publish or subscribe to named messages to interact with
// other doodads.
// Logs go to the game's log file (standard output on Linux/Mac).
console.log("%s initialized!", Self.Doodad.Title);
// If our doodad has 'solid' parts that should prohibit movement,
// define the hitbox here. Coordinates are relative so 0,0 is the
// top-left pixel of the doodad's sprite.
Self.SetHitbox(0, 0, 64, 12);
// Handle a collision when another doodad (or player) has entered
// the space of our doodad.
Events.OnCollide(function(e) {
// The `e` object holds information about the event.
console.log("Actor %s has entered our hitbox!", e.Actor.ID());
// InHitbox is `true` if we defined a hitbox for ourselves, and
// the colliding actor is inside of the hitbox we defined.
if (e.InHitbox) {
// To prohibit movement, return false from the OnCollide handler.
// If you don't return false, the actor is allowed to keep on
// moving through.
return false;
}
});
// OnLeave is called when an actor, who was previously colliding with
// us, is no longer doing so.
Events.OnLeave(function(e) {
console.log("Actor %s has stopped colliding!", e.Actor.ID());
})
}
```
# JavaScript API
## Global Variables
The following global variables are available to all Doodad scripts.
### Self
Self holds information about the current doodad. The full surface area of
the Self object is subject to change, but some useful things you can access
from it include:
* Self.Doodad: a pointer to the doodad's file data.
* Self.Doodad.Title: get the title of the doodad file.
* Self.Doodad.Author: the name of the author who wrote the doodad.
* Self.Doodad.Script: the doodad's JavaScript source code. Note that
modifying this won't have any effect in-game, as the script had already
been loaded into the interpreter.
* Self.Doodad.GameVersion: the version of {{ app_name }} that was used
when the doodad was created.
### Events
### Message
## Global Functions
The following useful functions are also available globally:
### Timers and Intervals
Doodad scripts implement setTimeout() and setInterval() functions similar
to those found in web browsers.
```javascript
// Call a function after 5 seconds.
setTimeout(function() {
console.log("I've been called!");
}, 5000);
```
setTimeout() and setInterval() return an ID number for the timer created.
If you wish to cancel a timer before it has finished, or to stop an interval
from running, you need to pass its ID number into `clearTimeout()` or
`clearInterval()`, respectively.
```javascript
// Start a 1-second interval
var id = setInterval(function() {
console.log("Tick...");
}, 1000);
// Cancel it after 30 seconds.
setTimeout(function() {
clearInterval(id);
}, 30000);
```
### Console Logging
Doodad scripts also implement the `console.log()` and similar functions as
found in web browser APIs. They support "printf" style variable placeholders.
```javascript
console.log("Hello world!");
console.error("The answer is %d!", 42);
console.warn("Actor '%s' has collided with us!", e.Actor.ID());
console.debug("This only logs when the game is in debug mode!");
```
### RGBA(red, green, blue, alpha uint8)
RGBA initializes a Color variable using the game's native Color type. May
be useful for certain game APIs that take color values.
Example: RGBA(255, 0, 255, 255) creates an opaque magenta color.
### Point(x, y int)
Returns a Point object which refers to a location in the game world. This
type is required for certain game APIs.

View File

@ -0,0 +1,9 @@
# Guidebook to {{ app_name }}
This is the users manual to {{ app_name }}, a drawing-based maze game.
## Creating Custom Content
* [Doodad Scripts](DoodadScripts.html)
v{{ app_version }}

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ app_name }} Guidebook</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="pages/res/main.css">
</head>
<body>
<div id="sidebar">
<nav>
<h3>Navigation</h3>
<ul>
<li><a href="pages/Home.html" target="frame">Home</a></li>
</ul>
</nav>
</div>
<div id="content">
<div>
<iframe name="frame" src="pages/Home.html"></iframe>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="res/markdown.css">
<link rel="stylesheet" type="text/css" href="res/syntax.css">
</head>
<body>
$CONTENT
</body>
</html>

View File

@ -0,0 +1,66 @@
body,html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
body {
background-color: #EEE;
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
font-size: 16px;
color: #000;
line-height: 1.4em;
}
div#sidebar {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 220px;
background-color: #000066;
color: #EEE;
}
nav {
padding: 1.5rem;
}
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav ul li {
display: block;
}
nav a:link, nav a:visited {
color: #EEE;
text-decoration: none;
}
nav a:hover, nav a:active {
color: #F9F;
text-decoration: underline;
}
div#content {
position: absolute;
top: 0;
left: 220px;
right: 0;
bottom: 0;
}
div#content div {
position: relative;
width: 100%;
height: 100%;
}
div#content iframe {
width: 100%;
height: 100%;
border: 0;
overflow: auto;
}

View File

@ -0,0 +1,25 @@
body {
background-color: #EEE;
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
font-size: 16px;
color: #000;
line-height: 1.4em;
margin: 2rem;
}
a:link, a:visited {
color: #006699;
text-decoration: underline;
}
a:hover, a:active {
color: #996600;
}
.codehilite {
border: 1px solid #222;
}
pre {
font-family: "Lucida Console", "DejaVu LGC Sans Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Ubuntu Mono", monospace;
margin: 0;
padding: 8px;
}

View File

@ -0,0 +1,69 @@
.codehilite .hll { background-color: #ffffcc }
.codehilite { background: #f8f8f8; }
.codehilite .c { color: #408080; font-style: italic } /* Comment */
.codehilite .err { border: 1px solid #FF0000 } /* Error */
.codehilite .k { color: #008000; font-weight: bold } /* Keyword */
.codehilite .o { color: #666666 } /* Operator */
.codehilite .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
.codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
.codehilite .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
.codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
.codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
.codehilite .gd { color: #A00000 } /* Generic.Deleted */
.codehilite .ge { font-style: italic } /* Generic.Emph */
.codehilite .gr { color: #FF0000 } /* Generic.Error */
.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.codehilite .gi { color: #00A000 } /* Generic.Inserted */
.codehilite .go { color: #888888 } /* Generic.Output */
.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.codehilite .gs { font-weight: bold } /* Generic.Strong */
.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.codehilite .gt { color: #0044DD } /* Generic.Traceback */
.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.codehilite .kp { color: #008000 } /* Keyword.Pseudo */
.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.codehilite .kt { color: #B00040 } /* Keyword.Type */
.codehilite .m { color: #666666 } /* Literal.Number */
.codehilite .s { color: #BA2121 } /* Literal.String */
.codehilite .na { color: #7D9029 } /* Name.Attribute */
.codehilite .nb { color: #008000 } /* Name.Builtin */
.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.codehilite .no { color: #880000 } /* Name.Constant */
.codehilite .nd { color: #AA22FF } /* Name.Decorator */
.codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
.codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.codehilite .nf { color: #0000FF } /* Name.Function */
.codehilite .nl { color: #A0A000 } /* Name.Label */
.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
.codehilite .nv { color: #19177C } /* Name.Variable */
.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
.codehilite .mb { color: #666666 } /* Literal.Number.Bin */
.codehilite .mf { color: #666666 } /* Literal.Number.Float */
.codehilite .mh { color: #666666 } /* Literal.Number.Hex */
.codehilite .mi { color: #666666 } /* Literal.Number.Integer */
.codehilite .mo { color: #666666 } /* Literal.Number.Oct */
.codehilite .sa { color: #BA2121 } /* Literal.String.Affix */
.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
.codehilite .sc { color: #BA2121 } /* Literal.String.Char */
.codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */
.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
.codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
.codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.codehilite .sx { color: #008000 } /* Literal.String.Other */
.codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
.codehilite .ss { color: #19177C } /* Literal.String.Symbol */
.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
.codehilite .fm { color: #0000FF } /* Name.Function.Magic */
.codehilite .vc { color: #19177C } /* Name.Variable.Class */
.codehilite .vg { color: #19177C } /* Name.Variable.Global */
.codehilite .vi { color: #19177C } /* Name.Variable.Instance */
.codehilite .vm { color: #19177C } /* Name.Variable.Magic */
.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */

View File

@ -0,0 +1,2 @@
markdown
jinja2