Update Guidebook for v0.13.1

This commit is contained in:
Noah 2022-10-10 12:54:19 -07:00
parent 63a90db941
commit 5897d0dd59
56 changed files with 2133 additions and 747 deletions

View File

@ -1,50 +1,23 @@
# About _Sketchy Maze_
**Sketchy Maze** is a "drawing-based maze game" themed around hand-drawn maps
on paper.
**Sketchy Maze** is a "drawing-based maze game" themed around hand-drawn maps on paper.
![Screenshot of the level editor](images/about.png)
You can draw your own custom maps, freehand or with some basic drawing tools,
and then drag and drop pre-made "[doodads](doodads.md)" into your level for
interactive things like keys, doors and buttons.
This is an **early alpha build** of the game. Longer term it will include a couple
of built-in "single player campaigns" of multiple themed levels, but for now it
just includes a few example levels and the editor itself.
You can draw your own custom maps, freehand or with some basic drawing tools, and then drag and drop pre-made "[doodads](doodads.md)" into your level for interactive things like keys, doors and buttons.
## Inspiration
When I was a kid in the era of Sega Genesys and Super Nintendo, I liked to
draw my own levels with pen and paper and "play" them with my imagination. My
"mouse mazes" had all sorts of features borrowed from videogames I liked.
There were buttons that the player had to push that would open a door far
across the level (and I'd draw a little dotted line showing the connection
between the button and the door). Trapdoors would have the player fall through
and then close behind them so they can't go back. Keys in different shapes
could unlock doors in similar shapes (you'd just have to remember which keys
you've got!)
Growing up in the era of 2D platformer games on the likes of the Sega Genesys and Super Nintendo, as a kid I would often draw my own levels with pen and paper and "play" them with my imagination. My mazes had all sorts of features borrowed from videogames I liked. There would be buttons that the player had to push that would open a door far across the level (and I'd draw a little dotted line showing the connection between the button and the door). Trapdoors would have the player fall through and then close behind them so they can't go back. Keys in different shapes could unlock doors in similar shapes (you'd just have to remember which keys you've got!)
When you're drawing with a pen and paper, the level can be anything you want.
You can draw a castle or a cave, place little gizmos and traps throughout the
level (doors, keys, buttons and things) and create puzzles. Do you want the red
pixels to mean "fire" and burn the player? Or do you want to decorate the tops
of "bloody" spikes with red? Either way, the 'fire' attribute on that color will
do the job and you can draw whatever shape you want for your level hazards.
When you're just drawing with a pen and paper, the level can be anything you want. You can draw a castle or a cave, place little gizmos and traps throughout the level (doors, keys, buttons and things) and create puzzles. Do you want the red pixels to mean "fire" and burn the player? Or do you want to decorate the tops of "bloody" spikes with red? Either way, the 'fire' attribute on that color will do the job and you can draw whatever shape you want for your level hazards.
![Palette editor](images/palette.png)
## Mod Friendly
While the game ships with a [handful of built-in doodads](doodads.md) to
spice up your level, you can also create your own and program them to do
whatever you want, [with JavaScript](custom-doodads/scripts.md)!
While the game ships with a [handful of built-in doodads](doodads.md) to spice up your level, you can also create your own and program them to do whatever you want, [with JavaScript](custom-doodads/scripts.md)!
The game also has a few "generic" scripts built in that you can choose from,
to create your own simple doodads with no programming required! In the future,
template doodads can be created to be able to draw custom player characters,
Warp Doors and other complex doodads with a script already attached.
The game also has a few "generic" scripts built in that you can choose from, to create your own simple doodads with no programming required! In the future, template doodads can be created to be able to draw custom player characters, Warp Doors and other complex doodads with a script already attached.
Full versions of the game let you bundle custom doodads _inside_ of your
custom levels for easy sharing to other players. Custom wallpaper images embed
in a level file for all versions of the game.
Full versions of the game let you bundle custom doodads _inside_ of your custom levels for easy sharing to other players. Custom wallpaper images embed in a level file for all versions of the game.

View File

@ -1,5 +1,569 @@
# Changes
## v0.13.1 (Oct 10 2022)
This release brings a handful of minor new features to the game.
First, there are a couple of new Pixel Attributes available in the level editor:
* Semi-Solid: pixels with this attribute only behave as "solid" when walked on
from above. The player can jump through the bottom of a Semi-Solid and land
on top, and gradual slopes can be walked up and down as well, but a steep
slope or a wall can be simply passed through as though it were just decoration.
* Slippery: the player's acceleration and friction are reduced when walking on
a slippery floor. In the future, players and other mobile doodads may slide
down slippery slopes automatically as well (not yet implemented).
* These attributes are available in the Level Editor by clicking the "Edit"
button on your Palette (or the "Tools -> Edit Palette" menu). The Palette
Editor now has small icon images for the various attributes to make room for
the expanded arsenal of options.
Doodad/Actor Runtime Options have been added:
* In the Doodad Editor's "Doodad Properties" window, see the new "Options" tab.
* Doodad Options allow a map creator to customize certain properties about your
doodad, on a per-instance basis (instances of doodads are called "actors" when
placed in your level).
* In the Level Editor when the Actor Tool is selected, mousing over a doodad on
your level will show a new gear icon in the corner. Clicking the icon will open
the Actor Properties window, where you may toggle some of the doodad options
(if a doodad has any options available).
* Options can be of type boolean, string, or integer and have a custom name and a
default value at the doodad level. In the Level Editor, the map creator can
set values for the available options which the doodad script can read using the
`Self.GetOption()` method.
* Several of the game's built-in doodads have options you can play with, which are
documented below.
New and updated doodads:
* "Look At Me" is a new Technical doodad that will draw the camera's attention
to it when it receives a power signal from a linked button. For example, if
a button would open an Electric Door far across the level, you can also place
a "Look At Me" near the door and link the button to both doodads. When the
button is pressed, the camera will scroll to the "Look At Me" and the player
can see that the door has opened.
* Anvils will now attract the camera's attention while they are falling.
Several of the game's built-in doodads have new Actor Runtime Options you can
configure in your custom levels:
* Warp Doors: "locked (exit only)" will make it so the player can not enter the
warp door - they will get a message on-screen that it is locked, similar to
how warp doors behave when they aren't linked to another door. If it is linked
to another door, the player may still exit from the 'locked' door -
essentially creating a one-way warp, without needing to rely on the
orange/blue state doors. The "Invisible Warp Door" technical doodad also
supports this option.
* Electric Door & Electric Trapdoor: check the "opened" option and these doors
will be opened by default when the level gameplay begins. A switch may still
toggle the doors closed, or if the doors receive and then lose a power signal
they will close as normal.
* Colored Doors & Small Key Door: you may mark the doors as "unlocked" at the
start of your level, and they won't require a key to open.
* Colored Keys & Small Key: you may mark the keys as "has gravity" and they
will be subject to the force of gravity and be considered a "mobile" doodad
that may activate buttons or trapdoors that they fall onto.
* Gemstones: these items already had gravity by default, and now they have a
"has gravity" option you may disable if you'd prefer gemstones not to be
subject to gravity (and make them behave the way keys used to).
* Gemstome Totems: for cosmetic purposes you may toggle the "has gemstone"
option and the totem will already have its stone inserted at level start.
These gemstones will NOT emit a power signal or interact normally with
linked totems - they should be configured this way only for the cosmetic
appearance, e.g., to have one totem filled and some others empty; only the
empty totems should be linked together and to a door that would open when
they are all filled.
* Fire Region: you may pick a custom "name" for this doodad (default is "fire")
to make it better behave as normal fire pixels do: "Watch out for (name)!"
Improvements in support of custom content:
* Add a JavaScript "Exception Catcher" window in-game. If your doodad scripts
encounter a scripting error, a red window will pop up showing the text of
the exception with buttons to copy the full text to your clipboard (in case
it doesn't all fit on-screen) and to suppress any further exceptions for
the rest of your game session (in case a broken doodad is spamming you with
error messages). Cheat codes can invoke the Exception Catcher for testing:
`throw <message>` to show custom text, `throw2` to test a "long" message
and `throw3` to throw a realistic message.
* Calling `console.log()` and similar from doodad scripts will now prefix the
log message with the doodad's filename and level ID.
There are new JavaScript API methods available to doodad scripts:
* `Self.CameraFollowMe()` will attract the game's camera viewport to center
on your doodad, taking the camera's focus away from the player character.
The camera will return to the player if they enter a directional input.
* `Self.Options()` returns a string array of all of the options available on
the current doodad.
* `Self.GetOption(name)` returns the configured value for a given option.
Some improvements to the `doodad` command-line tool:
* `doodad show` will print the Options on a .doodad file and, when showing
a .level file with the `--actors` option, will list any Options configured
on a level's actors where they differ from the doodad's defaults.
* `doodad edit-doodad` adds a `--option` parameter to define an option on a
doodad programmatically. The syntax is like `--option name=type=default`
for example `--option unlocked=bool=true` or `--option unlocked=bool`; the
default value is optional if you want it to be the "zero value" (false,
zero, or empty string).
Minor fixes and improvements:
* Add a "Wait" modal with a progress bar. Not used yet but may be useful
for long operations like Giant Screenshot or level saving to block input
to the game while it's busy doing something. Can be tested using the
cheat code "test wait screen"
* Detect the presence of a touchscreen device and automatically disable
on-screen touch hints during gameplay if not on a touch screen.
* Mobile Linux: mark the Sketchy Maze launcher as supporting the mobile
form-factor for the Phosh desktop shell especially.
* Fix the Crusher doodad sometimes not falling until it hits the ground
and stopping early on slower computers.
* Small tweaks to player physics - acceleration increased from 0.025 to
0.04 pixels per tick.
## v0.13.0 (May 7 2022)
This is a major update that brings deep architectural changes and a lot
of new content to the game.
Swimming physics have been added:
* The **water** pixels finally do something besides turn the character
blue: swimming physics have finally been hooked up!
* While the player is touching water pixels (and is colored blue),
your gravity and jump speed are reduced, but you can "jump"
infinite times in order to swim higher in the water. Hold the jump
button to climb slowly, spam it to climb quickly.
* The **Azulians** understand how to swim, too, though left to their
own devices they will sink to the bottom of a body of water. They'll
swim (jump) up if you're detected and above them. The Blue Azulian
has the shortest vertical aggro radius, so it's not a very good swimmer
but the White Azulian can traverse water with ease and track you
from a greater distance.
New levels:
* **The Jungle** (First Quest) - a direct sequel to the Boat level, it's
a jungle and Mayan themed platformer featuring many of the new doodads
such as snakes, gemstones, and crushers.
* **Gems & Totems** (Tutorial, Lesson 4) - a tutorial level about the
new Gem and Totem doodads.
* **Swimming** (Tutorial, Lesson 5) - a tutorial level to learn how
"water pixels" work with some moderately safe platforming puzzles
included.
* **Night Sky** (Azulian Tag) - a moderately difficult Azulian Tag level
with relatively few enemies but plenty of tricky platforming.
* Some of the existing levels have had minor updates to take advantage
of newer game features, such as the water being re-done for the Castle
level.
New doodads:
* **Blue Bird:** a blue version of the Bird which flies in a sine wave
pattern about its original altitude, and has a larger search range to
dive at the player character.
* **Snake:** a green snake that sits coiled up and always faces the
player. If you get nearby and try and jump over, the Snake will jump
up and hope to catch you.
* **Crusher:** a block-headed enemy with an iron helmet which tries to
drop on you from above. Its helmet makes a safe platform to ride
back up like an elevator.
* **Gems and Totems:** four collectible gems (in different colors and
shapes) that slot into Totems of a matching shape. Totems can link
together to require multiple gemstones before they'll emit a power
signal to other linked doodads.
New **File Formats**:
* Levels and Doodads have a new file format based on ZIP files,
like levelpacks.
* It massively improves loading screen times and helps the
game keep a substantially lighter memory footprint (up to 85%
less memory used, like 1.5 GB -> 200 MB on _Azulian Tag - Forest_).
* **Your old levels and doodads still work**! The next time you save
them, they will be converted to the new file format automatically.
* The `doodad` tool can also upgrade your levels by running:
`doodad edit-level --touch <filename>.level`
Other new content to use in your levels:
* New wallpapers: Dotted paper (dark), Parchment paper (red, blue,
green, and yellow).
* New palette: Neon Bright, all bright colors to pair with a dark level
wallpaper.
* New brush pattern: Bubbles. The default "water" color of all the game's
palettes will now use the Bubbles pattern by default.
New cheat codes:
* `super azulian`: play as the Red Azulian.
* `hyper azulian`: play as the White Azulian.
* `bluebird`: play as the Blue Bird.
* `warp whistle`: automatically win the current level, with a snarky
cheater message in the victory dialog. It will mark the level as
Completed but not reward a high score.
* `$ d.SetPlayerCharacter("anything.doodad")` - set your character to any
doodad you want, besides the ones that have dedicated cheat codes. The
".doodad" suffix is optional. Some to try out are "key-blue", "anvil",
or "box". If you are playing as a key, a mob might be able to collect
you! This will softlock the level, but another call to
`d.SetPlayerCharacter()` will fix it! Use the `pinocchio` cheat or
restart the game to return to the default character (boy.doodad)
Updates to the JavaScript API for doodads:
* `Self.IsWet() bool` can test if your actor is currently in water.
Other changes this release:
* Editor: fancy **mouse cursors** gives some visual feedback about what
tool is active in the editor, with a Pencil and a Flood Fill
cursor when those tools are selected.
* Editor: your **Palette** buttons will now show their pattern with their
color as the button face, rather than just the color.
* Editor: Auto-save is run on a background thread so that, for large
levels, it doesn't momentarily freeze the editor on save when it runs.
* Editor: Fix the Link Tool forgetting connections when you pick up and
drop one of the linked doodads.
* Link Tool: if you click a doodad and don't want to link it to another,
click the first doodad again to de-select it (or change tools).
* Editor: your last scroll position on a level is saved with it, so the
editor will be where you left it when you reopen your drawing.
* Doodad tool: `doodad edit-level --resize <int>` can re-encode a level
file using a different chunk size (the default has been 128).
Experimental! Very large or small chunk sizes can lead to different
performance characteristics in game!
* Fixed the bug where characters' white eyes were showing as transparent.
## v0.12.1 (April 16 2022)
This update focuses on memory and performance improvements for the game.
Some larger levels such as "Azulian Tag - Forest" could run out of
memory on 32-bit systems. To improve on memory usage, the game more
aggressively frees SDL2 textures when no longer needed and it doesn't
try to keep the _whole_ level's chunks ready in memory (as rendered
images) -- only the chunks near the window viewport are loaded, and
chunks that leave the viewport are freed to reclaim memory. Improvements
are still a work in progress.
New fields are added to the F3 debug overlay to peek at its performance:
* "Textures:" shows the count of SDL2 textures currently loaded
in memory. Some textures, such as toolbar buttons and the
loadscreen wallpaper, lazy load and persist in memory. Most level
and doodad textures should free when the level exits.
* "Sys/Heap:" shows current memory utilization in terms of MiB taken
from the OS and MiB of active heap memory, respectively.
* "Threads:" counts the number of goroutines currently active. In
gameplay, each actor monitors its PubSub queue on a goroutine and
these should clean up when the level exits.
* "Chunks:" shows the count of level chunks inside and outside the
loading viewport.
Some other changes and bug fixes in this release include:
* Fixed the bug where the player was able to "climb" vertical walls to
their right.
* When entering a cheat code that changes the default player character
during gameplay, you immediately become that character.
## v0.12.0 (March 27 2022)
This update adds several new features to gameplay and the Level Editor.
A **Game Rules** feature has been added to the Level Editor which allows
customizing certain gameplay features while that level is being played.
These settings are available in the Level Properties window of the editor:
* The **Difficulty** rule can modify the behavior of enemy doodads
when the level is played. Choose between Peaceful, Normal, or Hard.
* On Peaceful, Azulians and Birds don't attack the player, acting
like pre-0.11.0 versions that ignored the player character.
* On Hard difficulty, Azulians have an infinite aggro radius
(they'll immediately hunt the player from any distance on
level start) and they are hostile to _all_ player creatures.
* **Survival Mode** changes the definition of "high score" for levels
where the player is very likely to die at least once.
* The silver high score (respawned at checkpoint) will be for the
_longest_ time survived on the level rather than the fastest time
to complete it.
* The gold high score (got to an Exit Flag without dying once) is
still rewarded to the fastest time completing the level.
An update to the Level Editor's toolbar:
* New **Text Tool** to easily paste messages onto your level, selecting
from the game's built-in fonts.
* New **Pan Tool** to be able to scroll the level safely by dragging with
your mouse or finger.
* New **Flood Tool** (or paint bucket tool) can be used to replace
contiguous areas of your level from one color to another.
* The toolbar buttons are smaller and rearranged. On medium-size screens
or larger, the toolbar buttons are drawn side-by-side in two columns.
On narrower screens with less real estate, it will use a single column
when it fits better.
New levels:
* An **Azulian Tag** levelpack has been added featuring two levels so
far of the Azulian Tag game mode.
New doodads:
* A technical doodad for **Reset Level Timer** resets the timer to zero,
one time, when touched by the player. If the doodad receives a power
signal from a linked doodad, it can reset the level timer again if the
player touches it once more.
Updates to the JavaScript API for custom doodads:
* New global integer `Level.Difficulty` is available to doodad scripts to
query the difficulty setting of the current level:
* Peaceful (-1): `Level.Difficulty < 0`
* Normal (0): `Level.Difficulty == 0`
* Hard (1): `Level.Difficulty > 1`
* New function `Level.ResetTimer()` resets the in-game timer to zero.
New cheat codes:
* `test load screen` tests the loading screen UI for a few seconds.
* `master key` allows playing locked Story Mode levels without unlocking
them first by completing the earlier levels.
Other changes:
* Several screens were re-worked to be responsive to mobile screen sizes,
including the Settings window, loading screen, and the level editor.
* Fixed a bug where making the app window bigger during a loading screen
caused the Editor to not adapt to the larger window.
* Don't show the _autosave.doodad in the Doodad Dropper.
* The Azulians have had their jump heights buffed slightly.
* Birds no longer register as solid when colliding with other birds (or
more generally, characters unaffected by gravity).
Bugs fixed:
* When modifying your Palette to rename a color or add an additional
color, it wasn't possible to draw with that new color without fully
exiting and reloading the editor - this is now resolved.
* The palette editor will try and prevent the user from giving the same
name to different colors.
## v0.11.0 (Feb 21 2022)
New features:
* **Game Controller** support has been added! The game can now be played
with an Xbox style controller, including Nintendo Pro Controllers. The
game supports an "X Style" and "N Style" button layout, the latter of
which swaps the A/B and the X/Y buttons so gameplay controls match the
button labels in your controller.
* The **JavaScript Engine** for doodad scripts has been switched from
github.com/robertkrimen/otto to github.com/dop251/goja which helps
"modernize" the experience of writing doodads. Goja supports many
common ES6 features already, such as:
* Arrow functions
* `let` and `const` keywords
* Promises
* for-of loops
* The **JavaScript API** has been expanded with new functions and
many of the built-in Creatures have gotten an A.I. update.
* For full versions of the game, the **Publish Level** function is now
more streamlined to just a checkbox for automatically bundling your
doodads next time you save the level.
New levels:
* **The Zoo:** part of the Tutorial levelpack, it shows off all of the
game's built-in doodads and features a character selection room to
play as different creatures.
* **Shapeshifter:** a new level on the First Quest where you switch
controls between the Boy, Azulian and the Bird in order to clear the
level.
Some of the built-in doodads have updates to their A.I. and creatures
are becoming more dangerous:
* The **Bird** now searches for the player diagonally in front of
it for about 240px or so. If spotted it will dive toward you and
it is dangerous when diving! When _playing_ as the bird, the dive sprite
is used when flying diagonally downwards. The player-controlled bird
can kill mobile doodads by diving into them.
* The **Azulians** will start to follow the player when you get
close and they are dangerous when they touch you -- but not if
you're the **Thief.** The red Azulian has a wider search radius,
higher jump and faster speed than the blue Azulian.
* A new **White Azulian** has been added to the game. It is even faster
than the Red Azulian! And it can jump higher, too!
* The **Checkpoint Flag** can now re-assign the player character when
activated! Just link a doodad to the Checkpoint Flag like you do the
Start Flag. When the player reaches the checkpoint, their character
sprite is replaced with the linked doodad!
* The **Anvil** is invulnerable -- if the player character is the Anvil
it can not die by fire or hostile enemies, and Anvils can not destroy
other Anvils.
* The **Box** is also made invulnerable so it can't be destroyed by a
player-controlled Anvil or Bird.
New functions are available on the JavaScript API for doodads:
* `Actors.At(Point) []*Actor`: returns actors intersecting a point
* `Actors.FindPlayer() *Actor`: returns the nearest player character
* `Actors.New(filename string)`: create a new actor (NOT TESTED YET!)
* `Self.Grounded() bool`: query the grounded status of current actor
* `Actors.SetPlayerCharacter(filename string)`: replace the nearest
player character with the named doodad, e.g. "boy.doodad"
* `Self.Invulnerable() bool` and `Self.SetInvulnerable(bool)`: set a
doodad is invulnerable, especially for the player character, e.g.
if playing as the Anvil you can't be defeated by mobs or fire.
New cheat codes:
* `god mode`: toggle invincibility. When on, fire pixels and hostile
mobs can't make you fail the level.
* `megaton weight`: play as the Anvil by default on levels that don't
specify a player character otherwise.
Other changes:
* When respawning from a checkpoint, the player is granted 3 seconds of
invulnerability; so if hostile mobs are spawn camping the player, you
don't get soft-locked!
* The draw order of actors on a level is now deterministic: the most
recently added actor will always draw on top when overlapping another,
and the player actor is always on top.
* JavaScript exceptions raised in doodad scripts will be logged to the
console instead of crashing the game. In the future these will be
caught and presented nicely in an in-game popup window.
* When playing as the Bird, the flying animation now loops while the
player is staying still rather than pausing.
* The "Level" menu in Play Mode has options to restart the level or
retry from last checkpoint, in case a player got softlocked.
* When the game checks if there's an update available via
<https://download.sketchymaze.com/version.json> it will send a user
agent header like: "Sketchy Maze v0.10.2 on linux/amd64" sending only
static data about the version and OS.
## v0.10.1 (Jan 9 2022)
New features:
* **High scores and level progression:** when playing levels out of
a Level Pack, the game will save your progress and high scores on
each level you play. See details on how scoring works so far, below.
* **Auto-save** for the Editor. Automatically saves your drawing every
5 minutes. Look for e.g. the _autosave.level to recover your drawing
if the game crashed or exited wrongly!
* **Color picker UI:** when asked to choose a color (e.g. for your level
palette) a UI window makes picking a color easy! You can still manually
enter a hexadecimal color value but this is no longer required!
Scoring system:
* The high score on a level is based on how quickly you complete it.
A timer is shown in-game and there are two possible high scores
for each level in a pack:
* Perfect Time (gold): if you complete the level without dying and
restarting at a checkpoint.
* Best Time (silver): if you had used a checkpoint.
* The gold/silver icon is displayed next to the timer in-game; it
starts gold and drops to silver if you die and restart from checkpoint.
It gives you a preview of which high score you'll be competing with.
* If cheat codes are used, the user is not eligible for a high score
but may still mark the level "completed."
* Level Packs may have some of their later levels locked by default,
with only one or a few available immediately. Completing a level will
unlock the next level until they have all been unlocked.
New and changed doodads:
* **Invisible Warp Door:** a technical doodad to create an invisible
Warp Door (press Space/'Use' key to activate).
* All **Warp Doors** now require the player to be grounded before they
can be opened, or else under the effects of antigravity. You shouldn't
be able to open Warp Doors while falling or jumping off the ground
at them.
Revised levels:
* Desert-2of2.level uses a new work-around for the unfortunate glitch
of sometimes getting stuck on two boxes, instead of a cheat code
being necessary to resolve.
* Revised difficulty on Tutorial 2 and Tutorial 3.
Miscellaneous changes:
* Title Screen: picks a random level from a few options, in the future
it will pick random user levels too.
* Play Mode gets a menu bar like the Editor for easier navigation to
other game features.
* New dev shell command: `titlescreen <level name>` to load the Title
Screen with the named level as its background, can be used to load
user levels _now_.
* For the doodads JavaScript API: `time.Since()` is now available (from
the Go standard library)
* Fix a cosmetic bug where doodads scrolling off the top or left edges
of the level were being drawn incorrectly.
* Fix the Editor's status bar where it shows your cursor position
relative to the level and absolute to the app window to show the
correct values of each (they were reversed before).
* The developer shell now has a chatbot in it powered by RiveScript.
## v0.10.0 (Dec 30 2021)
New features and changes:
* **Level Packs:** you can group a set of levels into a sequential
adventure. The game's built-in levels have been migrated into Level
Packs and users can create their own, too!
* **Crosshair Option:** in the level editor you can have a crosshair
drawn at your cursor position, which may help align things while
making a level. Find the option in the game's Settings window.
* **Smaller Palette Colors:** the color buttons in the Level Editor are
smaller and fit two to a row. This allows for more colors but may be
difficult for touch controls.
* Doodad AI updates: the **Bird** records its original altitude and will
attempt to fly back there when it can, so in case it slid up or down a
ramp it will correct its height when it comes back the other way.
* The "New Level" and "New Doodad" functions on the main menu are
consolidated into a window together that can create either, bringing
a proper UI to creating a doodad.
* Added a setting to **hide touch control hints** from Play Mode.
* The title screen is more adaptive to mobile. If the window height isn't
tall enough to show the menu, it switches to a 'landscape mode' layout.
* Adds a custom icon to the application window.
A few notes about level packs:
* A levelpack is basically a zip file containing levels and custom
doodads. **Note:** the game does not yet handle the doodads folder
of a levelpack at all.
* The `doodad` command-line tool can create .levelpack files. See
`doodad levelpack create --help`. This is the easiest way to
generate the `index.json` file.
* In the future, a .levelpack will be able to hold custom doodads on
behalf of the levels it contains, de-duplicating files and saving
on space. Currently, the levels inside your levelpack should embed
their own custom doodads each.
* Free (shareware) editions of the game can create and play custom
level packs that use only the game's built-in doodads. Free versions
of the game can't play levels with embedded custom doodads. You can
always copy custom .doodad files into your profile directory though!
Bugs fixed:
* Undo/Redo now works again for the Doodad Editor.
* Fix crash when opening the Doodad Editor (v0.9.0 regression).
* The Play Level/Edit Drawing window is more responsive to small screens
and will draw fewer columns of filenames.
* Alert and Confirm popup modals always re-center themselves, especially
to adapt to the user switching from Portrait to Landscape orientation
on mobile.
## v0.9.0 (Oct 9, 2021)
New features:

View File

@ -1,27 +1,66 @@
# Controls
**Sketchy Maze** currently uses a mouse and keyboard for inputs, but eventually
will be usable from gamepad controllers, especially if it branches out and
targets platforms other than desktop computers in the future.
**Sketchy Maze** can be played with a variety of input devices including keyboard & mouse, touch screen, or Xbox-style game controllers.
The list of controls is also viewable in-game in the Settings Window, accessible
from the title screen or the Edit->Settings menu of the editor. The controls can
not be customized at this time.
The list of controls is also viewable in-game in the Settings Window, accessible from the title screen or the Edit->Settings menu of the editor. The controls can not be customized at this time.
![Controls UI](images/controls.png)
## During Gameplay
## Gamepad Controls
An Xbox-style game controller can be used with Sketchy Maze. Nintendo-style controllers also work, such as a Switch Pro Controller. The game has a built-in "X Style" or "N Style" setting to make sure the A/B and X/Y buttons map correctly based on your controller. You can choose which button style you prefer in the game's Settings window.
The gamepad controls currently operate under two different "modes" which are described below.
### Mouse Mode
The default gamepad controls will emulate a mouse cursor, allowing you to navigate the game's screens and work with the Level Editor. Under Mouse Mode, the gamepad controls are as follows:
* The **Left analog stick** moves a mouse cursor around the screen.
* The **Right analog stick** can scroll the level on the title screen or editor.
* The **A** and **X** buttons act as a "left click" to activate buttons and draw pixels in the level editor.
* The **B** and **Y** buttons act as a "right click," e.g. to remove doodads from your level while the Doodad Tool is selected.
* The **Left shoulder** button (L1) acts as a "middle click", e.g. to pan the level around on the title screen or editor.
* The **Left trigger** button (L2) will close the top-most popup window in the level editor (similar to the Backspace key on keyboard controls).
### Gameplay Mode
When level gameplay begins, the game controller will move the player character around using familiar controls.
* The **Left analog stick** and the **D-Pad** will move the player character left or right. If playing as the Bird or under the effects of antigravity, the control stick can also move the player up and down.
* The **A** and **X** buttons are to "Use" an object, such as to open a Warp Door.
* The **B** and **Y** buttons are to "Jump"
* The **Right shoulder** button (R1) toggles the gamepad controls between Gameplay Mode and Mouse Mode. So, during gameplay you may access the menu bar or on-screen buttons by toggling into Mouse Mode.
## Touch Controls
Buttons and UI windows can be touched and dragged around as though your finger is a mouse cursor. There are also some gestures supported:
* Drag two fingers across the screen to **pan a scrollable drawing** such as in the Level Editor or the Title Screen.
* Tip: for the Level Editor select the Actor Tool or Link Tool before panning the level, otherwise you might plot some pixels on your map before the game realizes you were just wanting to scroll!
During gameplay, touch any region of the screen surrounding the center to move the player character in the relative direction you touched. By default, if you are idle in a level for a few seconds some on-screen hints will appear about the touch controls:
![Touch Controls Hint](images/touch-controls.png)
The square in the middle that says "Touch here to 'use' objects" is the center of your screen and all the other touch regions are directly touching this square.
* Touch anywhere above center to **Jump.**
* Touch anywhere left of center to **Move left.**
* Touch anywhere right of center to **Move right.**
* Touch anywhere below center to **Move downwards.** (note: for flying characters like the Bird or during times of antigravity)
* Touch the center to **Use** objects (such as to open a Warp Door).
Generally the center is aligned on the player character unless you're close to level boundaries.
## Keyboard Controls (Gameplay)
While playing a level, the following keys are used to control the player character:
* **Left** and **Right** arrow keys move the player left or right.
* **Up** arrow to make the player jump.
* **Space Bar** is used to "activate" certain doodads. Currently, only the
[Warp Doors](doodads.md#warp-doors) require deliberate activation; Buttons and
Switches activate _automatically_ when the player character (or other mobile
doodad) touches them.
* **Space Bar** is used to "activate" certain doodads. Currently, only the [Warp Doors](doodads.md#warp-doors) require deliberate activation; Buttons and Switches activate _automatically_ when the player character (or other mobile doodad) touches them.
## Hotkeys
See the [Hotkeys](hotkeys.md) page for shortcut keys, especially around the
Level Editor feature.
See the [Hotkeys](hotkeys.md) page for shortcut keys, especially around the Level Editor feature.

View File

@ -0,0 +1,745 @@
# JavaScript API
This page describes the JavaScript API available to Doodad scripts. These take the form of globally available functions that provide hooks into the game's logic and empower doodads to react to their surroundings and communicate with other doodads on the level.
During gameplay, the doodads are called "actors" which are the _instantiated_ form of the doodad; meaning, they are running their scripts and have come "alive" during gameplay. The surface area of functions available on the [Self](#self) object (which points to the current actor) is also available on other actors, such as the `e.Actor` property of [OnCollide](#eventsoncollide-funcevent) events or the actor returned by the [Actors.FindPlayer()](#actorsfindplayer-actor) function.
Table of Contents:
* [Global Functions](#global-functions)
* [EndLevel()](#endlevel)
* [FailLevel()](#faillevelmessage-string)
* [SetCheckpoint()](#setcheckpointpoint)
* [Flash()](#flashmessage-string-args)
* [GetTick()](#gettick-uint64)
* [time.Now()](#timenow-timetime)
* [time.Add()](#timeaddt-timetime-milliseconds-int64-timetime)
* [time.Since()](#timesincetimetime-timeduration) `v0.10.1`
* [Console Logging](#console-logging)
* [Self](#self) - functions for the current (and other) actors
* [Self.ID()](#selfid-string)
* [Self.IsPlayer()](#selfisplayer-bool) `v0.8.0`
* [Self.GetTag()](#selfgettagstring-name-string)
* [Self.Options()](#selfoptions-string) `v0.13.1`
* [Self.GetOption()](#selfgetoptionstring-name-any) `v0.13.1`
* [Self.Position()](#selfposition-point)
* [Self.MoveTo()](#selfmovetopoint)
* [Self.CameraFollowMe()](#selfcamerafollowme) `v0.13.1`
* [Self.SetHitbox()](#selfsethitboxx-y-w-h-int)
* [Self.Hitbox()](#selfhitbox-rect) `v0.8.0`
* [Self.SetVelocity()](#selfsetvelocityvelocity)
* [Self.GetVelocity()](#selfgetvelocity-velocity) `v0.9.0`
* [Self.SetMobile()](#selfsetmobilebool)
* [Self.SetGravity()](#selfsetgravitybool)
* [Self.SetInvulnerable()](#selfsetinvulnerablebool) `v0.11.0`
* [Self.Invulnerable()](#selfinvulnerable-bool) `v0.11.0`
* [Self.Hide(), Self.Show()](#selfhide-selfshow) `v0.9.0`
* [Self.SetInventory()](#selfsetinventorybool)
* [Self.AddItem()](#selfadditemfilename-string-quantity-int)
* [Self.RemoveItem()](#selfremoveitemfilename-string-quantity-int)
* [Self.HasItem()](#selfhasitemfilename-string-bool)
* [Self.Inventory()](#selfinventory-mapstringint)
* [Self.ShowLayer()](#selfshowlayerindex-int)
* [Self.ShowLayerNamed()](#selfshowlayernamedname-string)
* [Self.AddAnimation()](#selfaddanimationname-string-interval-int-layers-list)
* [Self.PlayAnimation()](#selfplayanimationname-string-callback-func)
* [Self.IsAnimating()](#selfisanimating-bool)
* [Self.StopAnimation()](#selfstopanimation)
* [Self.Destroy()](#selfdestroy)
* [Actors](#actors) - actor management functions
* [Actors.At()](#actorsatpoint-actor) `v0.11.0`
* [Actors.FindPlayer()](#actorsfindplayer-actor) `v0.11.0`
* [Actors.New()](#actorsnewfilename-string-actor) `v0.11.0`
* [Actors.SetPlayerCharacter()](#actorssetplayercharacterfilename-string) `v0.11.0`
* [Level](#level) - functions and variables relating to the level
* [Level.Difficulty](#leveldifficulty-int) `v0.12.0`
* [Level.ResetTimer](#levelresettimer) `v0.12.0`
* [Timers and Intervals](#timers-and-intervals)
* [setTimeout()](#settimeoutfunction-milliseconds-int-int)
* [setInterval()](#setintervalfunction-milliseconds-int-int)
* [clearTimeout()](#cleartimeoutid-int)
* [clearInterval()](#clearintervalid-int)
* [Type Constructors](#type-constructors) - native types
* [RGBA(r,g,b,a)](#rgbared-green-blue-alpha-uint8)
* [Point(x,y)](#pointx-y-int)
* [Vector(x,y)](#vectorx-y-float64)
* [Event Handlers](#event-handlers)
* [Events.OnCollide()](#eventsoncollide-funcevent)
* [Events.OnLeave()](#eventsonleave-funcevent)
* [Events.RunKeypress()](#eventsrunkeypress-funcevent)
* [Pub/Sub Communication](#pubsub-communication) - for linked doodads
* [Official, Standard Pub/Sub Messages](#official-standard-pubsub-messages)
* [Message.Publish()](#messagepublishname-string-data)
* [Message.Subscribe()](#messagesubscribename-string-function)
* [Message.Broadcast()](#messagebroadcastname-string-data)
* * *
## Global Functions
Some useful globally available functions:
### EndLevel()
This ends the current level in a win condition, i.e. to be used by the goal flag.
### FailLevel(message string)
Trigger a failure condition in the level. For example, a hazardous doodad can cause a death message as though the player had touched a "fire" pixel on the level.
### SetCheckpoint(Point)
Set the respawn point for the player character. Usually, this will be relative to a checkpoint flag's location on the level.
```javascript
Events.OnCollide(function(e) {
if (e.Settled && e.Actor.IsPlayer()) {
SetCheckpoint(Self.Position());
}
})
```
### Flash(message string, args...)
Flash a message on screen to the user.
Flashed messages appear at the bottom of the screen and fade out after a few moments. If multiple messages are flashed at the same time, they stack from the bottom of the window with the newest message on bottom.
Don't abuse this feature as spamming it may annoy the player.
### GetTick() uint64
Returns the current game tick. This value started at zero when the game was launched and increments every frame while running.
### time.Now() time.Time
This exposes the Go standard library function `time.Now()` that returns the current date and time as a Go time.Time value.
### time.Add(t time.Time, milliseconds int64) time.Time
Add a number of milliseconds to a Go Time value.
### time.Since(time.Time) time.Duration
**New in v0.10.1**
Get the duration since a time. Example:
```javascript
var now = time.Now()
// later
if (time.Since(now) > 5 * time.Minute) {
// 5 minutes have passed
}
```
The `time` global exposes the following duration intervals as seen in the above example:
* time.Hour
* time.Minute
* time.Second
* time.Millisecond
* time.Microsecond
* * *
## Console Logging
Like in node.js and the web browser, `console.log` and friends are available for logging from a doodad script. Logs are emitted to the same place as the game's logs are.
```javascript
console.log("Hello world!");
console.log("Interpolate strings '%s' and numbers '%d'", "string", 123);
console.debug("Debug messages shown when the game is in debug mode");
console.warn("Warning-level messages");
console.error("Error-level messages");
```
* * *
## Self
Self holds data about the current doodad instance loaded inside of a level. Many of these are available on other actors that collide with your doodad in the OnCollide handler, at event.Actor.
**String attributes:**
* Self.Title: the doodad title.
* Self.Filename: the doodad filename (useful for inventory items).
Methods are below.
### Self.ID() string
Returns the "actor ID" of the doodad instance loaded inside of a level. This is usually a random UUID string that was saved with the level data.
### Self.IsPlayer() bool
**New in v0.8.0**
Check if the doodad is the player character. Some enemy creature doodads check this so as to disable their normal A.I. movement pattern and allow player controls to set its animations.
### Self.GetTag(string name) string
Return a "tag" that was saved with the doodad's file data.
Tags are an arbitrary key/value data store attached to the doodad file. You can configure the tags in-game in the Doodad Properties window of the editor, or can use the `doodad.exe` tool shipped with the game to view and manage tags on your own custom doodads:
```bash
# Command-line doodad tool usage:
# Show information about a doodad, look for the "Tags:" section.
doodad show filename.doodad
# Set a tag. "-t" for short.
doodad edit-doodad --tag 'color=blue' filename.doodad
# Set the tag to empty to remove it.
doodad edit-doodad -t 'color=' filename.doodad
```
This is useful for a set of multiple doodads to share the same script but have different behavior depending on how each is tagged. For example, the colored keys & doors are tagged with their color so they know which color doodads they interact with.
### Self.Options() []string
**New in v0.13.1**
Returns the list of Option names defined on the doodad.
### Self.GetOption(string name) Any
**New in v0.13.1**
Get the value for an Option on this actor.
If the map creator has customized the option value, it will be returned here; otherwise the default Option at the doodad level has its value returned. If the option name didn't exist, it returns `null`
The type of the returned value will be a correct type based on the Option settings: booleans will be proper `true/false` types, integers proper Number types, etc.
### Self.Position() Point
Returns the doodad's current position in the level.
Point is an object with .X and .Y integer values.
```javascript
var p = Self.Position()
console.log("I am at %d,%d", p.X, p.Y)
```
### Self.MoveTo(Point)
Teleport the current doodad to an exact point on the level.
```javascript
// Teleport to origin.
Self.MoveTo(Point(0, 0))
```
### Self.CameraFollowMe()
**New in v0.13.1**
Attract the focus of the game's camera to be centered on your doodad, instead of the player character.
If the player inputs a directional control, they will reclaim the camera's focus.
### Self.SetHitbox(x, y, w, h int)
Configure the "solid hitbox" of this doodad.
You can configure the hitbox in-game in the Doodad Properties window. It is not necessary to call SetHitbox() from your doodad script.
The X and Y coordinates are relative to the doodad's sprite: (0,0) is the top left pixel of the doodad. The W and H are the width and height of the hitbox starting at those coordinates.
When another doodad enters the area of your doodad's sprite (for example, the player character has entered the square shape of your doodad sprite) your script begins to receive OnCollide events from the approaching actor.
The OnCollide event tells you if the invading doodad is inside your custom hitbox which you define here (`InHitbox`) making it easy to make choices based on that status.
Here's an example script for a hypothetical "locked door" doodad that acts solid but only on a thin rectangle in the middle of its sprite:
```javascript
// Example script for a "locked door"
function main() {
// Suppose the doodad's sprite size is 64x64 pixels square.
// The door is in side profile where the door itself ranges from pixels
// (20, 0) to (24, 64)
Self.SetHitbox(20, 0, 24, 64)
// OnCollide handlers.
Events.OnCollide(function(e) {
// The convenient e.InHitbox tells you if the colliding actor is
// inside the hitbox we defined.
if (e.InHitbox) {
// Return false to protest the collision (act solid).
return false;
}
});
}
```
### Self.Hitbox() Rect
**New in v0.8.0**
Return the current hitbox of your doodad. If you did not call Self.SetHitbox() yourself, then this will return the hitbox that was configured on the Doodad's Properties.
Check Self.Hitbox().IsZero() to see whether the doodad has a hitbox configured at all (having a value of 0,0,0,0). For example, the generic doodad scripts run checks like this:
```javascript
function main() {
// If the doodad does not have a hitbox set, default it to
// the full square canvas size of this doodad.
if (Self.Hitbox().IsZero()) {
var size = Self.Size();
Self.SetHitbox(0, 0, size, size);
}
}
```
### Self.SetVelocity(Velocity)
Set the doodad's velocity. Velocity is a type that can be created with the Velocity() constructor, which takes an X and Y value:
```javascript
Self.SetVelocity( Velocity(3.2, 7.0) );
```
A positive X velocity propels the doodad to the right. A positive Y velocity propels the doodad downward.
### Self.GetVelocity() Velocity
**New in v0.9.0**
Returns the current velocity of the doodad.
Note: for playable characters, velocity is currently managed by the game engine.
### Self.SetMobile(bool)
Call `SetMobile(true)` if the doodad will move on its own.
This is for mobile doodads such as the player character and enemy mobs. Stationary doodads like buttons, doors, and trapdoors do not mark themselves as mobile.
Mobile doodads incur extra work for the game doing collision checking so only set this to `true` if your doodad will move (i.e. changes its Velocity or Position).
```javascript
Self.SetMobile(true);
```
### Self.SetGravity(bool)
Set whether gravity applies to this doodad. By default doodads are stationary and do not fall downwards. The player character and some mobile enemies that want to be affected by gravity should opt in to this.
```javascript
Self.SetGravity(true);
// HasGravity to check.
console.log(Self.HasGravity()); // true
```
### Self.SetInvulnerable(bool)
**New in v0.11.0**
Set whether the actor should be marked as invulnerable.
If the player character's actor is invulnerable, it will be immune to fire pixels and hostile mobs won't be able to harm them.
Certain doodads will behave differently to a doodad which is marked as invulnerable. For example, the Anvil can destroy all mobile doodads but it won't destroy other Anvils because they are invulnerable. If the player is playing _as_ the Anvil, it can destroy mobs by jumping onto them but the mobs can not harm the player.
### Self.Invulnerable() bool
**New in v0.11.0**
Returns whether the invulnerable flag is currently set on an actor.
### Self.Hide(), Self.Show()
**New in v0.9.0**
Hide the current doodad to make it invisible and Show it again.
### Self.SetInventory(bool)
Set whether this doodad has an inventory and can carry items. Doodads without inventories can not pick up keys and other items.
The player character always has an inventory, regardless which doodad they are playing as.
```javascript
Self.SetInventory(true);
Self.GetInventory(); // true
```
### Self.AddItem(filename string, quantity int)
Add an item to the current doodad's inventory. The filename is the name of the item to add, such as "key-blue.doodad"
If the quantity is zero, the item goes in as a "key item" which does not show a quantity in your inventory. The four colored keys are examples of this, as compared to the Small Key which has a quantity.
### Self.RemoveItem(filename string, quantity int)
Remove items from the current doodad's inventory.
### Self.HasItem(filename string) bool
Tests if the item is in the inventory.
### Self.Inventory() map\[string\]int
Returns the doodad's full inventory data, an object that maps filename strings to quantity integers.
### Self.ShowLayer(index int)
Switch the active layer of the doodad to the layer at this index.
A doodad file can contain multiple layers, or images. The first and default layer is at index zero, the second layer at index 1, and so on.
```javascript
Self.ShowLayer(0); // 0 is the first and default layer
Self.ShowLayer(1); // show the second layer instead
```
### Self.ShowLayerNamed(name string)
Switch the active layer by name instead of index.
Each layer has an arbitrary name that it can be addressed by instead of needing to keep track of the layer index.
Doodads created by the command-line `doodad` tool will have their layers named automatically by their file name. The layer **indexes** will retain the same order of file names passed in, with 0 being the first file:
```bash
# Doodad tool-created doodads have layers named after their file names.
# example "open-1.png" will be named "open-1"
doodad convert door.png open-1.png open-2.png open-3.png my-door.doodad
```
### Self.AddAnimation(name string, interval int, layers list)
Register a named animation for your doodad. `interval` is the time in milliseconds before going to the next frame. `layers` is an array of layer names or indexes to be used for the animation.
Doodads can animate by having multiple frames (images) in the same file. Layers are ordered (layer 0 is the first, then increments from there) and each has a name. This function can take either identifier to specify which layers are part of the animation.
```javascript
// Animation named "open" using named layers, 100ms delay between frames.
Self.AddAnimation("open", 100, ["open-1", "open-2", "open-3"]);
// Animation named "close" using layers by index.
Self.AddAnimation("close", 100, [3, 2, 1]);
```
### Self.PlayAnimation(name string, callback func())
This starts playing the named animation. The callback function will be called when the animation has completed.
```javascript
Self.PlayAnimation("open", function() {
console.log("I've finished opening!");
// The callback is optional; use null if you don't need it.
Self.PlayAnimation("close", null);
});
```
### Self.IsAnimating() bool
Returns true if an animation is currently being played.
### Self.StopAnimation()
Stops any currently playing animation.
* 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.
### Self.Destroy()
This destroys the current instance of the doodad as it appears in a level.
For example, a Key destroys itself when it's picked up so that it disappears from the level and can't be picked up again. Call this function when the doodad instance should be destroyed and removed from the active level.
* * *
## Actors
The Actors API provides functions relating to other doodads (actors) on the level.
### Actors.At(Point) \[\]\*Actor
**New in v0.11.0**
Returns a list of the actors that intersect the given point in the level. For example, the Bird seeks the player character by scanning in a 45-degree angle and checking Actors.At() to see whether the player is at any of those points.
```javascript
let actors = Actors.At(Point(123, 456));
for (let a of actors) {
console.log("Saw actor %s", a.ID());
}
```
### Actors.FindPlayer() \*Actor
**New in v0.11.0**
Returns the nearest player character. While the game is single player, this will return **the** player character no matter where they are on the level. When multiplayer is added, it will return the player nearest to the position of the actor which asked.
The Azulians use this to identify the player and decide if the player's position is within aggro range, or to move the Azulian in the direction closest to the player character.
### Actors.New(filename string) \*Actor
**New in v0.11.0**
> **NOT TESTED:** this function supports future growth in the game but has not been tested yet and may have bugs.
Create a new actor and place them on the level. The filename will be the doodad name, like `example.doodad`. Returns the newly created Actor so that you may call functions like MoveTo() or SetVelocity() on it.
### Actors.SetPlayerCharacter(filename string)
**New in v0.11.0**
Replace the nearest player character with the named doodad.
This is used by the Checkpoint Flag when the flag is linked to a doodad so that it replaces the player character with it.
* * *
## Level
### Level.Difficulty int
**New in v0.12.0**
This integer holds the difficulty setting of the current level:
* \-1 is Peaceful
* 0 is Normal (default)
* 1 is Hard
An enemy doodad can alter its behavior by checking the difficulty level. For example, the Azulians become more aggressive on Hard difficulty.
```javascript
if (Level.Difficulty > 0) {
// Hard mode
} else if (Level.Difficulty < 0) {
// Peaceful mode
}
```
### Level.ResetTimer()
**New in v0.12.0**
Calling this function will reset the in-game level timer to zero.
* * *
## Timers and Intervals
Like in a web browser, functions such as setTimeout and setInterval are supported in doodad scripts.
### setTimeout(function, milliseconds int) int
setTimeout calls your function after the specified number of milliseconds.
1000ms are in one second.
Returns an integer "timeout ID" that you'll need if you want to cancel the timeout with clearTimeout.
### setInterval(function, milliseconds int) int
setInterval calls your function repeatedly after every specified number of milliseconds.
Returns an integer "interval ID" that you'll need if you want to cancel the interval with clearInterval.
### clearTimeout(id int)
Cancels the timeout with the given ID.
### clearInterval(id int)
Cancels the interval with the given ID.
* * *
## Type Constructors
Some methods may need data of certain native types that aren't available in JavaScript. These global functions will initialize data of the correct types:
### RGBA(red, green, blue, alpha uint8)
Creates a Color type from red, green, blue and alpha values (integers between 0 and 255).
### Point(x, y int)
Creates a Point object with X and Y coordinates.
### Vector(x, y float64)
Creates a Vector object with X and Y dimensions.
* * *
## Event Handlers
Doodad scripts can respond to certain events using functions on the global `Events` variable.
### Events.OnCollide( func(event) )
OnCollide is called when another actor is colliding with your doodad's sprite box. The function is given a CollideEvent object which has the following attributes:
* Actor: the doodad which is colliding with your doodad.
* Overlap (Rect): a rectangle of where the two doodads' boxes are overlapping, relative to your doodad sprite's box. That is, if the Actor was moving in from the left side of your doodad, the X value would be zero and W would be the number of pixels of overlap.
* InHitbox (bool): true if the colliding actor's hitbox is intersecting with the hitbox you defined with SetHitbox().
* Settled (bool): This is `false` when the game is trying to move the colliding doodad and is sussing out whether or not your doodad will act solid and protest its movement. When the game has settled the location of the colliding doodad it will call OnCollide a final time with Settled=true. If your doodad has special behavior when touched (i.e. a button that presses in), you should wait until Settled=true before running your handler for that.
### Events.OnLeave( func(event) )
Called when an actor that _was_ colliding with your doodad is no longer colliding (or has left your doodad's sprite box).
The event argument is the same as OnCollide, with the Actor available and Settled=true (others left as default zero values).
### Events.RunKeypress( func(event) )
Handle a keypress. `event` is an `event.State` from the render engine.
TODO: document that.
* * *
## Pub/Sub Communication
Doodads in a level are able to send and receive messages to other doodads, either those that they are **linked** to or those that listen on a more 'broadcast' frequency.
> **Linking** is when the level author connected two doodads together with the Link Tool. The two doodads' scripts can communicate with each other in-game over that link.
For example, if the level author links a Button to an Electric Door, the button can send a "power" event to the door so that it can open when a player touches the button.
Doodads communicate in a "publisher/subscriber" model: one doodad publishes an event with a name and data, and other doodads subscribe to the named event to receive that data.
### Official, Standard Pub/Sub Messages
The following message names and data types are used by the game's default doodads. You're free to use these in your own custom doodads.
If extending this list with your own custom events, be careful to choose a unique namespace to prevent collision with other users' custom doodads and their custom event names.
| Name | Data Type | Description |
|------|-----------|-------------|
| power | boolean | Communicates a "powered" (true) or "not powered" state, as in a Button to an Electric Door. |
| broadcast:ready | (none) | The level is ready and it is now safe for doodads to publish messages to others. |
| broadcast:state-change | boolean | An "ON/OFF" button was hit and all state blocks should flip. |
| broadcast:checkpoint | string | A checkpoint flag was reached. Value is the actor ID of the checkpoint flag. |
| sticky:down | boolean | A sticky button is pressed Down. If linked to other normal buttons, it tells them to press down as well. Sends a `false` when the Sticky Button itself pops back up. |
| switch:toggle | boolean | A switch has been toggled from on to off. |
### Message.Publish(name string, data...)
Publish a named message to all of your **linked** doodads.
`data` is a list of arbitrary arguments to send with the message.
```javascript
// Example button doodad that emits a "power" (bool) state to linked doodads
// that subscribe to this event.
function main() {
// When an actor collides with the button, emit a powered state.
Events.OnCollide(function(e) {
Message.Publish("power", true);
});
// When the actor leaves the button, turn off the power.
Events.OnLeave(function(e) {
Message.Publish("power", false);
})
}
```
### Message.Subscribe(name string, function)
Subscribe to a named message from any **linked** doodads.
The function receives the data that was passed with the message. Its data type is arbitrary and will depend on the type of message.
```javascript
// Example electronic device doodad that responds to power from linked buttons.
function main() {
// Boolean to store if our electric device has juice.
var powered = false;
// Do something while powered
setInterval(function() {
if (powered) {
console.log("Brmm...")
}
}, 1000);
// Subscribe to the `power` event by a linked button or other power source.
Message.Subscribe("power", function(boolValue) {
console.log("Powered %s!", boolValue === true ? "on" : "off");
powered = boolValue;
});
}
```
### Message.Broadcast(name string, data...)
This publishes a named message to **every** doodad in the level, whether it was linked to the broadcaster or not.
For example the "ON/OFF" button globally toggles a boolean state in every state block that subscribes to the `broadcast:state-change` event.
If you were to broadcast an event like `power` it would activate every single power-sensitive doodad on the level.
```javascript
// Example two-state block that globally receives the state-change broadcast.
function main() {
var myState = false;
Message.Subscribe("broadcast:state-change", function(boolValue) {
// Most two-state blocks just flip their own state, ignoring the
// boolValue passed with this message.
myState = !myState;
});
}
// Example ON/OFF block that emits the state-change broadcast. It also
// subscribes to the event to keep its own state in sync with all the other
// ON/OFF blocks on the level when they get hit.
function main() {
var myState = false;
// Listen for other ON/OFF button activations to keep our state in
// sync with theirs.
Message.Subscribe("broadcast:state-change", function(boolValue) {
myState = boolValue;
});
// When collided with, broadcast the state toggle to all state blocks.
Events.OnCollide(function(e) {
if (e.Settled) {
myState = !!myState;
Message.Broadcast("broadcast:state-change", myState);
}
})
}
```

View File

@ -1,33 +1,22 @@
# Creating Custom Levels
One of the core gameplay features is the Level Editor which lets you draw your
own custom maps to play and share with others.
One of the core gameplay features is the Level Editor which lets you draw your own custom maps to play and share with others.
From the game's Main Menu, click on the "Create a Level" button to open the
level editor. To edit an existing custom level, click on the "Edit a Level"
button instead.
From the game's Main Menu, click on the "Create a Level" button to open the level editor. To edit an existing custom level, click on the "Edit a Level" button instead.
## Level Properties
When creating a new level, you first choose some settings for it. These are
described below:
When creating a new level, you first choose some settings for it. These are described below:
![Screenshot of New Level dialog](../images/newlevel-1.png)
### Page Type
This setting controls the size and boundaries of your level, and control the
appearance of the notebook paper background of your level.
This setting controls the size and boundaries of your level, and control the appearance of the notebook paper background of your level.
* **Bounded** is the default. The camera won't scroll past the top-left corner
of the page (0,0), and the level size is capped to 2550x3300, or the
approximate size of an 11:9 standard sheet of notebook paper in pixels.
* **No Negative Space** is like Bounded, but the width and height of the level
have no boundary. Levels can grow "infinitely" to the right and downward
but no negative coordinates past the top or left edge.
* **Unbounded** allows for "infinite" sized maps that give unlimited room to
grow your level. The wallpaper on this level type only uses the "tiling"
pattern, so notebook-themed levels won't show the top/left decorations.
* **Bounded** is the default. The camera won't scroll past the top-left corner of the page (0,0), and the level size is capped to 2550x3300, or the approximate size of an 11:9 standard sheet of notebook paper in pixels. You can adjust the boundary size later if you need more room!
* **No Negative Space** is like Bounded, but the width and height of the level have no boundary. Levels can grow "infinitely" to the right and downward but no negative coordinates past the top or left edge.
* **Unbounded** allows for "infinite" sized maps that give unlimited room to grow your level. The wallpaper on this level type only uses the "tiling" pattern, so notebook-themed levels won't show the top/left decorations.
You can change these settings later if you change your mind.
@ -35,44 +24,24 @@ You can change these settings later if you change your mind.
![Wallpaper options on New Level](../images/palettes.png)
The wallpaper affects the "theme" of your level. Sketchy Maze is themed around
hand-drawn mazes on paper, so the built-in themes look like various kinds of
paper.
The wallpaper affects the "theme" of your level. Sketchy Maze is themed around hand-drawn mazes on paper, so the built-in themes look like various kinds of paper.
* **Notebook** looks like standard ruled notebook paper. It's a white paper with
blue horizontal lines, a single red vertical line down the left, and a wide
margin on the top and left edges.
* **Legal Pad** looks like ruled yellow legal pad. It's similar to Notebook but
has yellow paper and a second vertical red line down the left.
* **Graph paper** `new in v0.6.0` is a white paper with a repeating grid pattern
of light-grey lines about 32px each; a darker dotted gray grid every 3x3 units;
and a teal grid every 6x6 units. A light version of Blueprint.
* **Dotted paper** `new in v0.6.0` is a white page with a repeating pattern of
single dots every 32 pixels apart. Most dots are light blue but with a grid of
red dots every 6x6 units. It has the same grid spacing as the Graph paper.
* **Blueprint** is a dark blueprint paper background with a repeating grid pattern.
A dark version of Graph paper; you'll want to pair it with the **Blueprint Palette**
which has light colors for level geometry by default.
* **Pure White** is a blank, white (#FFFFFE) background color with nothing going
on except for what you draw on your level.
* **Custom wallpaper...** lets you use your own wallpaper image. See
[Custom Wallpaper](custom-wallpaper.md).
* **Notebook** looks like standard ruled notebook paper. It's a white paper with blue horizontal lines, a single red vertical line down the left, and a wide margin on the top and left edges.
* **Legal Pad** looks like ruled yellow legal pad. It's similar to Notebook but has yellow paper and a second vertical red line down the left.
* **Graph paper** `new in v0.6.0` is a white paper with a repeating grid pattern of light-grey lines about 32px each; a darker dotted gray grid every 3x3 units; and a teal grid every 6x6 units. A light version of Blueprint.
* **Dotted paper** `new in v0.6.0` is a white page with a repeating pattern of single dots every 32 pixels apart. Most dots are light blue but with a grid of red dots every 6x6 units. It has the same grid spacing as the Graph paper.
* **Blueprint** is a dark blueprint paper background with a repeating grid pattern. A dark version of Graph paper; you'll want to pair it with the **Blueprint Palette** which has light colors for level geometry by default.
* **Pure White** is a blank, white (#FFFFFE) background color with nothing going on except for what you draw on your level.
* **Custom wallpaper...** lets you use your own wallpaper image. See [Custom Wallpaper](custom-wallpaper.md).
The decorations of the wallpaper vary based on the Page Type. For example, the
Notebook and Legal Pad have extra padding on the top of the page and red lines
going down just the left side, and the rest of the level uses the repeating blue
lines pattern. The page types and their effect on the wallpapers are:
The decorations of the wallpaper vary based on the Page Type. For example, the Notebook and Legal Pad have extra padding on the top of the page and red lines going down just the left side, and the rest of the level uses the repeating blue lines pattern. The page types and their effect on the wallpapers are:
* **Bounded** and **No Negative Space** will show the decorations for the top
and left edges of the page, as these levels are bounded on their top/left
corner.
* **Unbounded** levels only use the repeating tiled pattern across the entire
level, because there is no top-left boundary to anchor those decorations to.
* **Bounded** and **No Negative Space** will show the decorations for the top and left edges of the page, as these levels are bounded on their top/left corner.
* **Unbounded** levels only use the repeating tiled pattern across the entire level, because there is no top-left boundary to anchor those decorations to.
### Default Palette
When starting a **new** level, you may choose a default Palette to start out
with. The available options as of **version 0.6.0** are:
When starting a **new** level, you may choose a default Palette to start out with. The available options as of **version 0.10.0** are:
* **Default:** the classic palette from previous alpha game releases.
1. **solid**: black, solid geometry
@ -81,12 +50,14 @@ with. The available options as of **version 0.6.0** are:
4. **water**: blue, water
5. **hint**: pink
* **Colored Pencil:** a new palette with some more varied default colors.
1. **grass**: green, solid geometry
2. **dirt**: brown, solid
3. **stone**: dark grey, solid
4. **fire**: red, fire
5. **water**: light blue (#0099FF), water
6. **hint**: pink
1. **darkstone**: dark grey, solid geometry
2. **grass**: green, solid
3. **dirt**: brown, solid
4. **stone**: grey, solid
5. **sandstone**: orangey, solid
6. **fire**: red, fire
7. **water**: light blue (#0099FF), water
8. **hint**: pink
* **Blueprint:** the classic palette for levels with the Blueprint wallpaper:
1. **solid**: white, solid
2. **decoration:** light grey
@ -95,268 +66,166 @@ with. The available options as of **version 0.6.0** are:
5. **electric**: yellow, solid
6. **hint**: pink
In earlier alpha versions of the game, the Blueprint palette was chosen by
default when the level starts out with the Blueprint wallpaper, which has a
very dark background color and Blueprint was basically a bright version of
the Default palette. As of v0.6.0, the user can select the palette separately
from the wallpaper.
In earlier alpha versions of the game, the Blueprint palette was chosen by default when the level starts out with the Blueprint wallpaper, which has a very dark background color and Blueprint was basically a bright version of the Default palette. As of v0.6.0, the user can select the palette separately from the wallpaper.
If you're using the Blueprint wallpaper, pick the Colored Pencil or Blueprint
palettes for best results: the default black color for level geometry won't
show well on the Blueprint wallpaper!
If you're using the Blueprint wallpaper, pick the Colored Pencil or Blueprint palettes for best results: the default black color for level geometry won't show well on the Blueprint wallpaper!
### Title and Author
After you start editing your level, access the "Level -> Level
Properties" menu to reopen the level settings and you will find the
options to edit the Title of your level and change the Author name
if you like. The default author copies your OS username.
After you start editing your level, access the "Level -> Level Properties" menu to reopen the level settings and you will find the options to edit the Title of your level and change the Author name if you like. The default author copies your OS username.
### Game Rules
Opening the "Level -> Level Properties" window from the editor, the Game Rules can be customized for your level and can tweak some of the gameplay behaviors to allow for some more interesting maps.
The current game rules available include:
#### Difficulty Setting
The default level difficulty is Normal but you can also set your level's difficulty to the Peaceful or Hard options:
* On Peaceful mode, enemy mobs will generally ignore the player character entirely and do not attack.
* On Hard mode, enemy mobs become more aggressive. For example, the Azulians will have an infinite aggro radius and will come at the player character no matter how far away you are.
Specific behaviors of enemies are up to their programming. Doodad scripts can query the `Level.Difficulty` value and react accordingly.
#### Survival Mode
On levels where player death is all but guaranteed (e.g. a Hard Mode, [Azulian Tag](../story-mode.md#azulian-tag)) map) the Survival Mode setting will invert the definition of "high score" for the silver tier in Story Mode.
Normally, the high score is rewarded to the fastest time to complete a level. If the player dies and respawns from checkpoint, they get a silver medal and if they make it to the Exit Flag unscathed they get a gold medal. For Survival levels, the level is completed if the player dies but they are rewarded for _how long_ they survived rather than how quickly they died. The gold medal for Survival levels is still based on how quickly they beat the level.
See [Azulian Tag](../story-mode.md#azulian-tag) for more details.
## Editor Interface
![Level Editor View](../images/newlevel-2.png)
This is the level editor. You can click and drag on the blank page and begin
drawing a level. The toolbar down the left has various drawing tools: Pencil
(freehand), Line, Rectangle, Ellipse. The toolbar down the right is your level
palette. You can mouse-over most buttons and see an immediate tooltip appear
that describes what it is.
This is the level editor. You can click and drag on the blank page and begin drawing a level. The toolbar down the left has various drawing tools: Pencil (freehand), Line, Rectangle, Ellipse. The toolbar down the right is your level palette. You can mouse-over most buttons and see an immediate tooltip appear that describes what it is.
Quick 5-second overview of the editor interface:
* The top of the window has your [**Menu Bar**](#menu-bar), a common sight on desktop applications.
* The panel on the left side of the window is your **Tool Box**. Clicking these
buttons activates a specific drawing tool or mode:
* <img src="../images/sprites/pencil-tool.png" width="16" height="16">
**Pencil Tool** lets you click, drag, and draw pixels of your selected
Palette color onto your level freehand. Shortcut key: `f`
* <img src="../images/sprites/line-tool.png" width="16" height="16">
**Line Tool** lets you easily draw a straight line between two points. Click
in your level where you want the first point to be, and drag your mouse to
the second point. Release the mouse to commit the line to your drawing.
Shortcut key: `l`
* <img src="../images/sprites/rect-tool.png" width="16" height="16">
**Rectangle Tool** lets you easily draw rectangles on your level. Shortcut: `r`
* <img src="../images/sprites/ellipse-tool.png" width="16" height="16">
**Ellipse Tool** lets you draw circles or elliptical shapes. Shortcut: `c`
* <img src="../images/sprites/actor-tool.png" width="16" height="16">
**Doodad Tool** lets you drag doodads such as buttons and doors onto your
level. See the [Doodad Tool](#doodad-tool) below. Shortcut: `d`
* <img src="../images/sprites/link-tool.png" width="16" height="16">
**Link Tool** lets you link doodads together so that they can interact off
each other. For example, a Button connected to an Electric Door will cause
the door to open and close when the button is pressed. See [Link Tool](#link-tool)
below.
* <img src="../images/sprites/eraser-tool.png" width="16" height="16">
**Eraser Tool** cleans up your mistakes. Click and drag over pixels you've
drawn to delete the pixels from your level. Shortcut: `x`
* The **Size:** label on the left controls the brush size of your current drawing
tool. This translates to the line thickness, or how big your pixels are when
drawn into the level. Click the + and - buttons to increase or decrease the
brush size, and draw thicker or thinner lines.
* The panel on the right side of the window is your **Palette** of colors to
draw with. Mouse over a color to see its name and properties -- different
colors may mean different things!
* The **Edit** button will open the Palette Editor where you can change a
color, rename it, and set its properties. See [Color Attributes](#color-attributes)
* The panel on the left side of the window is your **Tool Box**. Clicking these buttons activates a specific drawing tool or mode:
* ![](../images/sprites/pan-tool.png) **Pan Tool** lets you scroll the level viewport by clicking and dragging. Ideal for mobile where you rely on a touch screen and don't want to accidentally draw onto your level! Middle-click and two-finger swipe gestures can also scroll the level viewport at all times.
* ![](../images/sprites/pencil-tool.png) **Pencil Tool** lets you click, drag, and draw pixels of your selected Palette color onto your level freehand. Shortcut key: `f`
* ![](../images/sprites/line-tool.png) **Line Tool** lets you easily draw a straight line between two points. Click in your level where you want the first point to be, and drag your mouse to the second point. Release the mouse to commit the line to your drawing. Shortcut key: `l`
* ![](../images/sprites/rect-tool.png) **Rectangle Tool** lets you easily draw rectangles on your level. Shortcut: `r`
* ![](../images/sprites/ellipse-tool.png) **Ellipse Tool** lets you draw circles or elliptical shapes. Shortcut: `c`
* ![](../images/sprites/text-tool.png) **Text Tool** lets you stamp text messages onto your level. You can choose between the game's built-in fonts (including the Azulian font) and set the size and color from your palette.
* ![](../images/sprites/flood-tool.png) **Flood Tool** (or 'paint bucket tool') can easily replace a contiguous area of your drawing from one color to another.
* ![](../images/sprites/eraser-tool.png) **Eraser Tool** cleans up your mistakes. Click and drag over pixels you've drawn to delete the pixels from your level. Shortcut: `x`
* ![](../images/sprites/actor-tool.png) **Doodad Tool** lets you drag doodads such as buttons and doors onto your level. See the [Doodad Tool](#doodad-tool) below. Shortcut: `q`
* ![](../images/sprites/link-tool.png) **Link Tool** lets you link doodads together so that they can interact off each other. For example, a Button connected to an Electric Door will cause the door to open and close when the button is pressed. See [Link Tool](#link-tool) below.
* The **Size:** label on the left controls the brush size of your current drawing tool. This translates to the line thickness, or how big your pixels are when drawn into the level. Click the + and - buttons to increase or decrease the brush size, and draw thicker or thinner lines.
* The panel on the right side of the window is your **Palette** of colors to draw with. Mouse over a color to see its name and properties -- different colors may mean different things!
* The **Edit** button will open the Palette Editor where you can change a color, rename it, and set its properties. See [Color Attributes](#color-attributes)
---
* * *
## Doodad Tool
When clicking on the <img src="../images/sprites/actor-tool.png" width="16" height="16"> **Doodad Tool** or
pressing the `d` key, the Doodads window will appear in the level editor:
When clicking on the ![](../images/sprites/actor-tool.png) **Doodad Tool** or pressing the `q` key, the Doodads window will appear in the level editor:
![Doodads window](../images/doodads.png)
Doodads are objects you drag and drop into your level to add interactive elements
such as enemies and buttons. Mousing over a doodad will tell you its name, and
the pager buttons at the bottom can show more options. See the
[list of built-in doodads](../doodads.md) for details on what each one does.
Doodads are objects you drag and drop into your level to add interactive elements such as enemies and buttons. Mousing over a doodad will tell you its name, and the pager buttons at the bottom can show more options. See the [list of built-in doodads](../doodads.md) for details on what each one does.
Click and drag a doodad from the Doodads window onto your level to place it.
While the **Doodad Tool** is active on the left toolbar, when you mouse over an
existing doodad on your level, and orange box will appear around it. You may
click and drag to move this doodad somewhere else. Right-click it to remove it
from your level.
While the **Doodad Tool** is active on the left toolbar, when you mouse over an existing doodad on your level, and orange box will appear around it. You may click and drag to move this doodad somewhere else. Right-click it to remove it from your level.
* Left click: **move a doodad** somewhere else on your level.
* Right click: **removes the doodad** from your level.
Doodads provide various useful features to your level:
* **Keys and Locked Doors** let you place collectible keys around the level which,
when obtained, allow the player to permanently unlock doors of the same color
and open new paths on the level. There are four pairs of keys and doors.
* **Buttons and Switches** let you open and close **Electric Doors** and trigger
other devices to which they are linked.
* **Trapdoors** provide one-way gates; once the door has swung shut, it can not
be entered from the wrong side!
* **Keys and Locked Doors** let you place collectible keys around the level which, when obtained, allow the player to permanently unlock doors of the same color and open new paths on the level. There are four pairs of keys and doors.
* **Buttons and Switches** let you open and close **Electric Doors** and trigger other devices to which they are linked.
* **Trapdoors** provide one-way gates; once the door has swung shut, it can not be entered from the wrong side!
To connect buttons to control doors, use the
<img src="../images/sprites/link-tool.png" width="16" height="16"> **Link Tool.**
To connect buttons to control doors, use the ![](../images/sprites/link-tool.png) **Link Tool.**
### Doodad/Actor Runtime Options
**New in v0.13.1**
Some doodads have configurable options you can set on each instance ("actor") of the doodad placed in your level. For example, the Locked Doors have an option to mark them "unlocked" at level start, so that their key isn't required and they can be used for cosmetic purposes.
With the Actor Tool selected, mouse over a doodad on your level and look for the gear icon in the corner. Clicking it will open the Actor Properties window, which shows metadata about the actor and the Options tab may have some options you can configure.
### How do I remove a doodad from my level?
Select the <img src="../images/sprites/actor-tool.png" width="16" height="16"> **Doodad Tool**
to adjust the doodads already on your level.
Select the ![](../images/sprites/actor-tool.png) **Doodad Tool** to adjust the doodads already on your level.
To remove a doodad: either **right-click on it** or else drag it from your level
back into the Doodads window and release, and it will be gone from your level.
To remove a doodad: either **right-click on it** or else drag it from your level back into the Doodads window and release, and it will be gone from your level.
## Link Tool
The <img src="../images/sprites/link-tool.png" width="16" height="16"> **Link Tool**
allows you to pair two doodads on your level together. This allows the doodads
to communicate events with each other, for example, so a button can open an
electric door when pressed.
The ![](../images/sprites/link-tool.png) **Link Tool** allows you to pair two doodads on your level together. This allows the doodads to communicate events with each other, for example, so a button can open an electric door when pressed.
![Link Tool](../images/link-tool.png)
This screenshot shows several buttons and switches that are linked to several
electric doors. With the Link Tool selected, mouse over a doodad on your level
and a magenta box appears around it. Click on it, and then click on the other
doodad to pair it to. A glowing magenta line will connect the two doodads
together from then on, showing their connection.
This screenshot shows several buttons and switches that are linked to several electric doors. With the Link Tool selected, mouse over a doodad on your level and a magenta box appears around it. Click on it, and then click on the other doodad to pair it to. A glowing magenta line will connect the two doodads together from then on, showing their connection.
To disconnect a link between two doodads, click on the two of them again with
the Link Tool - or delete and replace one of them.
To disconnect a link between two doodads, click on the two of them again with the Link Tool - or delete and replace one of them.
Linked doodads are able to send small messages to their linked partners when
events happen to _them_. For example, when the player character steps on a button
it sends a "power on" signal to the door it's connected to, and the door opens.
When the button is released, it sends a "power off" signal and the door closes.
Linked doodads are able to send small messages to their linked partners when events happen to _them_. For example, when the player character steps on a button it sends a "power on" signal to the door it's connected to, and the door opens. When the button is released, it sends a "power off" signal and the door closes.
See the [Doodads](../doodads.md) page for a description of the game's built-in
doodads and how they interact with each other.
See the [Doodads](../doodads.md) page for a description of the game's built-in doodads and how they interact with each other.
---
* * *
## Giant Screenshot
From the level editor it is possible to create a "Giant Screenshot" of
your whole entire level and save it as a PNG image. Access this feature
by clicking on the "Level->Giant screenshot" menu of the editor.
From the level editor it is possible to create a "Giant Screenshot" of your whole entire level and save it as a PNG image. Access this feature by clicking on the "Level->Giant screenshot" menu of the editor.
Screenshots are saved in your [profile directory](../profile-directory.md)
in the 'screenshots' folder; there is a shortcut in the Level menu
to open the screenshots folder in your file browser.
Screenshots are saved in your [profile directory](../profile-directory.md) in the 'screenshots' folder; there is a shortcut in the Level menu to open the screenshots folder in your file browser.
---
* * *
## Palette Editor
![Screenshot of the Level Palette editor](../images/palette.png)
The Palette is the set of colors that you draw your actual level with. In your
default palette, some colors are designated as "solid" and will be used for the
walls and floors of your level, while others may be "fire" or "water" or just
decoration (not colliding with the player characters).
The Palette is the set of colors that you draw your actual level with. In your default palette, some colors are designated as "solid" and will be used for the walls and floors of your level, while others may be "fire" or "water" or just decoration (not colliding with the player characters).
You may edit or extend the palette to your liking. By Clicking the "Tools" menu
and "Edit Palette", or clicking the "Edit" button on the palette toolbar on the
right side of the screen, you will open the Palette Editor.
You may edit or extend the palette to your liking. By Clicking the "Tools" menu and "Edit Palette", or clicking the "Edit" button on the palette toolbar on the right side of the screen, you will open the Palette Editor.
Levels are designed to have a limited color palette, and this is your selection
of colors for the level or doodad you're drawing. You can click on "Add Color"
to create more rows as needed. There isn't a maximum bounds on number of distinct
colors, however, the user interface will not accommodate too many of them. This
game is themed around "hand-drawn maps on paper" and pretend each color is a pen
or marker and how many distinct colors do you need?
Levels are designed to have a limited color palette, and this is your selection of colors for the level or doodad you're drawing. You can click on "Add Color" to create more rows as needed. There isn't a maximum bounds on number of distinct colors, however, the user interface will not accommodate too many of them. This game is themed around "hand-drawn maps on paper" and pretend each color is a pen or marker and how many distinct colors do you need?
> **NOTICE:** Modifying the color of an existing swatch on your Palette will also
> change any pixels _already on your level_ to the new color. Drawings in this
> game use an indexed palette, similar to GIF and some PNG images!
> **NOTICE:** Modifying the color of an existing swatch on your Palette will also change any pixels _already on your level_ to the new color. Drawings in this game use an indexed palette, similar to GIF and some PNG images!
### Brush Patterns
A color swatch on your palette may have a Brush Pattern (labeled "Tex") applied
to it which will vary the look of your color once drawn onto your level. For
example, instead of a red color drawing on as solid red pixels, it can take on
a more noisy pattern resembling colored pencil graphite or marker.
A color swatch on your palette may have a Brush Pattern (labeled "Tex") applied to it which will vary the look of your color once drawn onto your level. For example, instead of a red color drawing on as solid red pixels, it can take on a more noisy pattern resembling colored pencil graphite or marker.
![Screenshot showing various brush patterns](../images/patterns.png)
The pattern when drawn onto your level is a cosmetic-only effect: you can change
the pattern after the fact, or remove the pattern altogether, and your level
immediately updates.
The pattern when drawn onto your level is a cosmetic-only effect: you can change the pattern after the fact, or remove the pattern altogether, and your level immediately updates.
In the future, you will be able to add your own custom pattern images but for
now there are a handful of built-in options to choose from.
In the future, you will be able to add your own custom pattern images but for now there are a handful of built-in options to choose from.
### Color Attributes
The **Attributes** column toggles behaviors on or off for this color. In the default
color palette, black pixels make up your **solid** level geometry, red pixels are
**fire**, and blue pixels are **water**.
The **Attributes** column toggles behaviors on or off for this color. In the default color palette, black pixels make up your **solid** level geometry, red pixels are **fire**, and blue pixels are **water**.
By default the color will be purely decorative, not physically colliding with the
player or affecting them in any way.
By default the color will be purely decorative, not physically colliding with the player or affecting them in any way.
The attributes and their meanings are:
* **Solid**: the player character and other mobile doodads will collide against
pixels drawn in this color. Useful for your level geometry.
* **Solid**: the player character and other mobile doodads will collide against pixels drawn in this color. Useful for your level geometry.
* **Fire**: if the player touches pixels of this color, they die!
* **Water**: will act like water, currently it just draws the player blue.
### Changing Colors
Clicking on the colored square will prompt you to enter a new color in
hexadecimal notation, like `#FF00FF` for <span style="color: #FF00FF">magenta</span>
or `#0099FF` for <span style="color: #0099FF">light blue</span>. Colors can
be entered in the following formats (the # prefix is actually optional):
Clicking on the colored square will prompt you to enter a new color in hexadecimal notation, like `#FF00FF` for magenta or `#0099FF` for light blue. Colors can be entered in the following formats (the # prefix is actually optional):
* 3-digit hexadecimal: `#F0F` or `#09F`
* 6-digit hexadecimal: `#0099FF` or `#FC390E`
* 8-digit RGBA: `#0000FF99` - a color with semi-transparency!
You can set the color to be **semi-transparent** by providing the 8-digit RGBA
color code; the extra two digits control the transparency between 00 (fully
invisible) and FF (fully opaque).
You can set the color to be **semi-transparent** by providing the 8-digit RGBA color code; the extra two digits control the transparency between 00 (fully invisible) and FF (fully opaque).
![Enter an RGBA color value for see-thru colors](../images/palette-rgba.png)
---
## Menu Bar
While editing a level or doodad, a Menu Bar appears at the top of the screen.
Its options include:
* **File**
* New level (Ctrl-N)
* New doodad
* Save (Ctrl-S)
* Save as...
* Publish level (attach custom doodads for easy sharing)
* Open... (Ctrl-O)
* Close level
* Quit (Escape)
* **Edit**
* Undo (Ctrl-Z)
* Redo (Ctrl-Y)
* Settings
* **Level** _(only when editing a level)_
* Level Properties
* Attached files
* Playtest (P)
* **Doodad** _(only when editing a doodad)_
* Doodad Properties
* Layers
* **Tools**
* Debug overlay (F3)
* Command shell (Enter)
* Edit Palette
* Pencil Tool (f)
* Line Tool (L)
* Rectangle Tool (r)
* Ellipse Tool (c)
* Eraser Tool (x)
* Doodads (d)
* Link Tool
* **Help**
* User Manual (F1)
* Register
* About

View File

@ -0,0 +1,126 @@
# Level Packs
Level Packs are collections of levels that are played in series. The game ships with a couple built-in level packs, but you can also create your own! Level Packs are selectable under the "Story Mode" option from the game's main menu.
![Screenshot of Level Packs window](../images/levelpack.png)
While you can just create some [custom levels](index.md) one at a time and share them with your friends, with a Level Pack you can group a bunch of levels together that play one after another. Use them to tell a story or just group similar styles of level together.
## Features of Level Packs
Gameplay:
* The **Story Mode** screen presents a UI to browse level packs and select a level.
* Upon winning a level, a "Next Level" button appears that automatically advances to the next level of the pack. Pressing the Return key works too.
* A level pack may "lock" some of its levels until the player completes earlier levels. Each level completed will unlock the next. A level pack can define the number of unlocked levels to start with (or have them all unlocked).
Custom doodads:
* (In the future) A level pack can hold a folder of custom doodads that will be used by its levels. Instead of each level needing to [publish](publishing.md) (embed) its doodads individually, the level pack holds onto them so multiple levels can use them while saving on disk space!
* **Note:** [Free (shareware)](../register.md) versions of the game fully support custom Level Packs, but they don't support embedded custom doodads. Level Packs that use only the built-in doodads work perfectly, and in case you're using custom doodads, the player may manually install the custom doodads in their [profile directory](../profile-directory.md) and play it that way.
## Structure of a Level Pack
A levelpack is basically a ZIP file that contains levels, doodads, and an index.json that describes the level pack. To create a levelpack by hand, just create a correctly formatted ZIP file and rename the .zip extension to .levelpack. See [Creating a Level Pack](#creating-a-level-pack), below: the doodad tool makes this much easier!
The contents of a .levelpack ZIP archive are like follows:
levels/
First.level
Second.level
Third.level
doodads/
Example.doodad
index.json
The `levels` folder holds your .level files and the `doodads` folder holds custom .doodad files. The doodads folder is optional and doesn't need to be included if there are no custom doodads.
The index.json file describes the levelpack. At time of writing it is structured like the following:
{
"Title": "Tutorial",
"description": "Learn how to play the game.",
"author": "Noah P",
"created": "2021-12-27T04:45:29.186345525Z",
"levels": [
{
"title": "Lesson 1: Controls",
"author": "Noah P",
"filename": "Tutorial 1.level"
},
{
"title": "Lesson 2: Keys & Doors",
"author": "Noah P",
"filename": "Tutorial 2.level"
},
{
"title": "Lesson 3: Gizmos and Doodads",
"author": "Noah P",
"filename": "Tutorial 3.level"
}
],
"freeLevels": 0
}
The `levels` array describes the levels and their sort order. It is possible for .level files to exist in the levelpack which _are not_ described in the index.json; these levels will not be reachable in-game but in the future this may support hiding bonus levels linked to by other levels in the pack.
**TO DO:** the game does not yet do anything with the `doodads` folder. In the future, this folder will help a group of levels embed a custom doodad _once_ in the levelpack instead of each keeping a separate copy.
## Creating a Level Pack
The easiest way to create a .levelpack file is with the [doodad tool](../doodad-tool.md) that shipped with the game.
If you're using Windows or are not very experienced with the command line, you may want to create a folder and copy all your .level files from your [profile directory](../profile-directory.md) into it, as well as copy the `doodad.exe` or `doodad` program into the folder too and open that folder in your terminal window.
Run `./doodad levelpack create --help` to see the options:
NAME:
doodad levelpack create - create a new .levelpack file from source files
USAGE:
doodad levelpack create [command options] <output.levelpack> <input.level> [input.level...]
OPTIONS:
--title value, -t value set a title for your levelpack, default will use the first level's title
--author value, -a value set an author for your levelpack, default will use the first level's author
--description value, -d value set a description for your levelpack
--free value, -f value set number of free levels (levels unlocked by default), 0 means all unlocked (default: 0)
--doodads value, -D value which doodads to embed: none, custom, all (default: "all")
--help, -h show help (default: false)
The general format will be like:
> doodad levelpack create OUTPUT.levelpack INPUT.level
Write the name of your .levelpack OUTPUT file first, then give it the names of all your .level files.
You can use the additional command-line options (--title, --description, etc.) to set the metadata on your level pack. If you don't provide any, the Title will copy your first level's Title and the Author will copy your first level's Author (which is usually your username by default).
Examples:
# Simple creation from a series of levels.
# The levelpack Title will be the title from First.level
# The levelpack Author will be the author from First.level
doodad levelpack create OUTPUT.levelpack First.level Second.level Third.level
# Provide metadata with the levelpack
doodad levelpack create --title "My First Level Pack" \
--author "Noah P" --description "Some of my first levels." \
OUTPUT.levelpack First.level Second.level Third.level
# Shorthand flags
doodad levelpack create -t "My First Level Pack" -a "Noah P" -d "Some of my first levels." \
OUTPUT.levelpack First.level Second.level Third.level
Place the resulting .levelpack file into your [profile directory](../profile-directory.md)'s "levelpacks" folder, and restart _Sketchy Maze_. Your levelpack should appear in the "Story Mode" menu!
## Open Levels in Editor
When playing a Story Mode level from a levelpack, the "Edit" button may be clicked to open the level in the Editor.
You are free to do this and learn from the levels you enjoy, and this won't harm the original levels at all! You can save a copy of the level, make changes to it and playtest your version of the level.

View File

@ -1,38 +1,36 @@
# Built-in Doodads
Sketchy Maze comes with several built-in doodads that you can use in your
levels. You may also [create your own](custom-doodads/index.md) custom doodads
and program them to do whatever you want!
Sketchy Maze comes with several built-in doodads that you can use in your levels. You may also [create your own](custom-doodads/index.md) custom doodads and program them to do whatever you want!
Doodads are available in the Level Editor by clicking on the
<img src="images/sprites/actor-tool.png" width="16" height="16"> **Doodad Tool**
and then dragging a doodad onto your level. See the [Doodad Tool](custom-levels/index.md#doodad-tool)
for more information.
Doodads are available in the Level Editor by clicking on the ![](images/sprites/actor-tool.png) **Doodad Tool** and then dragging a doodad onto your level. See the [Doodad Tool](custom-levels/index.md#doodad-tool) for more information.
**See also:** [Linked Doodads](linked-doodads.md) for how doodads interact when
linked together in your levels.
Some doodads have Options you can configure on a per-actor instance in your level. For example, Locked Doors can start unlocked by default, or Electric Doors may be opened by default when the level begins. These options will be described below on the doodads which have them.
**See also:** [Linked Doodads](linked-doodads.md) for how doodads interact when linked together in your levels.
* [Objects](#objects)
* [Start Flag](#start-flag) - Spawn point of a level
* [Checkpoint Flag](#checkpoint-flag) - **NEW in v0.8.0**
* [Checkpoint Flag](#checkpoint-flag)
* [Exit Flag](#exit-flag) - Goal of a level
* [Anvil](#anvil) - **NEW in v0.8.0**
* [Anvil](#anvil)
* [Box](#box)
* [Creatures](#creatures)
* [Boy](#boy) - The player character
* [Red Bird](#red-bird)
* [Blue Bird](#blue-bird) **NEW in v0.13.0**
* [Azulians](#azulians)
* [Thief](#thief) - **NEW in v0.8.0**
* [Thief](#thief)
* [Snake](#snake) - **NEW in v0.13.0**
* [Crusher](#crusher) - **NEW in v0.13.0**
* [Doors & Trapdoors](#doors-trapdoors)
* [Colored Locked Doors & Keys](#colored-locked-doors-keys)
* [Small Key Doors](#small-key-doors)
* [Gems & Totems](#gems-totems) - **NEW in v0.13.0**
* [Warp Doors](#warp-doors)
* [Trapdoors](#trapdoors)
* [Electric Door](#electric-door)
* [Electric Trapdoor](#electric-trapdoor)
* [Crumbly Floor](#crumbly-floor)
* [Objects](#objects)
* [Box](#box)
* [Gizmos](#gizmos)
* [Buttons](#buttons)
* [Sticky Button](#sticky-button)
@ -45,10 +43,13 @@ linked together in your levels.
* [Goal Region](#goal-region)
* [Checkpoint Region](#checkpoint-region)
* [Fire Region](#fire-region)
* [Look At Me](#look-at-me) **NEW in v0.13.1**
* [Power Source](#power-source)
* [Stall Player](#stall-player)
* [Invisible Warp Door](#invisible-warp-door) - **NEW in v0.10.1**
* [Reset Timer](#reset-timer) **NEW in v0.12.0**
---
* * *
## Objects
@ -56,42 +57,33 @@ linked together in your levels.
![Start Flag](images/doodads/start-flag.png)
The **Start Flag** sets the player spawn point in your level. There should be
only one start flag per level.
The **Start Flag** sets the player spawn point in your level. There should be only one start flag per level.
Multiple Start Flags in one level is considered to be an error; a warning is
flashed on-screen and the player will spawn at the "first" start flag it found.
Multiple Start Flags in one level is considered to be an error; a warning is flashed on-screen and the player will spawn at the "first" start flag it found.
A level without a Start Flag will spawn the player at the 0,0 coordinate at
the top-left corner of the level, and flash an error about the missing Start
Flag.
A level without a Start Flag will spawn the player at the 0,0 coordinate at the top-left corner of the level, and flash an error about the missing Start Flag.
If the Start Flag is [linked](linked-doodads.md#start-flag) to another doodad
in your level, then that doodad will be used for the player character. For example,
linking a Start Flag to a Thief will use the Thief as the player character
for that level instead of the default character, [Boy](#boy).
If the Start Flag is [linked](linked-doodads.md#start-flag) to another doodad in your level, then that doodad will be used for the player character. For example, linking a Start Flag to a Thief will use the Thief as the player character for that level instead of the default character, [Boy](#boy).
![Link a doodad to the Start Flag to set the player character](images/start-flag-link.png)
### Checkpoint Flag
![Checkpoint Flag](images/doodads/checkpoint-flag.png)
The **Checkpoint Flag** records the player's position in the level each time
he reaches a checkpoint. Should they die during the level, the option to
"Retry from checkpoint" will teleport the player back to that location and
continue gameplay without resetting the level -- so you keep any keys you
have, unlocked doors remain unlocked, etc.
The **Checkpoint Flag** records the player's position in the level each time they reach a checkpoint. Should they die during the level, the option to "Retry from checkpoint" will teleport the player back to that location and continue gameplay without resetting the level -- so you keep any keys you have, unlocked doors remain unlocked, etc.
The default checkpoint location is at the Start Flag, and crossing Checkpoint
Flags updates it to the last flag touched. When a second checkpoint is touched,
the previous checkpoint flags are reset and the player's spawn point is the
checkpoint they most recently touched.
The default checkpoint location is at the Start Flag, and crossing Checkpoint Flags updates it to the last flag touched. When a second checkpoint is touched, the previous checkpoint flags are reset and the player's spawn point is the checkpoint they most recently touched.
**New in v0.11.0:** if you link a doodad to a Checkpoint Flag, the player character will be replaced with that doodad when the flag is activated!
![Link a doodad to the Checkpoint Flag](images/checkpoint-link.png)
### Exit Flag
![Exit Flag](images/doodads/exit-flag.png)
The **Exit Flag** sets a goal point for the level. The player must touch this
flag to win the level.
The **Exit Flag** sets a goal point for the level. The player must touch this flag to win the level.
### Anvil
@ -99,122 +91,114 @@ flag to win the level.
The **Anvil** is a "harmless" object that becomes dangerous when it is falling.
It has no collision and is affected by gravity; when falling, it is dangerous
to any **mobile** doodad that it encounters, including the player character.
Being hit by it will fail the level with "Watch out for falling anvils!" and
you can retry from your last checkpoint. It destroys other mobile doodads that
it lands on, removing them from the level.
It has no collision and is affected by gravity; when falling, it is dangerous to any mobile doodad that it encounters, including the player character. Being hit by it will fail the level with "Watch out for falling anvils!" and you can retry from your last checkpoint. It destroys other mobile doodads that it lands on, removing them from the level.
If it receives a **power** signal (from a [linked](linked-doodads.md#buttons)
Button or Switch), the Anvil will reset to its original location on the level,
making "reset buttons" possible for puzzle levels.
If it receives a **power** signal (from a [linked](linked-doodads.md#buttons) Button or Switch), the Anvil will reset to its original location on the level, making "reset buttons" possible for puzzle levels.
**New in v0.11.0:** the Anvil is invulnerable. This means that if the player character _is_ an Anvil, it can jump on and crush other enemies but can't be damaged by enemies or by fire pixels. Anvils also will not destroy invulnerable characters such as other Anvils.
### Box
![Box](images/doodads/box.gif)
The **Box** is a pushable object. If the player or another mobile doodad touches
the box from the side, the box will move at a fixed speed. It can be pushed up
and down slopes and it is affected by gravity.
The **Box** is a pushable object. If the player or another mobile doodad touches the box from the side, the box will move at a fixed speed. It can be pushed up and down slopes and it is affected by gravity.
The box is taller than [Boy](#boy) and so can make a useful platform to jump on top of
to reach a higher ledge.
The box is taller than [Boy](#boy) and so can make a useful platform to jump on top of to reach a higher ledge.
Boxes can be pushed by enemies too, but it gets dicey with multiple enemies
pushing simultaneously. Boxes can be stacked on top of each other, but sometimes
Boy will get "stuck" standing on top of the pile. If this happens, use the
[cheat code](hacking.md#cheat-codes) `ghost mode` to get yourself unstuck.
Boxes can be pushed by enemies too, but it gets dicey with multiple enemies pushing simultaneously. Boxes can be stacked on top of each other, but sometimes Boy will get "stuck" standing on top of the pile. If this happens, use the [cheat code](hacking.md#cheat-codes) `ghost mode` to get yourself unstuck.
**New in v0.8.0:**
If it receives a **power** signal (from a [linked](linked-doodads.md#buttons)
Button or Switch), the Anvil will reset to its original location on the level,
making "reset buttons" possible for puzzle levels.
If it receives a **power** signal (from a [linked](linked-doodads.md#buttons) Button or Switch), the Box will reset to its original location on the level, making "reset buttons" possible for puzzle levels.
---
* * *
# Creatures
## Creatures
### Boy
![Boy](images/doodads/boy.gif)
**Boy** is the player character.
The **Boy** is the default player character.
If he touches a "fire" pixel, he dies! You get a message like "Watch out for fire!"
and it doesn't even have to say "fire" - it'll use the color's name.
If he touches a "fire" pixel, he dies! You get a message like "Watch out for fire!" and it doesn't even have to say "fire" - it'll use the color's name.
If he touches water he'll turn blue. Swimming physics aren't hooked up yet!
The player character can be substituted on a custom map by linking another doodad to the Start Flag.
### Red Bird
![Bird](images/doodads/bird.gif)
The **Bird** is a simple creature which flies left and right across your level,
changing direction when it encounters an obstacle.
The **Bird** is a simple creature which flies left and right across your level, changing direction when it encounters an obstacle.
The bird has solid collision on its top side, so the player can ride on it
across the level. It's very slippery, though!
The Bird is hostile towards players who are affected by gravity, and will dive bomb if they see a shot they can take (if you are spotted 45 degrees below the direction the Bird is flying). The Bird is dangerous while it is dive bombing. If it misses and hits the ground, it will fly back up to its original elevation.
In the future, the bird will dive-bomb the player character in a diagonal
trajectory when it sees a shot it can take. This will harm the player if the
bird hits. If the bird hits the player, or misses and touches the ground, it
will fly back up to its original altitude and continue its A.I. program of
flying back and forth and searching for the player. It will also be easier to
ride more reliably.
The Bird can not pick up any items (such as keys) unless it is controlled by the player character. You can play as the Bird in a custom map by linking it to the Start Flag or a Checkpoint Flag. When under the player's control, you can dive by moving diagonally downwards and you can kill mobile doodads (such as the Azulians) by diving into them. Watch out! They can get you too if they touch you while you're _not_ diving!
Currently, however, the bird is harmless and does not dive bomb the player.
The Bird's behavior can vary according to the level's Difficulty rule:
**New in v0.8.0:** the Bird no longer can pick up items such as keys, unless
controlled by the player character.
* Peaceful: the Bird will not attack any player and simply flies back and forth.
### Blue Bird
![Bird](images/doodads/bird-blue.gif)
The Blue bird flies in a sine wave pattern while idle and, like the Red Bird, will dive and attack player characters who can't fly, but with a larger aggro radius than the red bird.
### Azulians
![Red Azulian](images/doodads/red-azulian.gif)
![Blue Azulian](images/doodads/blue-azulian.gif) ![Red Azulian](images/doodads/red-azulian.gif) ![White Azulian](images/doodads/white-azulian.gif)
The **Red Azulian** was the first test mobile character, and the
**Blue Azulian** was originally the player character in very early builds of
the game.
The **Azulians** are hostile mobs and come in three varieties. The Blue Azulian walks the slowest and has the shortest jump height and on the other end of the spectrum, the White Azulian is the fastest and can jump the highest.
The Azulians' A.I., when placed in your level, is that they walk right and
left across the ground, changing directions when hitting an obstacle. They
can pick up keys, unlock doors, and interact with buttons and switches that
they walk onto - basically all the capabilities as the player character.
The blue Azulian walks half as fast as the red one.
When the Azulians notice the player character they will begin to chase after them, and you'll fail the level if they get you! Azulians are friendly to other Azulians, and they don't attack the Thief either.
You can play as them in your custom levels by linking a Start Flag to
the Azulian.
When not chasing after the player, the Azulians simply walk back and forth and change direction when they encounter an obstacle. They can pick up keys, unlock doors, and interact with buttons and switches that they walk onto.
You can play as the Azulians in your custom levels by linking them to the Start Flag or to a Checkpoint Flag.
> Fun Trivia: the Red Azulian was the game's first test mobile character, and the Blue Azulian was originally a placeholder for the player character in early builds of the game.
The Azulian's behavior can very depending on the level's Difficulty rule:
* Peaceful: Azulians are passive to all players and simply walk back and forth.
* Hard: Azulians have an infinite aggro radius and will move towards the player character no matter how far away. They are hostile to _all_ player creatures, even if you are playing as an Azulian or a Thief.
### Thief
![Thief](images/doodads/thief.gif)
The **Thief** is a mobile character which can steal items from other doodads,
including the player character.
The **Thief** is a mobile character which can steal items from other doodads, including the player character.
The Thief's A.I. is to walk right and left, she can pick up items, unlock doors,
and activate most devices that it walks onto. When she encounters another
doodad (including the player), the Thief will **steal** any items they are
carrying:
The Thief's A.I. is to walk right and left, she can pick up items, unlock doors, and activate most devices that it walks onto. When she encounters another doodad (including the player), the Thief will **steal** any items they are carrying:
* For items which have no quantity, such as the Blue Key, the Thief will only
steal it if she does not already have one, letting the player keep the
key.
* Items with quantity are always stolen: the Thief will steal all your small
keys.
* For items which have no quantity, such as the Blue Key, the Thief will only steal it if she does not already have one, letting the player keep the key.
* Items with quantity are always stolen: the Thief will steal all your small keys.
* The A.I. Thief does **not** steal from other A.I. Thieves.
The player can play **as** the Thief by using the Link Tool and connecting
the Start Flag to a Thief. When controlled by the player character, the Thief
has special abilities compared to most other characters:
The player can play **as** the Thief by using the Link Tool and connecting the Start Flag to a Thief. When controlled by the player character, the Thief has special abilities compared to most other characters:
* You can steal items from other characters. When you contact another character
such as the Azulians, if they are holding any items, you'll automatically
steal them in the same way the Thief usually steals from you.
* You can steal items from other characters. When you contact another character such as the Azulians, if they are holding any items, you'll automatically steal them in the same way the Thief usually steals from you.
* The player character is immune to Thieves which will not steal from Thieves.
* The player character _can_, though, pilfer items that the other Thieves have
collected.
* The player character _can_, though, pilfer items that the other Thieves have collected.
---
### Snake
![Snake](images/doodads/snake.gif)
The **Snake** is a stationary enemy that always turns to face the player character. If you are near the snake and you jump, the Snake will also jump, hoping to catch you mid-air when you try and jump over!
If you are playing **as** the snake, you stay in your idle animation while moving laterally and play the jump animation when you jump. Snakes are friendly to other Snakes but will still jump along with you.
### Crusher
![Crusher](images/doodads/crusher.gif)
The **Crusher** is a trap that falls from above. It sleeps soundly until the player character approaches, and it will start peeking at you with one eye open. If you get below the Crusher, it will attempt to drop on top of you! It might also crush other mobile creatures who happen to get in the way.
If you play **as** the Crusher you can travel through the air freely with antigravity enabled. The Crusher will peek in the direction you're moving (right or left, or both!) and puts on the angry drop face if you are moving downwards.
* * *
## Doors & Trapdoors
@ -224,18 +208,11 @@ has special abilities compared to most other characters:
There are four pairs of **Colored Locked Doors and Keys** you can use on your level.
Colored doors are locked and behave as a solid wall until the player or another
mobile doodad "picks up" the Key of the same color. The doors may then be
permanently unlocked if the player walks into them while holding the key.
Colored doors are locked and behave as a solid wall until the player or another mobile doodad "picks up" the Key of the same color. The doors may then be permanently unlocked if the player walks into them while holding the key.
The **Colored Keys** are not consumed when used; with one key the player can
unlock many doors of the same color unless they lose the key. Currently there is
no method to lose keys except for the "drop all items" [cheat code](hacking.md#cheat-codes).
The **Colored Keys** are not consumed when used; with one key the player can unlock many doors of the same color unless they lose the key. Keys may be stolen by the [Thief](#thief) or by using the "drop all items" [cheat code](hacking.md#cheat-codes).
A locked door has a golden padlock over its sprite; after being unlocked, the
padlock is missing even while the door is closed. Should the player lose the keys
later, previously opened doors will remain unlocked but the player will need to
find another key to open more doors.
A locked door has a golden padlock over its sprite; after being unlocked, the padlock is missing even while the door is closed. Should the player lose the keys later, previously opened doors will remain unlocked but the player will need to find another key to open more doors.
![Red Key](images/doodads/red-key.png) ![Green Key](images/doodads/green-key.png) ![Yellow Key](images/doodads/yellow-key.png) ![Blue Key](images/doodads/blue-key.png)
@ -246,60 +223,87 @@ Each key/door pair also has a distinct shape for color-impaired players:
* **Yellow Key** (star)
* **Blue Key** (diamond)
**Actor Options:**
* `unlocked` - boolean - if this option is checked, the door will be "unlocked" by default when the level begins, not requiring a key to open.
* Keys: `gravity` - boolean - if this option is checked, the keys will be subject to gravity and be considered a 'mobile' doodad, able to activate buttons or trapdoors that it falls on.
### Small Key Doors
![Small Key Door](images/doodads/small-key-door.gif) ![Small Key](images/doodads/small-key.png)
**Small Key Doors** are doors which consume the **Small Key** when unlocked. The
player or other mobile doodad may carry several Small Keys and they can only
unlock as many Small Key Doors as the number of keys they hold.
**Small Key Doors** are doors which consume the **Small Key** when unlocked. The player or other mobile doodad may carry several Small Keys and they can only unlock as many Small Key Doors as the number of keys they hold.
The Small Key Door is permanently unlocked after unlocking it once. A golden
padlock appears on the door when it's locked, which disappears after unlocking.
The Small Key Door is permanently unlocked after unlocking it once. A golden padlock appears on the door when it's locked, which disappears after unlocking.
**Actor Options:**
* `unlocked` - boolean - if this option is checked, the door will be "unlocked" by default when the level begins, not requiring a key to open.
* Keys: `gravity` - boolean - if this option is checked, the keys will be subject to gravity and be considered a 'mobile' doodad, able to activate buttons or trapdoors that it falls on.
### Gems & Totems
![Totems](images/doodads/totem.png)
![Green Gemstone](images/doodads/gem-green.gif)  ![Blue Gemstone](images/doodads/gem-blue.gif)  ![Yellow Gemstone](images/doodads/gem-yellow.gif)  ![Red Gemstone](images/doodads/gem-red.gif)
Gemstones are collectible items which slot into Totems blocks. The player can carry many of the same gemstone at a time and a gemstone is consumed when its matching totem is activated.
The Totem emits a `power(true)` signal to linked doodads when it receives its gem stone. However, if the Totem is linked with _other_ Totems, it will not emit a power signal until _all_ of its linked Totems have their gem stones.
To set up a multi-totem lock that opens an Electric Door only when all the gems have been collected:
* Only one totem of the bunch needs to link to the Electric Door.
* That same totem also needs to link to each of the other totems.
You do not need to link every Totem to every Totem. Pick just one of your totems and link it to the Electric Door _and_ to all of the other totems, and it won't emit a power signal until itself and all its linked totems have gems.
![How to link multiple totems together](images/totem-links.png)
**Actor Options:**
* Totems: `has gemstone` - boolean - if this option is checked, the totem will already have its gemstone. This is for cosmetic purposes only -- do not Link the totem to anything, as it will not emit a power signal or inform linked totems that it has a gemstone.
* Gemstones: `gravity` - boolean - this is on by default and gemstones are affected by gravity. Turn it off to remove gravity, and they will behave as keys do by default.
### Warp Doors
![Warp Door](images/doodads/warp-door.gif)
The **Warp Door** allows the player character to fast travel between two remote
locations within the same level. The door is brown in color with a yellow "W"
symbol.
The **Warp Door** allows the player character to fast travel between two remote locations within the same level. The door is brown in color with a yellow "W" symbol.
To connect the doors together, drag two doors into your level and then use the
**Link Tool** to connect them. During gameplay, walk the player character to one
of the doors and press the Space Key to open it. The door will swing open and
shut and the player character exits from the other door.
To connect the doors together, drag two doors into your level and then use the **Link Tool** to connect them. During gameplay, walk the player character to one of the doors and press the Space Key to open it. The door will swing open and shut and the player character exits from the other door.
If a Warp Door is not linked to another door, a message will display indicating
that the door is "locked" and it can not be entered by the player.
If a Warp Door is not linked to another door, a message will display indicating that the door is "locked" and it can not be entered by the player.
**See also:** the [Blue & Orange Warp Doors](#blue-orange-warp-doors) tied to the
[State Blocks](#state-blocks).
**New in v0.10.1:** a Warp Door may only be opened by the player while the player is touching the ground (unless under the effects of antigravity, or while playing as the Bird). A door that is sufficiently up in the air requiring the player to jump or to fall past it can _not_ be opened by the player while in mid-air.
**Actor Options:**
* `locked (exit only)` - boolean - if this option is checked, the Warp Door can not be entered by the player; it will behave as a locked door, similarly to a door which has no linked exit. The door may still be exited from if another linked Warp Door sends the player there. You can make one-way Warp Doors by using this option.
**See also:** the [Blue & Orange Warp Doors](#blue-orange-warp-doors) tied to the [State Blocks](#state-blocks).
### Trapdoors
![Trapdoor](images/doodads/trapdoor-down.gif)
A **Trapdoor** is a one-way passage. If the player or other mobile doodad touches
the door from the "correct" side, the door will swing open. After the mobile
doodad has passed, the door will swing shut again.
A **Trapdoor** is a one-way passage. If the player or other mobile doodad touches the door from the "correct" side, the door will swing open. After the mobile doodad has passed, the door will swing shut again.
When the door is shut, you can not open it from the "wrong" side and it behaves
as a solid wall. If the door is open you may run in from the wrong side.
When the door is shut, you can not open it from the "wrong" side and it behaves as a solid wall. If the door is open you may run in from the wrong side.
Trapdoors come in four variants: downward-facing (default), rightward, leftward
and upwards.
Trapdoors come in four variants: downward-facing (default), rightward, leftward and upwards.
### Electric Door
![Electric Door](images/doodads/electric-door.gif)
The sci-fi **Electric Door** can only be opened when it receives a "power" signal
from a linked button or switch. See [Linked Doodads](custom-levels/index.md#link-tool).
The sci-fi **Electric Door** can only be opened when it receives a "power" signal from a linked button or switch. See [Linked Doodads](custom-levels/index.md#link-tool).
When the door receives a "power: on" signal it will open and allow passage to
the player or other mobile doodads. When it receives a "power: off" signal it
will close.
When the door receives a "power: on" signal it will open and allow passage to the player or other mobile doodads. When it receives a "power: off" signal it will close.
**Actor Options:**
* `opened` - boolean - if this option is checked, the Electric Door will be opened (powered) by default when the level begins. A switch may toggle it closed, or if it receives and then loses power, it will close as normal.
### Electric Trapdoor
@ -307,28 +311,25 @@ will close.
The **Electric Trapdoor** requires a power source to open it.
If it receives a power signal from a linked Button or Switch, it will open.
When it loses power, it will close. Switches will always toggle its state
regardless of "power" status.
If it receives a power signal from a linked Button or Switch, it will open. When it loses power, it will close. Switches will always toggle its state regardless of "power" status.
**Actor Options:**
* `opened` - boolean - if this option is checked, the Electric Trapdoor will be opened (powered) by default when the level begins. A switch may toggle it closed, or if it receives and then loses power, it will close as normal.
### Crumbly Floor
![Crumbly Floor](images/doodads/crumbly-floor.gif)
The **Crumbly Floor** behaves as a solid ceiling when hit from below, and a
solid floor when walked on from above, but watch out! The floor will shake
and collapse after a moment beneath your feet.
The **Crumbly Floor** behaves as a solid ceiling when hit from below, and a solid floor when walked on from above, but watch out! The floor will shake and collapse after a moment beneath your feet.
The floor will respawn after a while and forbids passage from the underside
of the doodad.
The floor will respawn after a while and forbids passage from the underside of the doodad.
---
* * *
## Gizmos
The gizmo doodads work best when **Linked** to other doodads in your level. For
example, a Button linked to an Electric Door will cause the door to open whenever
the button is pressed.
The gizmo doodads work best when **Linked** to other doodads in your level. For example, a Button linked to an Electric Door will cause the door to open whenever the button is pressed.
**See also:** [Link Tool](custom-levels/index.md#link-tool)
@ -336,12 +337,9 @@ the button is pressed.
![Button Type A](images/doodads/button-a.gif) ![Button Type B](images/doodads/button-b.gif)
**Buttons** will emit a `power: on` signal to all doodads that they are
[linked to](custom-levels/index.md#link-tool) when the button is pressed by the
player or another mobile doodad.
**Buttons** will emit a `power: on` signal to all doodads that they are [linked to](custom-levels/index.md#link-tool) when the button is pressed by the player or another mobile doodad.
When the button stops being pressed, it will emit a `power: off` signal to
all connected doodads, which will generally close electric doors.
When the button stops being pressed, it will emit a `power: off` signal to all connected doodads, which will generally close electric doors.
Buttons come in two varieties which are cosmetic only:
@ -354,48 +352,35 @@ Buttons come in two varieties which are cosmetic only:
The **Sticky Button** is a variant of the Button but with a red arrow on its side.
When the Sticky Button is pressed, it will emit a `power: on` signal and it will
**remain pressed** forever -- unless the button itself receives a `power: on`
signal from another linked doodad, then it will pop back up and can be pressed
again.
When the Sticky Button is pressed, it will emit a `power: on` signal and it will **remain pressed** forever -- unless the button itself receives a `power: on` signal from another linked doodad, then it will pop back up and can be pressed again.
### Switches
![Switch](images/doodads/switch.gif) ![Switch Right](images/doodads/switch-right.gif)
**Switches** will emit a `power: on` signal to any [linked](custom-levels/index.md#link-tool)
doodads when touched by the player or other mobile doodad, and then a `power: off`
signal when touched again.
**Switches** will emit a `power: on` signal to any [linked](custom-levels/index.md#link-tool) doodads when touched by the player or other mobile doodad, and then a `power: off` signal when touched again.
Switches come in a few different styles (all cosmetic in nature and behave the
same way):
Switches come in a few different styles (all cosmetic in nature and behave the same way):
* On/Off "background" wall switch that faces the screen.
* Side-profile switches to attach to the side of a wall (left and right).
* Side-profile floor switch.
---
* * *
## Boolean State Doodads
The **Boolean State Doodads** are a series of doodads which have a mutually
exclusive state from one another, with their state toggled by the "ON/OFF"
State Button.
The **Boolean State Doodads** are a series of doodads which have a mutually exclusive state from one another, with their state toggled by the "ON/OFF" State Button.
### State Button
![Blue "On"](images/doodads/blue-button.png) ![Orange "Off"](images/doodads/orange-button.png)
The **State Button** globally toggles the boolean state for all doodads in the
level which are sensitive to the state.
The **State Button** globally toggles the boolean state for all doodads in the level which are sensitive to the state.
The player character must jump into the ON/OFF block from below and hit it with
their head. From above, the ON/OFF block acts like a solid floor that the player
or other mobile doodads can stand on top of.
The player character must jump into the ON/OFF block from below and hit it with their head. From above, the ON/OFF block acts like a solid floor that the player or other mobile doodads can stand on top of.
In the future it will be possible to bonk the ON/OFF block from the sides or
top with enough force, but currently only hitting it from the bottom will flip
its state.
In the future it will be possible to bonk the ON/OFF block from the sides or top with enough force, but currently only hitting it from the bottom will flip its state.
* When the button is **OFF**, all **blue** state doodads are active. This is the default state.
* When the button is **ON**, all **orange** state doodads are active.
@ -406,11 +391,9 @@ its state.
![Orange "Off"](images/doodads/orange-off.png) ![Orange "On"](images/doodads/orange-on.png)
**State Blocks** are blue and orange squares that keep opposite state from one
another. In one state the block is solid, in another it is passable.
**State Blocks** are blue and orange squares that keep opposite state from one another. In one state the block is solid, in another it is passable.
The ON/OFF block will toggle all state blocks on the level to their opposite
setting whenever it's touched by the player or other mobile doodad.
The ON/OFF block will toggle all state blocks on the level to their opposite setting whenever it's touched by the player or other mobile doodad.
### Blue & Orange Warp Doors
@ -418,35 +401,33 @@ setting whenever it's touched by the player or other mobile doodad.
![Orange "Off" Door](images/doodads/warp-orange-off.png) ![Orange Warp Door](images/doodads/warp-door-orange.gif)
The **Blue & Orange Warp Doors** are variants of the [Warp Door](#warp-doors) that
are sensitive to the ON/OFF State Blocks. These doors can only be opened while the
door is in the "ON" (active) state -- when "OFF" (drawn as a hollow dotted outline)
the door can not be opened by the player. However, a player may still **exit** from
a de-activated door.
The **Blue & Orange Warp Doors** are variants of the [Warp Door](#warp-doors) that are sensitive to the ON/OFF State Blocks. These doors can only be opened while the door is in the "ON" (active) state -- when "OFF" (drawn as a hollow dotted outline) the door can not be opened by the player. However, a player may still **exit** from a de-activated door.
The **Blue Warp Door** is active at the same time as the **Blue State Blocks**,
and vice versa for the **Orange Warp Door.**
The **Blue Warp Door** is active at the same time as the **Blue State Blocks**, and vice versa for the **Orange Warp Door.**
---
**New in v0.10.1:** a Warp Door may only be opened by the player while the player is touching the ground (unless under the effects of antigravity, or while playing as the Bird). A door that is sufficiently up in the air requiring the player to jump or to fall past it can _not_ be opened by the player while in mid-air.
**Actor Options:**
* `locked (exit only)` - boolean - if this option is checked, the Warp Door can not be entered by the player; it will behave as a locked door, similarly to a door which has no linked exit. The door may still be exited from if another linked Warp Door sends the player there. You can make one-way Warp Doors by using this option.
* * *
## Technical Doodads
"Technical" doodads tend to turn invisible during gameplay and have some useful
interactions for certain situations.
"Technical" doodads tend to turn invisible during gameplay and have some useful interactions for certain situations.
### Goal Region
![Goal Region](images/doodads/goal-region.png)
This doodad acts like an invisible Exit Flag, winning the level if touched by
a player character.
This doodad acts like an invisible Exit Flag, winning the level if touched by a player character.
### Checkpoint Region
![Checkpoint Region](images/doodads/checkpoint-region.png)
This doodad acts like an invisible Checkpoint Flag, recording the player's
progress in a level.
This doodad acts like an invisible Checkpoint Flag, recording the player's progress in a level.
### Fire Region
@ -454,22 +435,50 @@ progress in a level.
This doodad will trigger the fail condition if touched by the player.
**Actor Options:**
* `name` - string - default is "fire", you may give the Fire Region a custom name to make it better imitate fire pixels. When touched, the fail message will be "Watch out for (name)!"
### Look At Me
![Look At Me](images/doodads/camera-focus.png)
The "Look At Me" doodad will attract the camera's attention when it receives a power signal from a linked button or switch.
An example use case is this: you have a Button that opens an Electric Door far across the level. When the button is pressed, you want the camera to scroll over to the Electric Door that it opened, so that the player can tell what has happened.
To do this, you would drag a "Look At Me" near the Electric Door and, with the Link Tool, connect the button to both the Electric Door and the "Look At Me." When the button is activated, and the two doodads receive power, the camera will scroll to where the Look At Me was placed.
If the player character inputs any directional controls, the camera will scroll back to follow the player again.
### Power Source
![Power Source](images/doodads/power-source.png)
On level start, this doodad emits a `power(true)` signal to all linked doodads.
Connect it to an Electric Door, for example, and the door will open immediately
when the level begins.
On level start, this doodad emits a `power(true)` signal to all linked doodads. Connect it to an Electric Door, for example, and the door will open immediately when the level begins.
### Stall Player
![Stall Player](images/doodads/stall-player.png)
This doodad will freeze the player character for 250ms, one time. It is useful
if you need to slow down the player to get some timing in your level to work
out.
This doodad will freeze the player character for 250ms, one time. It is useful if you need to slow down the player to get some timing in your level to work out.
If this doodad receives power from a linked button, it will reset the trap,
and will freeze the player again for 250ms should they make contact with the
doodad again.
If this doodad receives power from a linked button, it will reset the trap, and will freeze the player again for 250ms should they make contact with the doodad again.
### Invisible Warp Door
![Invisible Warp Door](images/doodads/invisible-warp-door.png)
This doodad acts just like the [Warp Doors](#warp-doors) but is invisible. Pressing the 'Use' key while grounded will activate the door and send you to the door it is linked to (if one exists).
**Actor Options:**
* `locked (exit only)` - boolean - if this option is checked, the Warp Door can not be entered by the player; it will behave as a locked door, similarly to a door which has no linked exit. The door may still be exited from if another linked Warp Door sends the player there. You can make one-way Warp Doors by using this option.
### Reset Timer
![Reset Timer](images/doodads/reset-timer.png)
This doodad will reset the level timer to zero, one time, when touched by the player. An example where it is used is on the Azulian Tag Tutorial level: the player could spend any amount of time reading the tutorial instructions, and Azulian Tag levels are rewarded for how long the player survives before dying, so they could artificially run up the clock before the game even begins!
The Reset Timer only runs one time when the player first touches it. If the doodad receives a power signal from a linked button or similar, it will 'reset' and is able to again reset the level timer one time the next time the player touches it.

View File

@ -1,22 +1,14 @@
# Hacking
This page discusses some advanced features of the game and targets a more
technical audience.
This page discusses some advanced features of the game and targets a more technical audience.
I've always loved it when developers keep debugging features in their released
games, and playing around with those and figuring out what makes the game tick.
I purposely left some debug features in the game that you can play around with.
I've always loved it when developers keep debugging features in their released games, and playing around with those and figuring out what makes the game tick. I purposely left some debug features in the game that you can play around with.
## Debug Features
Pressing `F3` within the game will draw the **Debug Overlay** on top of the
screen, displaying details such as the game's frames per second and some
contextual details like: what is the world index of the pixel below your mouse
cursor, while you're editing a level? (Details such as this are also seen in
the status bar at the bottom of the editor screen).
Pressing `F3` within the game will draw the **Debug Overlay** on top of the screen, displaying details such as the game's frames per second and some contextual details like: what is the world index of the pixel below your mouse cursor, while you're editing a level? (Details such as this are also seen in the status bar at the bottom of the editor screen).
The game can be launched with certain **Environment Variables** set to add
some additional debug visuals to the game. Examples:
The game can be launched with certain **Environment Variables** set to add some additional debug visuals to the game. Examples:
```bash
# Draw a semi-transparent yellow background over all level chunks
@ -31,46 +23,28 @@ $ DEBUG_CANVAS_LABEL=1 DEBUG_CHUNK_COLOR=FFFF00AA \
DEBUG_CANVAS_BORDER=FF0 ./doodle
```
![Debug features enabled](images/debugging.png)
Supported variables include:
* `DOODLE_W` and `DOODLE_H` set the width and height of the application
window. Equivalent to the `--window` command-line option.
* `D_SCROLL_SPEED` (int): tune the canvas scrolling speed. Default might
be around 8 or so.
* `DOODLE_W` and `DOODLE_H` set the width and height of the application window. Equivalent to the `--window` command-line option.
* `D_SCROLL_SPEED` (int): tune the canvas scrolling speed. Default might be around 8 or so.
* `D_DOODAD_SIZE` (int): default size for newly created doodads
* `D_SHELL_BG` (color): set the background color of the developer console
* `D_SHELL_FG` (color): text color for the developer console
* `D_SHELL_PC` (color): color for the shell prompt text
* `D_SHELL_LN` (int): set the number of lines of output history the
console will show. This dictates how 'tall' it rises from the bottom
of the screen. Large values will cover the entire screen with console
whenever the shell is open.
* `D_SHELL_FS` (int): set the font size for the developer shell. Default
is about 16. This also affects the size of "flashed" text that appears
at the bottom of the screen.
* `DEBUG_CHUNK_COLOR` (color): set a background color over each chunk
of drawing (level or doodad). A solid color will completely block out
the wallpaper; semitransparent is best.
* `DEBUG_CANVAS_BORDER` (color): the game will draw an insert colored
border around every "Canvas" widget (drawing) on the screen. The level
itself is a Canvas and every individual Doodad or actor in the level is
its own Canvas.
* `DEBUG_CANVAS_LABEL` (bool): draws a text label over every Canvas
widget on the screen, showing its name or Actor ID and some properties,
such as Level Position (LP) and World Position (WP) of actors within
a level. LP is their placement in the level file and WP is their
actual position now (in case it moves).
* `D_SHELL_LN` (int): set the number of lines of output history the console will show. This dictates how 'tall' it rises from the bottom of the screen. Large values will cover the entire screen with console whenever the shell is open.
* `D_SHELL_FS` (int): set the font size for the developer shell. Default is about 16. This also affects the size of "flashed" text that appears at the bottom of the screen.
* `DEBUG_CHUNK_COLOR` (color): set a background color over each chunk of drawing (level or doodad). A solid color will completely block out the wallpaper; semitransparent is best.
* `DEBUG_CANVAS_BORDER` (color): the game will draw an insert colored border around every "Canvas" widget (drawing) on the screen. The level itself is a Canvas and every individual Doodad or actor in the level is its own Canvas.
* `DEBUG_CANVAS_LABEL` (bool): draws a text label over every Canvas widget on the screen, showing its name or Actor ID and some properties, such as Level Position (LP) and World Position (WP) of actors within a level. LP is their placement in the level file and WP is their actual position now (in case it moves).
## Developer Console
Pressing the tilde/grave key (<code>`</code>) at any time will open the developer
console at the bottom of the screen (all gameplay logic is paused while the
console is open).
Pressing the tilde/grave key (`` ` ``) at any time will open the developer console at the bottom of the screen (all gameplay logic is paused while the console is open).
In the console you can type anything from simple commands, to hidden cheat
codes, to JavaScript commands to operate on some of the game's internal code!
In the console you can type anything from simple commands, to hidden cheat codes, to JavaScript commands to operate on some of the game's internal code!
![Screenshot of the developer console](images/shell.png)
@ -78,19 +52,14 @@ Pressing `Enter` without typing a command will close the console.
## Commands
At the white **&gt;** prompt you can type a command. Typing `help` will show
a listing of available commands; typing `help` and then a command name will
show further usage of that command. For example, `help echo`.
At the white **\>** prompt you can type a command. Typing `help` will show a listing of available commands; typing `help` and then a command name will show further usage of that command. For example, `help echo`.
The answer to your command is "flashed" in blue text at the bottom of the
screen and the developer console is closed. Pressing `Enter` will re-open the
console and show the recent history, including the answer to your last command.
The answer to your command is "flashed" in blue text at the bottom of the screen and the developer console is closed. Pressing `Enter` will re-open the console and show the recent history, including the answer to your last command.
>help echo
Usage: echo <message>
Flash a message back to the console
```
>help echo
Usage: echo <message>
Flash a message back to the console
```
The following commands are supported:
@ -116,20 +85,19 @@ The following commands are supported:
* `save [filename]`
Save the current drawing. If the drawing has not been saved
before, a filename is required, including the `.level` or
`.doodad` suffix.
Save the current drawing. If the drawing has not been saved before, a filename is required, including the `.level` or `.doodad` suffix.
* `edit <filename>`
Open a file for editing. The filename is a path on disk relative
to the game's working directory.
Open a file for editing. The filename is a path on disk relative to the game's working directory.
* `play <filename>`
Open a file for playing. The filename is a path on disk relative
to the game's working directory. A wrong filename will play a
new, blank level where Boy just falls to the bottom of the map.
Open a file for playing. The filename is a path on disk relative to the game's working directory. A wrong filename will play a new, blank level where Boy just falls to the bottom of the map.
* `titlescreen <filename>`
Open the title screen with a custom user level as its background. Note that the lazy scroll doesn't handle Unbounded levels very well yet!
* `close`
@ -139,47 +107,38 @@ The following commands are supported:
Close the developer console (an empty command would also work).
## Cheat Codes
Typing these messages in the console will toggle various mundane cheat
codes within the game. Press the tilde/grave key (<code>`</code>) to
open the developer console and type:
Typing these messages in the console will toggle various mundane cheat codes within the game. Press the tilde/grave key (`` ` ``) to open the developer console and type:
* `unleash the beast`
Do not cap the frames per second target of 60, allowing the game
to run as fast as it's capable of. May or may not actually work.
Do not cap the frames per second target of 60, allowing the game to run as fast as it's capable of. May or may not actually work.
* `don't edit and drive`
While playing a level, this makes the level canvas editable and
you can draw new pixels by clicking. Note that drawn pixels do not
"commit" to the level until you release the cursor.
While playing a level, this makes the level canvas editable and you can draw new pixels by clicking. Note that drawn pixels do not "commit" to the level until you release the cursor.
* `scroll scroll scroll your boat`
While playing a level, this allows scrolling the level with arrow
keys as if you're editing it. The camera still keeps the player
character in view.
While playing a level, this allows scrolling the level with arrow keys as if you're editing it. The camera still keeps the player character in view.
* `import antigravity`
While playing a level, this turns off gravity for the player
character. In this state the arrow keys can freely move the
character in any direction. [Relevant xkcd](https://xkcd.com/353/)
While playing a level, this turns off gravity for the player character. In this state the arrow keys can freely move the character in any direction. [Relevant xkcd](https://xkcd.com/353/)
* `ghost mode`
Disable collision detection for the player character. This
will also enable antigravity, otherwise you would fall to the
bottom of the level.
Disable collision detection for the player character. This will also enable antigravity, otherwise you would fall to the bottom of the level.
* `god mode`
Make the player character invulnerable to fire pixels and enemy mobs. You can walk thru fire and can't fail the level.
* `show all actors`
Run this during Play Mode to make all invisible actors visible. For
example, you'll be able to see all of the Technical Doodads which
normally turn themselves invisible, or you can reveal the player
character during Warp Door transitions.
Run this during Play Mode to make all invisible actors visible. For example, you'll be able to see all of the Technical Doodads which normally turn themselves invisible, or you can reveal the player character during Warp Door transitions.
* `give all keys`
@ -201,59 +160,80 @@ open the developer console and type:
Play as the Thief by default.
* `megaton weight`
Play as the Anvil by default.
* `pinocchio`
Play as the Boy (default) as the player character.
* `master key`
Temporarily allow playing locked levels in Story Mode without having completed earlier levels to unlock them properly.
* `warp whistle`
Automatically win the current level.
* `test load screen`
Opens the loading screen for a few moments.
* `test wait screen`
Opens the Wait modal for 10 seconds.
* `throw <message>`
Throw a custom JavaScript exception message, testing the exception catcher window.
* `throw2`
Test the JavaScript exception catcher with a very long message.
* `throw3`
Test the JavaScript exception catcher with a realistic error message.
## JavaScript Shell
The developer console also features a JavaScript shell, which exposes
many of the game's internal data types and functions that can be
useful when debugging the game, or just fun to see what you can
break within the game!
The developer console also features a JavaScript shell, which exposes many of the game's internal data types and functions that can be useful when debugging the game, or just fun to see what you can break within the game!
In the developer console, the `eval` or `$` command will run a single
line of JavaScript code.
In the developer console, the `eval` or `$` command will run a single line of JavaScript code.
>$ 2 + 2
4
>$ d.Flash("This is %s", d.Title())
This is Sketchy Maze v0.9.0
```
>$ 2 + 2
4
>$ d.Flash("This is %s", d.Title())
This is Sketchy Maze v0.9.0
```
The following native objects are exposed to the JavaScript shell:
* `d` is the master game object.
* `function RGBA(red, green, blue, alpha uint8)` creates a native
Color type, each value is range 0 to 255
* `function RGBA(red, green, blue, alpha uint8)` creates a native Color type, each value is range 0 to 255
* `function Point(x, y int)` creates a native Point type.
* `function Vector(x, y float64)` creates a native Vector type.
* `function Rect(x, y, w, h int)` creates a native Rect type.
* `function Tree(ui.Widget)` prints a tree of UI widgets drawn on the
screen -- if you can find the widgets somewhere under `d`
* `function Tree(ui.Widget)` prints a tree of UI widgets drawn on the screen -- if you can find the widgets somewhere under `d`
```
>$ RGBA(255, 153, 0, 230).String()
Color<#ff9900+e6>
>$ Object.keys(d)
Debug,Engine,Scene,ConfirmExit,DrawCollisionBox,DrawDebugOverlay,...
>$ typeof(d.Debug)
boolean
>$ typeof(d.Flash)
function
>$ d.Flash("Flash a custom message, like the `echo` command")
undefined
>$ d.EditDrawing("filename.level")
```
>$ RGBA(255, 153, 0, 230).String()
Color<#ff9900+e6>
>$ Object.keys(d)
Debug,Engine,Scene,ConfirmExit,DrawCollisionBox,DrawDebugOverlay,...
>$ typeof(d.Debug)
boolean
>$ typeof(d.Flash)
function
>$ d.Flash("Flash a custom message, like the `echo` command")
undefined
>$ d.EditDrawing("filename.level")
It helps if you run Sketchy Maze itself from a command line terminal,
so you can see its developer console output also on your terminal
window. Using `Object.keys(d)` will show all the exported functions and
variables from the internal game state.
Understanding that my game's [rendering engine](https://git.kirsle.net/go/render) and
[user interface toolkit](https://git.kirsle.net/go/ui) are open source projects
you can have fun reconfiguring widgets to change colors or whatever.
It helps if you run Sketchy Maze itself from a command line terminal, so you can see its developer console output also on your terminal window. Using `Object.keys(d)` will show all the exported functions and variables from the internal game state.
Understanding that my game's [rendering engine](https://git.kirsle.net/go/render) and [user interface toolkit](https://git.kirsle.net/go/ui) are open source projects you can have fun reconfiguring widgets to change colors or whatever.
![Screenshot of the JavaScript REPL](images/jsrepl.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
docs/images/levelpack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 107 KiB

BIN
docs/images/scoring.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 687 B

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 717 B

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 709 B

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 752 B

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 648 B

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
docs/images/totem-links.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

View File

@ -2,20 +2,19 @@
![](images/main-menu.png)
[Sketchy Maze](about.md) is a drawing-based maze game themed around hand-drawn
maps on paper. You can draw a level for a 2D platformer game, drag-and-drop
"doodads" such as buttons and doors into your level, play it and share your
levels with others.
[Sketchy Maze](about.md) is a drawing-based maze game themed around hand-drawn maps on paper. You can draw a level for a 2D platformer game, drag-and-drop "doodads" such as buttons and doors into your level, play it and share your levels with others.
**Last Updated:** Oct. 9, 2021 for Sketchy Maze v0.9.0.
**Last Updated:** Oct 10, 2022 for Sketchy Maze v0.13.1.
## Table of Contents
* [About Sketchy Maze](about.md)
* [Change History](changes.md)
* [Gameplay Controls](controls.md)
* [Story Mode](story-mode.md)
* [Creating Custom Levels](custom-levels/index.md)
* [Publishing Levels](custom-levels/publishing.md)
* [Level Packs](custom-levels/levelpacks.md)
* [Custom Wallpaper](custom-levels/custom-wallpaper.md)
* [The Built-in Doodads](doodads.md)
* [Linked Doodads](linked-doodads.md)
@ -27,4 +26,6 @@ levels with others.
* [The `doodad` command-line tool](doodad-tool.md)
* [Hacking and debugging](hacking.md)
* [Profile Directory](profile-directory.md)
* [Register Your Game](register.md)
* [Open Source Licenses](licenses.md)

View File

@ -1,7 +1,6 @@
# Profile Directory
Sketchy Maze stores your user-created levels and custom doodads in your
operating system's profile directory for your account.
Sketchy Maze stores your user-created levels and custom doodads in your operating system's profile directory for your account.
This will typically be found at the following locations based on your platform:
@ -12,14 +11,27 @@ This will typically be found at the following locations based on your platform:
## Opening your Profile Directory
The in-game Settings window has a button that will open your Profile Directory
in your operating system's default file browser. You will see the folders
labeled "levels" and "doodads" which is where your custom created content will
live.
The in-game Settings window has a button that will open your Profile Directory in your operating system's default file browser. You will see the folders labeled "levels" and "doodads" which is where your custom created content will live.
To install custom content created by other players, copy them into these folders.
## Contents of your Profile Directory
There are a few interesting folders:
* **levels:** This is where your user-created .level files are saved to. You can also copy levels made by other players into this folder.
* **doodads:** This is where your custom doodads go. You can copy doodads made by other players here and use them in your own levels.
* **levelpacks:** This is where you can place custom [Level Packs](custom-levels/levelpacks.md). You can create your own or download packs created by other players and place them in this folder.
* **screenshots:** the Giant Screenshot feature of the level editor will place its generated pictures here.
And some interesting files:
* **settings.json:** holds your game settings and is unique to your installation of the game.
* **savegame.json:** holds your progress through Story Mode level packs including high scores on the levels.
* **license.key:** if you have [registered the game](register.md) this is a copy of your license key file.
Note: to back up your savegame.json you must also copy the settings.json file, or otherwise the game will not accept the savegame.json if the settings file doesn't "match" it.
## See Also
* [Publishing Levels](custom-levels/publishing.md): embed custom doodads directly
_inside_ your level for easy sharing with others!
* [Publishing Levels](custom-levels/publishing.md): embed custom doodads directly _inside_ your level for easy sharing with others!

21
docs/register.md Normal file
View File

@ -0,0 +1,21 @@
# Register Your Game
_Sketchy Maze_ is a free (shareware) game and is intended to be fully functional in its free form, but for buying the game and supporting the creator you can unlock some additional functionality to make custom content and modding _much_ easier to do.
Visit the [Sketchy Maze](https://www.sketchymaze.com/) website for the latest information on how you can register your copy of the game and unlock these extra features.
## Activation
When you register the game you will receive a License Key file. From the game's main menu, click on the Register button (or from the level editor, the Help->Register menu) and click to browse for your License Key file and select it.
The game handles activation completely off-line (signed JWT) and it's _always_ yours and will always work for that version of the game at least. The developer reserves the right to revoke license keys with _future_ releases of the game in case keys are leaked onto piracy websites -- but versions of the game which accept a key today will always activate with that key.
## Features
The notable features that registering your game will unlock (as of v0.10.0) include:
* The ability to [publish](custom-levels/publishing.md) and play levels which **embed custom doodads** _inside_ the .level data for easy transport to "just play" on another registered copy of the game.
* And by extension, the ability to play a custom [Level Pack](custom-levels/levelpacks.md) which embeds custom doodads.
The free version of the game can use [custom doodads](custom-doodads/index.md): if the player copies the .doodad files into their [profile directory](profile-directory.md) they will appear in the Level Editor and will work in levels that ask for those doodads. Players can share custom levels and custom doodads, but the player needs to manage these files by hand. The features unlocked _so far_ allow levels to just _ship with_ their doodads and "just work" when you download and play their .level file, and [Level Packs](custom-levels/levelpacks.md) can do the same.

43
docs/story-mode.md Normal file
View File

@ -0,0 +1,43 @@
# Story Mode
The primary gameplay feature of Sketchy Maze is its Story Mode.
In Story Mode you can select from a [Level Pack](custom-levels/levelpacks.md) and play through its levels in series and compete for a local high score. Players may also create their own custom Level Packs and these will appear on the Story Mode menu as well.
![Scoring](images/scoring.png)
## High Score
In the Story Mode the player can record high scores on each level they complete. Currently, the high score is based around how quickly the level has been cleared and there are two tiers of scores per level:
* Perfect Run (gold): you completed the level without dying and restarting from a checkpoint.
* Best Run (silver): you completed the level but you had died and restarted from a checkpoint.
During gameplay, a timer appears in the corner of the screen accompanied by the gold or silver icon so you can see your current time while playing as well as which High Score tier you're competing for. The icon begins as gold but will turn silver if you run into a fire pixel or otherwise need to respawn from your last checkpoint.
If [cheat codes](hacking.md#cheat-codes) are used, you are not eligible to achieve a high score (the icon next to the timer will disappear) but you may still complete the level and unlock later levels.
## Unlocking Levels
Some Story Mode campaigns have locked levels and only the earliest levels are playable by default. Completing a level will unlock a level, until all of the levels have been unlocked.
You may complete a level by using cheat codes, e.g. for noclip and going straight for the level goal. This will unlock the next level, but you won't be able to record a High Score for completing a level using cheats.
## Azulian Tag
**New in v0.12.0**
Azulian Tag is a game mode in which the player is "It" and they have to avoid being caught by the enemies (an inverted version of the classic game, Tag). _Sketchy Maze_ includes a levelpack of Azulian Tag levels. The key elements of an Azulian Tag map include:
* Hard difficulty: so all Azulians across the whole level will chase towards the player character.
* Survival mode: the player is rewarded with a high score (silver medal) for surviving the longest amount of time before dying due to an Azulian or other cause.
Azulian Tag maps should also hide an Exit Flag somewhere to allow players to complete the level with a gold medal (for not dying). The gold medal high score is still based on how quickly the player beats the level, while the silver medal (if they get got by an Azulian) high score is for the longest duration kept alive.
## Backing Up Your Save Game
Your save game file can be backed up and restored to another computer so you don't lose your unlocked levels progression or your high scores. However, this must be handled carefully:
In your [profile directory](profile-directory.md) you'll want to copy your settings.json _and_ savegame.json files. To restore your backup to a different computer, place your settings.json and savegame.json into the profile directory on the new computer.
Notice: if you simply backup the savegame.json but not the settings.json then your savegame file will not be accepted by the game. The two are linked and this is a mild measure to deter cheating by editing your high scores directly.

View File

@ -5,17 +5,21 @@ nav:
- About Sketchy Maze: about.md
- Change History: changes.md
- Controls: controls.md
- Story Mode: story-mode.md
- Creating Levels: custom-levels/index.md
- Publishing Levels: custom-levels/publishing.md
- Level Packs: custom-levels/levelpacks.md
- Custom Wallpaper: custom-levels/custom-wallpaper.md
- Built-in Doodads: doodads.md
- Linked Doodads: linked-doodads.md
- Creating Custom Doodads: custom-doodads/index.md
- Drawing Doodads: custom-doodads/edit-in-game.md
- Doodad Scripts: custom-doodads/scripts.md
- Script API Reference: custom-doodads/api-reference.md
- Shortcut Keys: hotkeys.md
- "`doodad` Program": doodad-tool.md
- Hacking: hacking.md
- Register Your Game: register.md
- Open Source Licenses: licenses.md
theme: readthedocs
markdown_extensions: