diff --git a/docs/changes.md b/docs/changes.md index 79edca6..87ae450 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -1,5 +1,127 @@ # Changes +## v0.8.0 (September 4, 2021) + +This release brings some new features, new doodads, and new levels. + +New features: + +* **Checkpoints** for gameplay will ease the pain of dying to fire + pixels or Anvils by teleporting you back to the checkpoint instead + of resetting the whole level. +* The **Doodad Properties** window while editing a doodad grants access + to many features which were previously only available via the + `doodad` tool, such as: + * Edit metadata like the Title and Author of your doodad + * Set the default hitbox of your doodad. + * Attach, open, and delete the JavaScript for your doodad + * Manage tags (key/value store) on your doodads: how you can + communicate settings to the JavaScript which can receive the + tags via `Self.GetTag("name")` +* Some **Generic Doodad Scripts** are built in. Using only the in-game + tools, it is possible to create custom doodads which have some basic + in-game logic and you don't need to write any code. The generic + scripts include: + * Generic Solid: the hitbox is solid + * Generic Fire: its hitbox harms the player + * Generic Anvil: harmless, deadly when falling + * Generic Collectible Item: it goes in your inventory +* **All Characters are Playable!** Use the Link Tool to connect your + Start Flag with another doodad on your level, and you will play + **as** that doodad when the level starts. The Creature doodads are + all intended to be fully functional; playing as buttons and doors + leads to strange results. + +New doodads have been added: + +* The **Anvil** is a heavy metal object which is affected by gravity. + It is harmless to collision, but if the anvil is in freefall, it + will destroy every mobile doodad that it touches, and is deadly + to the player character. +* The **Electric Trapdoor** is a trapdoor that opens and closes when + powered by a button or switch. It is a horizontal version of the + Electric Door. +* The **Thief** is a new character which will steal items from the + player or other mobile doodads. The Thief is able to pick up items + and unlock doors and he walks back and forth like the Azulians. +* The **Blue Azulian** is now selectable from the Doodads menu. It + behaves like the Red Azulian but moves at half the speed. The + Azulians can pick up items and open doors. +* The **Checkpoint Flag** will remember the player's spot in the level. + Dying to fire pixels or Anvils no longer forces a restart of the + level - you can resume from your last checkpoint, or the Start Flag + by default. + +New levels have been added: + +* **Castle.level:** introduces the new Thief character. Castle-themed + level showing off various new doodads. +* **Thief 1.level:** a level where you play as the Thief! You need to + steal Small Keys from dozens of Azulians and even steal items back + from another Thief who has already stolen some of the keys. + +Some doodads have changed behavior: + +* The **Bird** can no longer pick up items, unless controlled by + the player character. +* The **Anvil** and **Box** will reset to their original locations + if they receive a power signal from a linked button or switch. + +The user interface has been improved: + +* **Tabbed windows!** The Doodad Dropper window of the level editor + and the Settings window use new, tabbed interfaces. +* **Doodad Categories:** the Doodad Dropper's tabs are divided into + a few major categories. + 1. Objects: Anvil, Box, Crumbly Floor, and Flags + 2. Doors: Doors, Trapdoors, and Keys + 3. Gizmos: Buttons, Switches, Electric Doors, etc. + 4. Creatures: Bird, Azulians, Thief + 5. All: a classic view paging over all doodads (and doodads + not fitting any of the above categories). + +New functions are available in the JavaScript API for custom doodads: + +* FailLevel(message string): global function that kills the player + with a custom death message. +* SetCheckpoint(Point): set the player respawn location +* Self.MoveTo(Point(x, y int)) +* Self.IsPlayer() bool +* Self.SetInventory(bool): turn on or off inventory. Keys and other + items will now only give themselves to mobile doodads which have + inventory. +* Self.HasInventory() bool +* Self.AddItem(filename string, quantity int) - zero quantity for + permanent items like the colored keys. +* Self.RemoveItem(filename string, quantity int) +* Self.HasItem(filename string) +* Self.Inventory() map[string]int +* Self.Hitbox() - also see Self.Hitbox.IsEmpty() + +The Events.OnLeave() callback now receives a CollideEvent argument, +like OnCollide, instead of the useless actor ID string. Notable +properties on the CollideEvent will be the .Actor which is leaving +and Settled=true. + +Other miscellaneous changes: + +* The **Link Tool** can now un-link two doodads by clicking on + them again. +* Actor UUIDs in your levels will now be Type 1 UUIDs (time-based) + instead of random. This will ensure each newly added doodad gets + a larger ID than the previous one, so in cases of draw order + conflicts or that sort of thing, the winner can be picked + deterministically (most recently added renders on top). +* A **death barrier** will prevent Boy from falling forever on unbounded + maps should he somehow fall off the level. The death barrier is a + Y value 1,000 pixels below the lowest pixel on your map. +* Mobile doodads no longer "moonwalk" when they change directions. +* A new color is added to all default palettes: "hint" (pink) for + writing hint notes. +* A maximum scroll speed on the "follow the player character" logic + makes for cooler animations when the character teleports around. +* Levels and Doodads are now sorted on the Open menu. + ## v0.7.2 (July 19 2021) This release brings some new features and some new content. diff --git a/docs/custom-doodads/edit-external.md b/docs/custom-doodads/edit-external.md index 3e253ff..58ce666 100644 --- a/docs/custom-doodads/edit-external.md +++ b/docs/custom-doodads/edit-external.md @@ -1,4 +1,4 @@ -# Drawing Doodads in an External Program +# External Editors for Doodads Doodad sprites can be drawn using any image editor and saved as .png files (with transparency). You can then create a doodad file from your series of @@ -18,3 +18,11 @@ doodad convert [options] # Example: doodad convert door-closed.png door-open.png door.doodad ``` + +The `doodad` tool can also be used to attach a JavaScript to your doodad, +modify its tags, and other things. See [`doodad` tool](../doodad-tool.md). + +## Example Doodads + +There are some fully working example doodads you can check out at +. \ No newline at end of file diff --git a/docs/custom-doodads/edit-in-game.md b/docs/custom-doodads/edit-in-game.md index 78805ca..0f6db34 100644 --- a/docs/custom-doodads/edit-in-game.md +++ b/docs/custom-doodads/edit-in-game.md @@ -4,12 +4,80 @@ Sketchy Maze has support for drawing your custom doodad sprites in-game, although for now you may find it more comfortable to use an [external image editor](edit-external.md) instead. +![Screenshot of the Doodad editor](../images/doodad-editor.png) + To start a new doodad, open the game and enter the level editor. Select the "File -> New Doodad" menu at the top of the screen. You will be prompted for the square dimensions of your doodad (i.e. `100` for a 100x100 sprite) and you can begin editing. -![Screenshot of the Doodad editor](../images/doodad-editor.png) +## Doodad Properties + +The "Doodad -> Doodad Properties" menu brings up the properties window for +the doodad you're editing: + +![Doodad Properties](../images/doodad-properties.png) + +This window has many useful features which (prior to v0.8.0) used to only be +available on the [`doodad` tool](../doodad-tool.md): + +* Metadata: you can modify the Title, Author and Hitbox fields. +* Doodad Script: you can view, upload and delete a JavaScript source for + your doodad. +* Generic Scripts: some built-in scripts to easily make useful doodads + without needing to write _any_ code! +* Tags: manage the key/value tag store on the doodad. Tags hold configuration + data that the JavaScript sometimes wants, or some tags have special meaning + to the game such as "category" (see below). + +## Generic Doodad Scripts + +![Generic Scripts](../images/generic-script.png) + +The game includes a few "generic" scripts that you can _easily_ attach to +your doodad. From the Doodad Properties window, click into the select box +and choose from the built-in scripts. A confirmation window will explain +the script and if you want to attach it to your doodad. + +### Generic Solid + +The Hitbox of your doodad will behave as a solid object in-game. Mobile +doodads can walk on top of it. + +### Generic Fire + +The Hitbox of your doodad acts just like fire pixels: it will "burn" mobile +doodads and it will harm the player character, failing the level. +"Watch out for (doodad title)!" + +### Generic Anvil + +Draw your own version of the Anvil! Your doodad does not have a solid hitbox, +and is perfectly harmless, except it falls with gravity and becomes deadly +while falling. It destroys any mobile doodad that it falls on and, if it's +the player character, fails the level. + +### Generic Collectible Item + +Your doodad will behave similarly to the Keys and can be "picked up" by the +player or other doodad with an inventory. Its sprite will appear in the +Inventory HUD in-game. Be careful on your sprite size, the inventory HUD +grows to accommodate the largest item sprite size! + +## Setting the Category Tag + +In the Level Editor, the Doodad Dropper window shows a categorical tab frame +with options like "Objects, Gizmos, Doors, Creatures, All" + +Your custom doodads will only appear in the "All" tab by default. To put your +doodad into one of the official category tabs, add a tag named "category" +holding one of these values: objects, gizmos, doors, or creatures (all +lowercase). + +![Doodad Tags](../images/doodad-tags.png) + +You may comma separate multiple categories. Unrecognized categories are +ignored - your doodad always appears on the All tab regardless. ## Layers @@ -17,7 +85,7 @@ A key difference between Levels and Doodads are that Doodad drawings can have multiple **layers**. For doodads these are used to store multiple frames of animation or different states, such as an opened vs. closed door. -Clicking the **Lyr.** button on the left toolbar or the "Tools -> Layers" +Clicking the **Lyr.** button on the left toolbar or the "Doodad -> Layers" menu will open the Layers window where you can switch your editor between layers, add and rename them. Layers can be toggled by the doodad's [JavaScript code](scripts.md) by index number or by name, so giving each layer @@ -26,10 +94,3 @@ a descriptive name is useful. Doodads saved in-game go in your [user config directory](../profile-directory.md) on your system. -## Future Planned Features - -Creating doodads in-game is intended to be a fully supported feature. The -following features are planned to be supported: - -* Implement some features only available on the `doodad` tool using in-game - UI, such as attaching JavaScripts to the doodad. diff --git a/docs/custom-doodads/index.md b/docs/custom-doodads/index.md index 70bcd2c..0830e25 100644 --- a/docs/custom-doodads/index.md +++ b/docs/custom-doodads/index.md @@ -13,6 +13,33 @@ image editor. Then, you can program their behavior using JavaScript to make them * Program its Behavior * [JavaScript](scripts.md) +## In-game Doodad Editor + +The in-game level editor can be used to create custom doodads. As of +Sketchy Maze v0.8.0, doodads can be authored entirely in-game without +needing to use the `doodad` command-line tool. + +![Screenshot of the Doodad editor](../images/doodad-editor.png) + +See [Drawing Doodads](edit-in-game.md) for details. + +## Using external editors + +You may find it more comfortable to draw your doodads in an external +image editor. All of the game's built-in doodads were drawn in The GIMP. +The `doodad` command-line tool that ships with the game is able to convert +a series of PNG images into a doodad, attach a JavaScript, set tags, and +so on. + +See [External Editors for Doodads](edit-external.md) + +## Example Doodads + +There are some example custom doodads you can check out at +. There you will find +example custom doodads to make your own player characters, Warp Doors, +and more. + ## Naming Convention It is strongly encouraged that you name your custom doodad files with a @@ -30,6 +57,30 @@ than yourself. Future versions of the game will likely prevent saving a new doodad with the same filename of a built-in one. +## Categories + +The in-game Doodad Dropper window of the level editor shows a categorical +view of doodads: Objects, Doors, Gizmos, Creatures, and All. + +Categories are managed by setting custom tags on your .doodad file, which +can be done by the [doodad tool](../doodad-tool.md) like so: + +```bash +doodad edit-doodad --tag "category=objects" example.doodad +``` + +The "category" tag should hold a lowercase value. Only supported categories +are recognized, which include: objects, doors, gizmos, creatures. + +A doodad can appear under multiple categories by joining them with a comma: + +```bash +doodad edit-doodad --tag "category=doors,gizmos" example.doodad +``` + +Every doodad also appears in the "All" tab. In the future, custom tags will +be editable using in-game UI when creating a custom doodad. + ## Profile Directory Custom doodads and levels will go in your [Profile Directory](../profile-directory.md), diff --git a/docs/custom-doodads/scripts.md b/docs/custom-doodads/scripts.md index 33fc8d4..7bcde8c 100644 --- a/docs/custom-doodads/scripts.md +++ b/docs/custom-doodads/scripts.md @@ -1,6 +1,6 @@ # Doodad Scripts -Doodads are programmed using JavaScript which gives them their behavior +Doodads are programmed using (ES5) JavaScript which gives them their behavior and ability to interact with the player and other doodads. Doodad scripts are run during "Play Mode" when a level _containing_ the doodad @@ -58,9 +58,14 @@ function main() { } ``` -# Installing a Doodad Script +## Installing a Doodad Script -Use the command-line `doodad` tool to attach a script to your doodad file: +Scripts can be attached to your doodad either in-game (using the Doodad +Properties window in the editor) or by using the command-line `doodad` program. + +![In-game Script UI](../images/doodad-properties.png) + +Using the command-line [`doodad` tool](../doodad-tool.md): ```bash # Attach the JavaScript at "script.js" to the doodad file "filename.doodad" @@ -71,7 +76,9 @@ doodad install-script script.js filename.doodad doodad show --script filename.doodad ``` -# Testing Your Script + + +## Testing Your Script The best way to test your doodad script is to use it in a level! @@ -80,13 +87,68 @@ like `console.log()` in your script to help debug issues. Drag your custom doodad into a level and playtest it! Your script's main() function is called when the level instance of your doodad is initialized. -# JavaScript API +## JavaScript API The following global variables are available to all Doodad scripts. -## Self +### Global Functions + +Some useful globally available functions: + +#### EndLevel() + +This ends the current level, 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. + +-------- + +### 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:** @@ -95,12 +157,20 @@ Self holds data about the current doodad instance loaded inside of a level. Methods are below. -### Self.ID() string +#### 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.GetTag(string name) string +#### 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. @@ -124,7 +194,7 @@ 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. -### Self.Position() Point +#### Self.Position() Point Returns the doodad's current position in the level. @@ -135,7 +205,16 @@ var p = Self.Position() console.log("I am at %d,%d", p.X, p.Y) ``` -### Self.SetHitbox(x, y, w, h int) +#### Self.MoveTo(Point) + +Teleport the current doodad to an exact point on the level. + +```javascript +// Teleport to origin. +Self.MoveTo(Point(0, 0)) +``` + +#### Self.SetHitbox(x, y, w, h int) Configure the "solid hitbox" of this doodad. @@ -174,7 +253,30 @@ function main() { } ``` -### Self.SetVelocity(Velocity) +#### 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: @@ -186,7 +288,7 @@ 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.SetMobile(bool) +#### Self.SetMobile(bool) Call `SetMobile(true)` if the doodad will move on its own. @@ -202,7 +304,7 @@ Position). Self.SetMobile(true); ``` -### Self.SetGravity(bool) +#### 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 @@ -210,9 +312,44 @@ want to be affected by gravity should opt in to this. ```javascript Self.SetGravity(true); + +// HasGravity to check. +console.log(Self.HasGravity()); // true ``` -### Self.ShowLayer(index int) +#### 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. + +```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. @@ -224,7 +361,7 @@ Self.ShowLayer(0); // 0 is the first and default layer Self.ShowLayer(1); // show the second layer instead ``` -### Self.ShowLayerNamed(name string) +#### Self.ShowLayerNamed(name string) Switch the active layer by name instead of index. @@ -241,7 +378,7 @@ order of file names passed in, with 0 being the first file: doodad convert door.png open-1.png open-2.png open-3.png my-door.doodad ``` -### Self.AddAnimation(name string, interval int, layers list) +#### 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 @@ -260,7 +397,7 @@ Self.AddAnimation("open", 100, ["open-1", "open-2", "open-3"]); Self.AddAnimation("close", 100, [3, 2, 1]); ``` -### Self.PlayAnimation(name string, callback func()) +#### Self.PlayAnimation(name string, callback func()) This starts playing the named animation. The callback function will be called when the animation has completed. @@ -274,11 +411,11 @@ Self.PlayAnimation("open", function() { }); ``` -### Self.IsAnimating() bool +#### Self.IsAnimating() bool Returns true if an animation is currently being played. -### Self.StopAnimation() +#### Self.StopAnimation() Stops any currently playing animation. @@ -292,7 +429,7 @@ Stops any currently playing animation. * Self.Doodad().GameVersion: the version of {{ app_name }} that was used when the doodad was created. -### Self.Destroy() +#### Self.Destroy() This destroys the current instance of the doodad as it appears in a level. @@ -302,7 +439,7 @@ doodad instance should be destroyed and removed from the active level. ----- -## Console Logging +### 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 @@ -318,12 +455,12 @@ console.error("Error-level messages"); ----- -## Timers and Intervals +### 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(function, milliseconds int) int setTimeout calls your function after the specified number of milliseconds. @@ -332,7 +469,7 @@ setTimeout calls your function after the specified number of milliseconds. Returns an integer "timeout ID" that you'll need if you want to cancel the timeout with clearTimeout. -### setInterval(function, milliseconds int) int +#### setInterval(function, milliseconds int) int setInterval calls your function repeatedly after every specified number of milliseconds. @@ -340,76 +477,42 @@ milliseconds. Returns an integer "interval ID" that you'll need if you want to cancel the interval with clearInterval. -### clearTimeout(id int) +#### clearTimeout(id int) Cancels the timeout with the given ID. -### clearInterval(id int) +#### clearInterval(id int) Cancels the interval with the given ID. ----- -## Type Constructors +### 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) +#### 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) +#### Point(x, y int) Creates a Point object with X and Y coordinates. -### Vector(x, y float64) +#### Vector(x, y float64) Creates a Vector object with X and Y dimensions. ----- -## Global Functions - -Some useful globally available functions: - -### EndLevel() - -This ends the current level, i.e. to be used by the goal flag. - -### 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. - --------- - -## Event Handlers +### Event Handlers Doodad scripts can respond to certain events using functions on the global `Events` variable. -### Events.OnCollide( func(event) ) +#### 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 @@ -429,12 +532,15 @@ attributes: 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) ) +#### 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). -### Events.RunKeypress( func(event) ) +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. @@ -442,7 +548,7 @@ TODO: document that. ----- -## Pub/Sub Communication +### 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 @@ -460,7 +566,7 @@ 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 +#### 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. @@ -473,10 +579,11 @@ their custom event names. |------|-----------|--------------| | power | boolean | Communicates a "powered" (true) or "not powered" state, as in a Button to an Electric Door. | | 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...) +#### Message.Publish(name string, data...) Publish a named message to all of your **linked** doodads. @@ -498,7 +605,7 @@ function main() { } ``` -### Message.Subscribe(name string, function) +#### Message.Subscribe(name string, function) Subscribe to a named message from any **linked** doodads. @@ -526,7 +633,7 @@ function main() { } ``` -### Message.Broadcast(name string, data...) +#### 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. diff --git a/docs/custom-levels/index.md b/docs/custom-levels/index.md index 7d1e1ed..10e36b6 100644 --- a/docs/custom-levels/index.md +++ b/docs/custom-levels/index.md @@ -79,18 +79,21 @@ with. The available options as of **version 0.6.0** are: 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 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 @@ -210,8 +213,8 @@ 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. -> **Note:** there seems to be no way to un-link two doodads once linked, -> deleting one from your level and placing a new one will break the links. +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 @@ -316,10 +319,13 @@ Its options include: * Undo (Ctrl-Z) * Redo (Ctrl-Y) * Settings -* **Level** - * Page settings (to change the level type or wallpaper) +* **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) diff --git a/docs/doodads.md b/docs/doodads.md index daa7aed..3f22c52 100644 --- a/docs/doodads.md +++ b/docs/doodads.md @@ -14,17 +14,22 @@ linked together in your levels. * [Objects](#objects) * [Start Flag](#start-flag) - Spawn point of a level + * [Checkpoint Flag](#checkpoint-flag) - **NEW in v0.8.0** * [Exit Flag](#exit-flag) - Goal of a level - * [Box](#bog) + * [Anvil](#anvil) - **NEW in v0.8.0** + * [Box](#box) * [Creatures](#creatures) * [Boy](#boy) - The player character * [Red Bird](#red-bird) - * [Red Azulian (test mob)](#red-azulian-test-mob) + * [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) @@ -32,7 +37,6 @@ linked together in your levels. * [Buttons](#buttons) * [Sticky Button](#sticky-button) * [Switches](#switches) - * [Electric Door](#electric-door) * [Boolean State Doodads](#boolean-state-doodads) * [State Button](#state-button) * [State Blocks](#state-blocks) @@ -50,12 +54,32 @@ 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 one of the flags at random. +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. +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). + +### 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 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. + ### Exit Flag ![Exit Flag](images/doodads/exit-flag.png) @@ -63,6 +87,22 @@ Flag. The **Exit Flag** sets a goal point for the level. The player must touch this flag to win the level. +### Anvil + +![Anvil](images/doodads/anvil.png) + +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. + +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. + ### Box ![Box](images/doodads/box.gif) @@ -79,6 +119,11 @@ 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. + --- # Creatures @@ -113,19 +158,55 @@ ride more reliably. Currently, however, the bird is harmless and does not dive bomb the player. -### Red Azulian (Test Mob) +**New in v0.8.0:** the Bird no longer can pick up items such as keys, unless +controlled by the player character. + +### Azulians ![Red Azulian](images/doodads/red-azulian.gif) -The red Azulian is a test mobile character. Not really an enemy, as he doesn't -care about the player. +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' 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. + +You can play as them in your custom levels by linking a Start Flag to +the Azulian. + +### Thief -The Azulian's A.I. just has it run left and right until it meets resistance. -It can pick up keys, activate buttons and switches that it passes by, and can -unlock doors. +![Thief](images/doodads/thief.gif) -This mob will probably go away in future releases of the game and will remain -in the code as a hidden easter egg. +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: + +* 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: + +* 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. --- @@ -203,6 +284,27 @@ 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. +### 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). + +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. + +### Electric Trapdoor + +![Electric Trapdoor](images/doodads/electric-trapdoor.gif) + +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. + ### Crumbly Floor ![Crumbly Floor](images/doodads/crumbly-floor.gif) @@ -266,17 +368,6 @@ same way): * Side-profile switches to attach to the side of a wall (left and right). * Side-profile floor switch. -### 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). - -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. - --- ## Boolean State Doodads diff --git a/docs/hacking.md b/docs/hacking.md index deaf3ea..3e98a9d 100644 --- a/docs/hacking.md +++ b/docs/hacking.md @@ -178,6 +178,22 @@ open the developer console and type: Removes all keys and items from the player's inventory. +* `fly like a bird` + + Play as the Bird by default on levels that don't specify a character. + +* `the cell` + + Play as the Blue Azulian by default. + +* `play as thief` + + Play as the Thief by default. + +* `pinocchio` + + Play as the Boy (default) as the player character. + ## JavaScript Shell The developer console also features a JavaScript shell, which exposes diff --git a/docs/images/doodad-editor.png b/docs/images/doodad-editor.png index 481ed17..b78bd32 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 new file mode 100644 index 0000000..02c8507 Binary files /dev/null and b/docs/images/doodad-properties.png differ diff --git a/docs/images/doodad-tags.png b/docs/images/doodad-tags.png new file mode 100644 index 0000000..b637297 Binary files /dev/null and b/docs/images/doodad-tags.png differ diff --git a/docs/images/doodads.png b/docs/images/doodads.png index 491497c..ce08bf3 100644 Binary files a/docs/images/doodads.png and b/docs/images/doodads.png differ diff --git a/docs/images/doodads/anvil.png b/docs/images/doodads/anvil.png new file mode 100644 index 0000000..205becc Binary files /dev/null and b/docs/images/doodads/anvil.png differ diff --git a/docs/images/doodads/checkpoint-flag.png b/docs/images/doodads/checkpoint-flag.png new file mode 100644 index 0000000..d8d9503 Binary files /dev/null and b/docs/images/doodads/checkpoint-flag.png differ diff --git a/docs/images/doodads/electric-trapdoor.gif b/docs/images/doodads/electric-trapdoor.gif new file mode 100644 index 0000000..5c27e08 Binary files /dev/null and b/docs/images/doodads/electric-trapdoor.gif differ diff --git a/docs/images/doodads/thief.gif b/docs/images/doodads/thief.gif new file mode 100644 index 0000000..316e4b0 Binary files /dev/null and b/docs/images/doodads/thief.gif differ diff --git a/docs/images/generic-script.png b/docs/images/generic-script.png new file mode 100644 index 0000000..0a90308 Binary files /dev/null and b/docs/images/generic-script.png differ diff --git a/docs/images/main-menu.png b/docs/images/main-menu.png index f8b135e..626e601 100644 Binary files a/docs/images/main-menu.png and b/docs/images/main-menu.png differ diff --git a/docs/index.md b/docs/index.md index e11dc44..1c0c453 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,7 +7,7 @@ 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:** July 19, 2021 for Sketchy Maze v0.7.2. +**Last Updated:** Sept. 3, 2021 for Sketchy Maze v0.8.0. ## Table of Contents diff --git a/docs/linked-doodads.md b/docs/linked-doodads.md index 95f0135..c722a30 100644 --- a/docs/linked-doodads.md +++ b/docs/linked-doodads.md @@ -20,6 +20,28 @@ Currently, the only way to _unlink_ two doodads is to delete one of them. With t This section describes how the built-in doodads interact with one another when they're linked, and some example use cases. Custom doodads made by users should follow similar patterns; check the [PubSub event types](custom-doodads/scripts.md#official-standard-pub-sub-messages) used by built-in doodads, or invent your own custom event types! +### Start Flag + +Link it with **any one doodad** and the that doodad will be the player +character for this level. + +It is considered an error to link more than one doodad to the Start Flag. +It is undefined behavior which doodad "wins" in that case. + +Upon level start, all actors linked to the Start Flag are destroyed. + +### Anvil + +If the Anvil receives **power** from any linked Button or Switch, it will teleport +back to its original starting location on the level. With this, players can make +a "Reset Button" for puzzle levels. + +### Box + +If the Box receives **power** from any linked Button or Switch, it will teleport +back to its original starting location on the level. With this, players can make +a "Reset Button" for puzzle levels. + ### Buttons Quick reference: @@ -81,6 +103,15 @@ The technicals: * If the sender is saying **power** (false), the door will close. * If the sender is a Switch, this message is ignored in favor of the toggle behavior. +### Electric Trapdoor + +The Electric Trapdoor is basically a horizontal version of the +[Electric Door](#electric-door). + +* Opens when it receives power from a Button, closes when power is removed. +* Always toggles state when powered from a Switch regardless of the Switch's + actual power status. + ### Warp Doors Warp Doors let the player fast travel across the map by sending them to a linked Warp Door.