diff --git a/docs/about.md b/docs/about.md index c0ce7f9..c409427 100644 --- a/docs/about.md +++ b/docs/about.md @@ -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. \ No newline at end of file +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. diff --git a/docs/changes.md b/docs/changes.md index 3f34c30..a10dd93 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -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 ` 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 .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 ` 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 + 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 ` 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: @@ -337,11 +901,11 @@ The new features: * **Choice of Default Palette for New Levels:** when creating a new level, a "Palette:" option appears which allows you to set the default colors to start your level with. The options include: - * Default: the classic default 4 colors (black, grey, red, blue). - * Colored Pencil: a set with more earthy tones for outdoorsy levels - (grass, dirt, stone, fire, water) - * Blueprint: the classic Blueprint wallpaper theme, a bright version of Default - for dark level backgrounds. + * Default: the classic default 4 colors (black, grey, red, blue). + * Colored Pencil: a set with more earthy tones for outdoorsy levels + (grass, dirt, stone, fire, water) + * Blueprint: the classic Blueprint wallpaper theme, a bright version of Default + for dark level backgrounds. * **Custom Wallpapers:** unhappy with the default, paper-themed level background images? You can now use your own! They attach to your level data for easy transport when sharing your level with others. diff --git a/docs/controls.md b/docs/controls.md index e565a9e..268d8ba 100644 --- a/docs/controls.md +++ b/docs/controls.md @@ -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. +* **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. ## 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. diff --git a/docs/custom-doodads/api-reference.md b/docs/custom-doodads/api-reference.md new file mode 100644 index 0000000..63e49c2 --- /dev/null +++ b/docs/custom-doodads/api-reference.md @@ -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); + } + }) +} +``` diff --git a/docs/custom-levels/index.md b/docs/custom-levels/index.md index 5f743a5..d558408 100644 --- a/docs/custom-levels/index.md +++ b/docs/custom-levels/index.md @@ -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,328 +24,208 @@ 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 - 2. **decoration**: light grey - 3. **fire**: red, fire - 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 -* **Blueprint:** the classic palette for levels with the Blueprint wallpaper: - 1. **solid**: white, solid - 2. **decoration:** light grey - 3. **fire**: light red (#FF5000), fire - 4. **water**: light blue (#0099FF), water - 5. **electric**: yellow, solid - 6. **hint**: pink +* **Default:** the classic palette from previous alpha game releases. + 1. **solid**: black, solid geometry + 2. **decoration**: light grey + 3. **fire**: red, fire + 4. **water**: blue, water + 5. **hint**: pink +* **Colored Pencil:** a new palette with some more varied default colors. + 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 + 3. **fire**: light red (#FF5000), fire + 4. **water**: light blue (#0099FF), water + 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: - * - **Pencil Tool** lets you click, drag, and draw pixels of your selected - Palette color onto your level freehand. Shortcut key: `f` - * - **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` - * - **Rectangle Tool** lets you easily draw rectangles on your level. Shortcut: `r` - * - **Ellipse Tool** lets you draw circles or elliptical shapes. Shortcut: `c` - * - **Doodad Tool** lets you drag doodads such as buttons and doors onto your - level. See the [Doodad Tool](#doodad-tool) below. Shortcut: `d` - * - **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. - * - **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 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: + * ![](../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 **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. +* 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 - **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 **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 **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. -* **Fire**: if the player touches pixels of this color, they die! -* **Water**: will act like water, currently it just draws the player blue. +* **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 magenta -or `#0099FF` for light blue. 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! +* 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 diff --git a/docs/custom-levels/levelpacks.md b/docs/custom-levels/levelpacks.md new file mode 100644 index 0000000..63cbd5d --- /dev/null +++ b/docs/custom-levels/levelpacks.md @@ -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] [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. + diff --git a/docs/doodads.md b/docs/doodads.md index 628c15f..2cbc9e6 100644 --- a/docs/doodads.md +++ b/docs/doodads.md @@ -1,54 +1,55 @@ # 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 - **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. -* [Objects](#objects) - * [Start Flag](#start-flag) - Spawn point of a level - * [Checkpoint Flag](#checkpoint-flag) - **NEW in v0.8.0** - * [Exit Flag](#exit-flag) - Goal of a level - * [Anvil](#anvil) - **NEW in v0.8.0** - * [Box](#box) -* [Creatures](#creatures) - * [Boy](#boy) - The player character - * [Red Bird](#red-bird) - * [Azulians](#azulians) - * [Thief](#thief) - **NEW in v0.8.0** -* [Doors & Trapdoors](#doors-trapdoors) - * [Colored Locked Doors & Keys](#colored-locked-doors-keys) - * [Small Key Doors](#small-key-doors) - * [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) - * [Switches](#switches) -* [Boolean State Doodads](#boolean-state-doodads) - * [State Button](#state-button) - * [State Blocks](#state-blocks) - * [Blue & Orange Warp Doors](#blue-orange-warp-doors) -* [Technical Doodads](#technical-doodads) - * [Goal Region](#goal-region) - * [Checkpoint Region](#checkpoint-region) - * [Fire Region](#fire-region) - * [Power Source](#power-source) - * [Stall Player](#stall-player) +**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) + * [Exit Flag](#exit-flag) - Goal of a level + * [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) + * [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) +* [Gizmos](#gizmos) + * [Buttons](#buttons) + * [Sticky Button](#sticky-button) + * [Switches](#switches) +* [Boolean State Doodads](#boolean-state-doodads) + * [State Button](#state-button) + * [State Blocks](#state-blocks) + * [Blue & Orange Warp Doors](#blue-orange-warp-doors) +* [Technical Doodads](#technical-doodads) + * [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. -* The A.I. Thief does **not** steal from other A.I. Thieves. +* 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. -* 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. +* 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. ---- +### 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,82 +208,102 @@ 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) Each key/door pair also has a distinct shape for color-impaired players: -* **Red Key** (triangle) -* **Green Key** (cross) -* **Yellow Key** (star) -* **Blue Key** (diamond) +* **Red Key** (triangle) +* **Green Key** (cross) +* **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,17 +337,14 @@ 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: -* **Button:** a button with a grey arrow that pops back up when pressed. -* **Button Type B:** a variation without the grey arrow but behaves the same. +* **Button:** a button with a grey arrow that pops back up when pressed. +* **Button Type B:** a variation without the grey arrow but behaves the same. ### Sticky Button @@ -354,51 +352,38 @@ 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. +* 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. +* 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. ### State Blocks @@ -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. \ No newline at end of file +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. diff --git a/docs/hacking.md b/docs/hacking.md index 1c18238..e257fc7 100644 --- a/docs/hacking.md +++ b/docs/hacking.md @@ -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. -* `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). +* `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). ## Developer Console -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). +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,182 +52,188 @@ Pressing `Enter` without typing a command will close the console. ## Commands -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`. +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 + Flash a message back to the console -``` ->help echo -Usage: echo -Flash a message back to the console -``` The following commands are supported: -* `help`, `help ` +* `help`, `help ` Shows the list of commands, or further help on a specific command. -* `echo ` +* `echo ` Flashes your custom message on the bottom of the screen. -* `error ` +* `error ` Flash your message in the error color. -* `alert ` +* `alert ` Pop up an alert box modal with a custom message. -* `new` +* `new` Go to the "New Drawing" screen. -* `save [filename]` +* `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 ` +* `edit ` - 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 ` +* `play ` - 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. -* `close` +* `titlescreen ` + + 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` Close the current level being edited and return to the title screen. -* `quit`, `exit` +* `quit`, `exit` 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 (`) 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` +* `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` +* `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` +* `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` +* `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` +* `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. -* `show all actors` +* `god mode` - 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. + Make the player character invulnerable to fire pixels and enemy mobs. You can walk thru fire and can't fail the level. -* `give all keys` +* `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. + +* `give all keys` Gives all four colored keys to the player. -* `drop all items` +* `drop all items` Removes all keys and items from the player's inventory. -* `fly like a bird` +* `fly like a bird` Play as the Bird by default on levels that don't specify a character. -* `the cell` +* `the cell` Play as the Blue Azulian by default. -* `play as thief` +* `play as thief` Play as the Thief by default. -* `pinocchio` +* `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 ` + + 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 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` +* `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 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` -``` ->$ 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) + diff --git a/docs/images/about.png b/docs/images/about.png index e620e8b..b9c866a 100644 Binary files a/docs/images/about.png and b/docs/images/about.png differ diff --git a/docs/images/checkpoint-link.png b/docs/images/checkpoint-link.png new file mode 100644 index 0000000..7c5963b Binary files /dev/null and b/docs/images/checkpoint-link.png differ diff --git a/docs/images/controls.png b/docs/images/controls.png index 2a418e4..6dcbf77 100644 Binary files a/docs/images/controls.png and b/docs/images/controls.png differ diff --git a/docs/images/doodad-editor.png b/docs/images/doodad-editor.png index b78bd32..6c165a5 100644 Binary files a/docs/images/doodad-editor.png and b/docs/images/doodad-editor.png differ diff --git a/docs/images/doodad-properties.png b/docs/images/doodad-properties.png index 02c8507..e812a6c 100644 Binary files a/docs/images/doodad-properties.png and b/docs/images/doodad-properties.png differ diff --git a/docs/images/doodads.png b/docs/images/doodads.png index ce08bf3..c78ffd8 100644 Binary files a/docs/images/doodads.png and b/docs/images/doodads.png differ diff --git a/docs/images/doodads/bird-blue.gif b/docs/images/doodads/bird-blue.gif new file mode 100644 index 0000000..ed6ea33 Binary files /dev/null and b/docs/images/doodads/bird-blue.gif differ diff --git a/docs/images/doodads/blue-azulian.gif b/docs/images/doodads/blue-azulian.gif new file mode 100644 index 0000000..9417767 Binary files /dev/null and b/docs/images/doodads/blue-azulian.gif differ diff --git a/docs/images/doodads/camera-focus.png b/docs/images/doodads/camera-focus.png new file mode 100644 index 0000000..d219673 Binary files /dev/null and b/docs/images/doodads/camera-focus.png differ diff --git a/docs/images/doodads/crusher.gif b/docs/images/doodads/crusher.gif new file mode 100644 index 0000000..637b947 Binary files /dev/null and b/docs/images/doodads/crusher.gif differ diff --git a/docs/images/doodads/gem-blue.gif b/docs/images/doodads/gem-blue.gif new file mode 100644 index 0000000..ff0f9f1 Binary files /dev/null and b/docs/images/doodads/gem-blue.gif differ diff --git a/docs/images/doodads/gem-green.gif b/docs/images/doodads/gem-green.gif new file mode 100644 index 0000000..7b4f87b Binary files /dev/null and b/docs/images/doodads/gem-green.gif differ diff --git a/docs/images/doodads/gem-red.gif b/docs/images/doodads/gem-red.gif new file mode 100644 index 0000000..4e0e187 Binary files /dev/null and b/docs/images/doodads/gem-red.gif differ diff --git a/docs/images/doodads/gem-yellow.gif b/docs/images/doodads/gem-yellow.gif new file mode 100644 index 0000000..aba508b Binary files /dev/null and b/docs/images/doodads/gem-yellow.gif differ diff --git a/docs/images/doodads/invisible-warp-door.png b/docs/images/doodads/invisible-warp-door.png new file mode 100644 index 0000000..f2b31d4 Binary files /dev/null and b/docs/images/doodads/invisible-warp-door.png differ diff --git a/docs/images/doodads/reset-timer.png b/docs/images/doodads/reset-timer.png new file mode 100644 index 0000000..4c55879 Binary files /dev/null and b/docs/images/doodads/reset-timer.png differ diff --git a/docs/images/doodads/snake.gif b/docs/images/doodads/snake.gif new file mode 100644 index 0000000..d7e80a3 Binary files /dev/null and b/docs/images/doodads/snake.gif differ diff --git a/docs/images/doodads/totem.png b/docs/images/doodads/totem.png new file mode 100644 index 0000000..58ea99d Binary files /dev/null and b/docs/images/doodads/totem.png differ diff --git a/docs/images/doodads/white-azulian.gif b/docs/images/doodads/white-azulian.gif new file mode 100644 index 0000000..6e9ba2d Binary files /dev/null and b/docs/images/doodads/white-azulian.gif differ diff --git a/docs/images/levelpack.png b/docs/images/levelpack.png new file mode 100644 index 0000000..208bfe7 Binary files /dev/null and b/docs/images/levelpack.png differ diff --git a/docs/images/link-tool.png b/docs/images/link-tool.png index c9b10d0..08ef504 100644 Binary files a/docs/images/link-tool.png and b/docs/images/link-tool.png differ diff --git a/docs/images/main-menu.png b/docs/images/main-menu.png index 85f5ae9..1725ec8 100644 Binary files a/docs/images/main-menu.png and b/docs/images/main-menu.png differ diff --git a/docs/images/newlevel-1.png b/docs/images/newlevel-1.png index 022a6dc..e17c71f 100644 Binary files a/docs/images/newlevel-1.png and b/docs/images/newlevel-1.png differ diff --git a/docs/images/newlevel-2.png b/docs/images/newlevel-2.png index 0041017..2618f6f 100644 Binary files a/docs/images/newlevel-2.png and b/docs/images/newlevel-2.png differ diff --git a/docs/images/palette-rgba.png b/docs/images/palette-rgba.png index 3f36611..3f92ff7 100644 Binary files a/docs/images/palette-rgba.png and b/docs/images/palette-rgba.png differ diff --git a/docs/images/palette.png b/docs/images/palette.png index 1de20f1..a1bd60c 100644 Binary files a/docs/images/palette.png and b/docs/images/palette.png differ diff --git a/docs/images/palettes.png b/docs/images/palettes.png index 1b66a95..ea5ff64 100644 Binary files a/docs/images/palettes.png and b/docs/images/palettes.png differ diff --git a/docs/images/patterns.png b/docs/images/patterns.png index 1df4772..4e37d90 100644 Binary files a/docs/images/patterns.png and b/docs/images/patterns.png differ diff --git a/docs/images/publish.png b/docs/images/publish.png index 9b095dc..4cbc9d2 100644 Binary files a/docs/images/publish.png and b/docs/images/publish.png differ diff --git a/docs/images/scoring.png b/docs/images/scoring.png new file mode 100644 index 0000000..ce96904 Binary files /dev/null and b/docs/images/scoring.png differ diff --git a/docs/images/sprites/actor-tool.png b/docs/images/sprites/actor-tool.png index c7135bb..de13aff 100644 Binary files a/docs/images/sprites/actor-tool.png and b/docs/images/sprites/actor-tool.png differ diff --git a/docs/images/sprites/ellipse-tool.png b/docs/images/sprites/ellipse-tool.png index 044de12..2921942 100644 Binary files a/docs/images/sprites/ellipse-tool.png and b/docs/images/sprites/ellipse-tool.png differ diff --git a/docs/images/sprites/eraser-tool.png b/docs/images/sprites/eraser-tool.png index 1680502..8a999e3 100644 Binary files a/docs/images/sprites/eraser-tool.png and b/docs/images/sprites/eraser-tool.png differ diff --git a/docs/images/sprites/flood-tool.png b/docs/images/sprites/flood-tool.png new file mode 100644 index 0000000..0a44c89 Binary files /dev/null and b/docs/images/sprites/flood-tool.png differ diff --git a/docs/images/sprites/line-tool.png b/docs/images/sprites/line-tool.png index 460aff0..2ce6007 100644 Binary files a/docs/images/sprites/line-tool.png and b/docs/images/sprites/line-tool.png differ diff --git a/docs/images/sprites/link-tool.png b/docs/images/sprites/link-tool.png index bcd27ac..eaf3917 100644 Binary files a/docs/images/sprites/link-tool.png and b/docs/images/sprites/link-tool.png differ diff --git a/docs/images/sprites/pan-tool.png b/docs/images/sprites/pan-tool.png new file mode 100644 index 0000000..829b065 Binary files /dev/null and b/docs/images/sprites/pan-tool.png differ diff --git a/docs/images/sprites/pencil-tool.png b/docs/images/sprites/pencil-tool.png index 8dd76f6..a96503a 100644 Binary files a/docs/images/sprites/pencil-tool.png and b/docs/images/sprites/pencil-tool.png differ diff --git a/docs/images/sprites/rect-tool.png b/docs/images/sprites/rect-tool.png index 00afb2c..c91ace8 100644 Binary files a/docs/images/sprites/rect-tool.png and b/docs/images/sprites/rect-tool.png differ diff --git a/docs/images/sprites/text-tool.png b/docs/images/sprites/text-tool.png new file mode 100644 index 0000000..62d02bc Binary files /dev/null and b/docs/images/sprites/text-tool.png differ diff --git a/docs/images/start-flag-link.png b/docs/images/start-flag-link.png new file mode 100644 index 0000000..9115bf7 Binary files /dev/null and b/docs/images/start-flag-link.png differ diff --git a/docs/images/totem-links.png b/docs/images/totem-links.png new file mode 100644 index 0000000..c81c447 Binary files /dev/null and b/docs/images/totem-links.png differ diff --git a/docs/images/touch-controls.png b/docs/images/touch-controls.png new file mode 100644 index 0000000..51ff9ab Binary files /dev/null and b/docs/images/touch-controls.png differ diff --git a/docs/index.md b/docs/index.md index d420b1c..858cba5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,29 +2,30 @@ ![](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) -* [Creating Custom Levels](custom-levels/index.md) - * [Publishing Levels](custom-levels/publishing.md) - * [Custom Wallpaper](custom-levels/custom-wallpaper.md) -* [The Built-in Doodads](doodads.md) -* [Linked Doodads](linked-doodads.md) -* [Creating Custom Doodads](custom-doodads/index.md) - * [Draw Sprites In-Game](custom-doodads/edit-in-game.md) - * [Draw Sprites with an External Program](custom-doodads/edit-external.md) - * [Program Them with JavaScript](custom-doodads/scripts.md) -* [Shortcut Keys](hotkeys.md) -* [The `doodad` command-line tool](doodad-tool.md) -* [Hacking and debugging](hacking.md) - * [Profile Directory](profile-directory.md) -* [Open Source Licenses](licenses.md) +* [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) +* [Creating Custom Doodads](custom-doodads/index.md) + * [Draw Sprites In-Game](custom-doodads/edit-in-game.md) + * [Draw Sprites with an External Program](custom-doodads/edit-external.md) + * [Program Them with JavaScript](custom-doodads/scripts.md) +* [Shortcut Keys](hotkeys.md) +* [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) + diff --git a/docs/profile-directory.md b/docs/profile-directory.md index 98a8abf..4a65158 100644 --- a/docs/profile-directory.md +++ b/docs/profile-directory.md @@ -1,25 +1,37 @@ # 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: -* **Windows:** `%APPDATA%` or `C:\Users\%USER%\AppData\Roaming\doodle` -* **Mac OS:** `$HOME/Library/Application Support/doodle` -* **GNU/Linux:** `$XDG_CONFIG_HOME/doodle` or `$HOME/.config/doodle` -* **Linux (Flatpak):** `$HOME/.var/app/com.sketchymaze.Doodle/config/doodle` +* **Windows:** `%APPDATA%` or `C:\Users\%USER%\AppData\Roaming\doodle` +* **Mac OS:** `$HOME/Library/Application Support/doodle` +* **GNU/Linux:** `$XDG_CONFIG_HOME/doodle` or `$HOME/.config/doodle` +* **Linux (Flatpak):** `$HOME/.var/app/com.sketchymaze.Doodle/config/doodle` ## 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! \ No newline at end of file +* [Publishing Levels](custom-levels/publishing.md): embed custom doodads directly _inside_ your level for easy sharing with others! diff --git a/docs/register.md b/docs/register.md new file mode 100644 index 0000000..4ede143 --- /dev/null +++ b/docs/register.md @@ -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. + diff --git a/docs/story-mode.md b/docs/story-mode.md new file mode 100644 index 0000000..6b5d883 --- /dev/null +++ b/docs/story-mode.md @@ -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. diff --git a/mkdocs.yml b/mkdocs.yml index 9d78449..4859e0b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -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: