1. Welcome To Adventuron

Adventuron is a TEXT ADVENTURE and GAMEBOOK game creation system for modern (HTML5) and retro platforms.

Click here for a list of games made using Adventuron.

For interactive help, don’t hesitate to use the Adventuron Discord Server (beginners channel).

Text Adventure Literacy Jam - Create a TEXT ADVENTURE game suitable for children with no prior experience. Lots of prizes to be won including a Raspberry Pi 400 Desktop Computer, Raspberry Pi 4 + more. Event runs Feb 25th to March 31st, 2021.

rite 3
Figure 1. Rite of the Druid by Sunteam (Adventuron version).

1.1. ZX Spectrum Next + Compatibility Mode

Adventuron (in 8-bit compatibility mode) can be used to target platforms such as ZX Spectrum, ZX Spectrum Next, Amstrad PCW, Amiga, & more.

If you are interested in this aspect of Adventuron, then please follow Tutorial A.

snext
Figure 2. ZX Spectrum Next, image from https://www.specnext.com (Copyright fair use)
rite zx
Figure 3. Rite of the Druid by Sunteam (ZX Spectrum Next version).

1.2. Features

  • Easy to learn, multiple tutorials, well documented.

  • A web-based code-editor with autocompletion.

  • Fast development - play as you code.

  • Play games on desktop, mobile, and classic computer platforms.

  • Export to 8-bit platforms: Amstrad CPC, Commodore 64, ZX Spectrum, ZX Spectrum Next, ..

  • A fun way to learn to code.

  • Suitable for Raspberry Pi

  • Excellent support.

1.3. Text Adventures

A text adventure game is a type of game in which the player interacts with via text (similar to instant messaging).

Typically, text adventure games are a blend of storytelling and problem solving, but some adventures may choose to focus on one or the other.

Text adventures can also feature bright vibrant graphics.

Click here to play an interactive tutorial game (5 minutes duration).

Screenshots of games made with Adventuron are shown below.

sample witch 1
Figure 4. The Witch’s Apprentice by Garry Francis (written in Adventuron Classroom)
hh 3
Figure 5. Treasures of Hollowhill by John Blythe (written in Adventuron Classroom)
rite 6
Figure 6. Rite of the Druid by Sunteam (written in Adventuron Classroom)
sample spooky 1
Figure 7. Spooky Adventure by Chris Ainsley (written in Adventuron Classroom)
excal phone
Figure 8. Excalibur

1.4. Games

Click here for a list of games written with Adventuron Classroom.

2. Tutorials

All tutorials contain step by step instructions supported by animated gifs.

2.1. Tutorial A - 60 minute

Tutorial A is about 60 minutes.

Tip
Start here if wanting to make games for ZX Spectrum Next.
com inside cave

2.2. Tutorial B - 180 minute

Tutorial B is about 180 minutes.

Note
This is the tutorial that is built into Adventuron Classroom.
game over

2.3. Video Tutorial (Tutorial A)

The following video tutorial is an earlier version of tutorial A. For exporting to ZX Spectrum Next, follow the tutorial A written (+ animated gif) tutorial.

3. Reference Guide

The Adventuron editor is located at adventuron.io/classroom.

If you have any problems with the documentation, or need help, don’t hesitate to use the Adventuron Discord Server.

3.1. Locations

A text adventure game must contain one or more location.

Each location has an id, which is the id that you refer to the location by in the game code.

A location must also have a description - although the description can be empty if you want.

Locations are very configurable, but we’ll deal with the normal simple definition of a location here.

start_at = bottom_of_hill

locations {
   bottom_of_hill : location "You are standing at the bottom of the hill." ;
   top_of_hill    : location "You are standing at the top of the hill." ;
}

3.1.1. Location Headers

Adventuron can be laid out with headers appearing when describing a location. They can also be utilized by the auto-map feature. To define a header, simply fill out the header="" section.

locations {
   bottom_of_hill : location "You are standing at the bottom of the hill." header="Bottom of Hill";
   top_of_hill    : location "You are standing at the top of the hill." header="Top of Hill";
}

3.1.2. Connections

Direction mappings are bidirectional in Adventuron, and you read from left to right.

Bidirectional Mappings
connections {
   from, direction, to = [
      bottom_of_hill, up, top_of_hill
   ]
}

Bottom of hill goes UP to the top of the hill - THEREFORE - the top of the hill goes DOWN to the bottom of the hill.

Unidirectional Mappings
connections {
   from, direction, to = [
      bottom_of_hill, up_oneway, top_of_hill
   ]
}

Bottom of hill goes UP to the top of the hill, but the top of the hill does NOT lead down to the bottom of the hill.

3.2. Objects

Objects are entities in the games that can be interacted with in some way.

Even though they are called objects, objects can also represent characters in the game too.

An object has a parent. The parent can be a location, or another object, or the 'ether', which is a special object which holds objects that don’t exist in the game world.

The weight of an object is "1" by default. The default weight limit that the player can carry is 200 by default. The default object carry limit (independent of weight) is 10.

Objects are takeable and droppable by default (the player can carry the objects).

An object (or character) that cannot be taken is called 'scenery', and you can find examples of defining objects and scenery in the next section.

3.2.1. Defining Objects

Object Type Details

object

A normal takeable/droppable object.

scenery

An object that cannot be taken, but will be listed (configurable).

Defining An Object That Will Not Exist On Game Start
objects {
   blue_spoon : object "a blue spoon";
}
Defining An Object That Will Be Held By Player On Game Start
objects {
   blue_spoon : object "a blue spoon" at="inventory";
}
Note
'at' and 'start_at' can both be used to describe the start location of an object, but only start_at can be used to describe the start location of the player.
Defining An Object In A Particular Location
objects {
   blue_spoon : object "a blue spoon" at="barn";
}
Defining An Object To Be Wearable
objects {
   hat : object "a stylish hat" at="barn" wearable="true";
}
Defining An Object To Be Wearable And Initially Worn
objects {
   // Wearable is implicitly true if an object is initially worn
   hat : object "a stylish hat" at="inventory" worn="true";
}
Defining an object that cannot be taken (scenery)
objects {
   boulder : scenery "a huge boulder" at = "cliff";
}
Defining an object with a weight of 50 (will be 1 if not provided).
objects {
   steel_bar : object "a steel bar" weight = "50" ;
}

3.2.2. Object Identifiers

Objects are special in that their identifiers have TWO uses. The first use is to act as a unique identifier for the purpose of referring to them from the code. The second use is to define the adjective and the noun associated with the object.

Declaration How it is used

key : object "a key";

Defines noun as "key", description as "a key";

blue_key : object "a key";

Defines noun as "key", adjective as "blue", description as "a key".

green_key : object "a key";

Defines noun as "key", adjective as "green", description as "a green key".

The description does not have to have anything to do with the noun or the adjective at all - although it SHOULD unless the player will become confused.

3.2.3. Conspicuousness

You may wish to manually describe the presence of an object (or scenery object) in your location (usually via the on_describe {} section).

In these cases, it can be handy to remove the object from the standard object list section. To do this, simply mark an object (or scenery object) as conspicuous="false".

Non-conspicuous scenery objects can be used to quietly place an object in a room, where the room description already describes the object within its own text.

e.g.

start_at = graveyard

locations {
   graveyard : location "You are in a brightly lit graveyard. A red brick wall lies to the north with a bench facing south. A gravestone takes your interest."
}

objects {
   bench      : scenery "a bench"      at="graveyard" conspicuous="false" msg="Sturdy";
   gravestone : scenery "a gravestone" at="graveyard" conspicuous="false" msg="Died 1692.";
}

Non-conspicuous objects can also be used to manually print objects that may move around the game in a bespoke manner (i.e. not in the objects list).

Describing an NPC in the on_describe{} section
start_at = waterfall

locations {
   waterfall : location "You are standing at the base of the waterfall."
}

objects {
   elf : scenery "an elf" at="waterfall" conspicuous="false" ;
}

on_describe {
   : if (is_present "elf") {
      : if (chance(50)) {
         : print "Terry, the mountain elf is here.";
      }
      : else {
         : print "The mountain elf is here.";
      }
   }
}

3.2.4. Multiple Objects With Same Adjective Noun

There are multiple ways to deal with this scenario, but the simplest way is to simply add a numeric suffix to the object name. This only works in the adjective_noun variant.

e.g.

objects {
   blue_spoon_1 : object "a blue spoon" at="barn";
   blue_spoon_2 : object "a blue spoon" at="kitchen";
   blue_spoon_3 : object "a blue spoon" at="well";
   blue_spoon_4 : object "a blue spoon" at="castle";
   blue_spoon_5 : object "a blue spoon" at="dungeon";
}

In all 5 cases, the objects will be created with noun = spoon, adjective = blue.

3.2.5. Object Identifiers, Descriptions, & Aliases

The id of the object is a shorthand for the associated adjective and noun, but specifying explicit adjective and/or noun will override this behaviour.

objects {
   noun              : scenery "anytext";
   adjective_noun    : scenery "anytext";
   anything_you_line : scenery "anytext" noun="lump" adjective ="yellow";
}

You can also switch off this entity id (to adjective / noun) association in the game_settings {} section, but it is enabled by default.

game_settings {
   scan_entity_ids_for_vocab_items = false
}

You can’t specify multiple nouns or multiple adjectives per object, but you can create noun groups and adjective groups that the parser will automatically collect together:

vocabulary {
   : verb      / aliases = [pet, stroke]
   : noun      / aliases = [cat, creature, feline]
   : adjective / aliases = [yellow, golden]
}

In the : match "" {} section, you can use any item in a noun group to match on, and it will treat it the same as any other member of the group.

That is : match "stroke cat" {} is exactly the same as : match "stroke feline" {}, the player could type STROKE CAT, or STROKE FELINE, or PET CAT, or PET FELINE, and it both these match statement would match all 4 of these inputs.

If you want a completely different noun to represent the same object, but the noun is not a synonym, then you can also chain together nouns in match statements like this:

// You may not want to put "lump" as a synonym for cat, therefore you can just list it as a different match item

: match "stroke cat; stroke lump" {
   : print "Cat Purrs."
}

3.3. Variables

3.3.1. Boolean Variables

booleans {
    has_bell_been_rung : boolean "false"; // False is the default
}

3.3.2. Integer Variables

integers {
    number_of_times_visited_well : integer "0";                      // 0 is default, 0 is min
    number_of_times_visited_hut  : integer "0" max="100";            // 0 is default, 0 is min, 100 is max
    number_of_times_visited_lake : integer "0" min="-100" max="100"; // 0 is default, -100 is min, 100 is max
}

3.3.3. String Variables

String variables can be used to hold text.

Every string variable has a string value (no concept of NULL).

strings {
   some_character_name : string "Susan"; // Susan is default
}

3.4. Barriers

Barriers represents a way of blocking (or intercepting) movement to another location, on a conditional basis.

There are 3 types of block:

Block Type Details

block

Blocks entry to a location from any adjacent location.

block_path

Blocks entry to a location, but only in one direction (from another particular location)

door

A door needs to be opened, and if locked, it needs to be nominated with a particular key.

3.4.1. Block activation conditions.

Blocks are dynamically evaluated by Adventuron. They generally are controlled by the contents of a boolean variable, or by the existence or non-existence of an object.

Example 1 - Block if an object exists
barriers {
   throneroom_block : block {
      block_when_exists   = king
      location            = throne_room
      message             = The king is far too busy and orders you out of the room.
    }
}
Example 2 - Block if an object is not carried
barriers {
   mines_block : block {
     block_when_not_carried = glowing_sword
     location               = emerald_mine_1
     message                = The mines are far too dark to venture into unaided.
   }
}
Example 3 - Block when boolean variable is false
barriers {
   maze_block : block {
      block_when_not = is_read_map
      location       = maze_1
      message        = You dare not enter the maze without knowing more about it first.
   }
}

The throneroom_block can be anything, but it has to be in the identifier format with is alpha numeric, with underscores.

3.4.2. Block Path

Block path work in exactly the same way as a 'block' except you must specify from and to.

barriers {
   throneroom_block : block_path {
      from                = hallway
      to                  = throne_room
      block_when_exists   = king
      message             = The king is far too busy and orders you out of the room.
   }
}

3.4.3. Doors (Basic)

Doors have a lot of advanced features, but this section will demonstrate the simple use case.

Doors require a 'from' and 'to' locations, same as block path, but doors don’t require an activation condition (like block_when_exists, block_when_not_carried, etc).

Doors might simply be open and close doors, but most doors require a key.

A Locked Door
barriers {
   shed_door : door {
      from  = garden
      to    = shed
      key   = shed_key
   }
}

Doors are closed and locked by default. A door defined without a key will not be locked, and will not be lockable or unlockable.

The identifier for doors is currently (like object identifiers). It does not imply a noun or an adjective.

Each room is currently only permitted to have one door, but in a future release, multiple doors per location will be permitted. This may not be appropriate for example for multiple doors in a corridor (yet).

3.5. Events

When things happen inside an adventure games, those things are called events.

For example, when the game starts, that is an event. When the player types something that is an event. Whe the player moves to a new location or redescribes the current location, that is an event. When the player types something in (or speaks to the game), that is an event.

The most common and useful event handlers are documented here.

3.5.1. on_startup {}

The startup event handler is executed when starting a new game. \

It is NOT executed when reloading a saved game. It is only executed once per NEW GAME, and before any other event handler.

Note
We use the ": print" and ": press_any_key" commands here, to read more about commands, click here .
on_startup {
   : print "Welcome to the world of nuts and bolts !!!!";
   : press_any_key ;
}

3.5.2. on_command {}

The on_command{} event handler is used to process a submitted command entered by the player.

The on_command{} event handler usually contains : match {} records, which look for specific verb and noun combinations. The _ character acts like a wildcard, and will match anything or nothing. The * character is also a wildcard, represents something. The - character can be used to specify nothing.

Adventuron ignores zero inputs by default, so handling : match "- -" will not work.

on_command {
   : match "throw rug" {
      : if (is_carried "rug") {
         : print   "You throw the rug, the rug is now gone.";
         : destroy "rug";
      }
   }
}

3.5.3. on_pre_describe {}

On pre describe is a block of code that is executed when BEFORE describing a location (entering a new location or redescribing it).

This block will execute before the any part of the location is described (graphic, object list, exit list, description).

A done executing in this block will not stop the rendering of the location.

Beware of using redescribe in this block (adventuron will detect redescribe recursion and report it).

If your location description contains some dynamic elements you can use this block to update those elements first, or possibly implement 'floating' objects that can follow the player around.

on_pre_describe {
   : if (is_just_entered() && is_at "forest_zone") {
      : create "owl"; // Creates the owl in every forest location as the player moves
   }
}

3.5.4. on_describe {}

On describe is a block of code that is executed when describing a location (entering a new location or redescribing it). It can be used to embelish a location description, or to trigger game events.

Note
The on_describe{} block is not available if "template = talp" is specified currently.
on_describe {
   : if (is_at "ice_cavern" && has_created_fire == false) {
      : print "You shiver.";
   }
}

3.5.5. on_tick {}

On tick is a block of code that is executed before processing the next command (prior to the prompt re-appearing). The on_tick event can be used to perform NPC actions in the world, and is executed every turn.

on_tick {
   : if (is_tune_stuck_in_head == true) {
      : print "You whistle the tune.";
   }
}

3.5.6. on_debug {}

On debug is executed instead of on_startup{} (if defined). It is used for debugging particular scenerios in a game.

on_debug {}, if used, should be commented out before packaging a game for release.

on_debug {
   : goto     "castle";
   : create   "elf";
   : set_true "has_learned_elf_song";
}

3.5.7. Local Handlers

Note
Local Event Handlers are not compatible with 8-bit compatibility mode.

A location can also define its own local event handlers. These event handlers only trigger for when the player is present in a given location, and are executed before the global handlers.

Local handlers are useful if the author wishes to code location-specific logic in a single place. It also means that the author doesn’t need to code is_at() conditions if the code is located underneath the location.

How to define local event handlers
locations {
   bottom_of_hill : location "You are standing at the bottom of the hill." {

      on_command {
         // Local command handlers here
      }

      on_describe {
         // Local description events here
      }

      on_tick {
         // Local tick events here
      }

   }
}

3.6. Text Matching

A match record is always (for now) in the format

: match "verb noun" {
   // Do something
}

It is a short form of writing something like:

: if (verb_is "verb" && noun1_is "noun") {
   // Do something
}

In real use, it uses real verbs and real nouns, such as:

: match "read sign" {
   // Do something
}

which can also be expressed as:

: if (verb_is "read" && noun1_is "sign") {
   // Do something
}

You can also use a semi colon to add additional verb noun patterns to match. Any number of verb noun pairs can be listed using ';' as the delimiter.

: match "read sign;examine sign" {
   // Do something
}

which can also be expressed as:

: if ( (verb_is "read" && noun1_is "sign") || (verb_is "examine" && noun1_is "sign") ) {
   // Do something
}

In match records the following symbols can be used to test for the following conditions

  • * Must include a value in this slot (verb or noun).

  • - Must not include a value in this slot (verb or noun).

  • _ May or may not include a value in this slot (verb or noun).

start_at = my_location

locations {
   my_location : location "";
}

on_command {
   : match "yawn -"  { : print "Yawn 1." ; }
   : match "yawn _"  { : print "Yawn 2." ; }
   : match "yawn *"  { : print "Yawn 3." ; }
}

The results are as follows:

match

3.7. Commands

Commands represent things that adventuron can do.

Adventuron can do lots of things, like show some text on the screen, show a graphic, make a beep, destroy an object in the game, make a new object in the game, put something in the players pocket, add a number to another number, and many many more.

When you code in Adventuron, you write lists of commands to perform in response to events (and possibly in response to something the player typed or spoke).

Certain commands can contain other commands, such as 'if' commands and 'while' commands. These commands often add a 'condition' for running the inner commands, and this type of code is called 'conditional' logic.

3.7.1. Control Of Flow Commands

Name Description

: match "VERB NOUN" {}

Matches a verb and noun, and executes the contained commands if the current logical sentence matches the verb and noun.

: if (CONDITION) { …​ }

Executes the inner commands {…​} IF the supplied boolean condition is true.

: else_if (CONDITION) { …​ }

If all immediately preceeding if and else_if statements evaluate to false in their conditions, and the else_if’s condition evaluates to true, then execute the inner commands.

: else { …​ }

If all immediately preceeding if and else_if statements evaluate to false in their conditions, then execute the inner commands.

: while (CONDITION) {…​}

While the condition evaluates to true, keep executing the inner commands. NOTE: Adventuron does not yet have a BREAK command, so a while loop can be only be exited via its top condition.

: gosub "SUBROUTINE_ID";

Execute subroutine with the supplied subroutine id.

: done ;

Stops executing the current event handler, no further items are evaluated.

: return ;

Stop executing the current subroutine and return to the calling handler.

: nope ;

Print the system message like "You can’t do that", and then acts like : done (Stops executing the current event handler, no further items are evaluated).

3.7.2. Common Commands

Adventuron has many advanced commands, but these commands are the most commonly used commands.

Name Description

: print "message text" ;

Prints the given message. If you want to seperate a paragraph use the text \n. To learn about other text layout and formatting codes, click here.

: tutorial "tutorial text" ;

Same as the print command, but will style the text with the 'tutorial' text colour (as defined in the current theme), and will also prefix the tutorial_prefix_text (as defined in the theme / system_properties).

: append "message text" ;

Prints the given message, but does not start a new paragraph.

: goto "LOCATION_ID" ;

Moves the player character to the given location (does not redescribe).

: goto "back" ;

Moves the player character to location that were in prior to the current location and removes the item from the 'back buffer'. You can step backwards through your steps, up to 32 steps, after which, nothing will happen.

: pause "MILLISECONDS" ;

Pauses the game the nominated amount of milliseconds.

: beep millis="MILLISECONDS" pitch="PITCH";

Plays the nominated pitch for the nominated amount of milliseconds. 0 is middle C.

: success ;

Plays a success 'jingle' sound (if enabled in the theme settings). Click here for more information.

: failure ;

Plays a failure 'jingle' sound (if enabled in the theme settings). Click here for more information.

: press_any_key ;

Wait until the player presses ENTER, SPACE, touches the screen, or clicks the mouse.

: inventory ;

Shows the objects that the player character is holding.

: save ;

Shows the save game dialog.

: load ;

Shows the load game dialog.

: create "OBJECT_ID" ;

Creates the object with the given id in the current location. If the object already exists somewhere else, it is moved to the present location.

: create "OBJECT_ID" target = "LOCATION_ID" ;

Creates the object with the given id in nominated location. If the object already exists somewhere else, it is moved to the nominated location.

: create "OBJECT_ID" target = "inventory" ;

Creates the object with the given id in the player inventory. A weight or item limit check is not performed.

: destroy "OBJECT_ID" ;

Destroys the object with the given id. If held it is removed from the inventory. Destroying moves the object to a special non-existence location.

: set_true "BOOLEAN_ID" ;

Sets the boolean variable with the given id to contain a true value.

: set_false "BOOLEAN_ID" ;

Sets the boolean variable with the given id to contain a false value.

: toggle "BOOLEAN_ID" ;

Toggles the boolean variable with the given id (if it currently contains true, then it it set to false, if it currently contains false, then it is set to true).

: add var = "INTEGER_VAR" value = "VALUE" ;

Adds a value onto the current value of an integer.

: store_random var = "INTEGER_VAR";

Puts a random value between 0 and 99 inclusive in the integer variable.

: set_integer var = "INTEGER_VAR" value = "VALUE" ;

Sets an integer variable to be the supplied value.

: set_string var = "STRING_VAR" value = "VALUE" ;

Sets a string variable to be the supplied value.

: increment "INTEGER_VAR";

Increments the value in the referenced integer variable. If the integer variable’s max value will be exceeded, then do nothing.

: decrement "INTEGER_VAR";

Decrements the value in the referenced integer variable. If the integer variable’s min value will be exceeded, then do nothing.

: swap o1 = "OBJECT1_ID" o2 = "OBJECT2_ID" ;

Swaps the location of object1 and object2. Swap will also swap the existence of object 1 and object 2. Swap will also swap the existence status of an object with the second object.

: redescribe ;

Flags to Adventuron that it should redescribe the current location, and stops executing the current event handler. This will retrigger on_describe{} and on_tick{} from the top of both of the tables.

: lose_game ;

Prompts the player to press any key (Enter key, space bar, touch or mouse click), then the game restarts - display intro screen/graphic, call on_startup{}, etc. Will also play the lose jingle if configured via the theme.

: win_game ;

Prompts the player to press any key (Enter key, space bar, touch or mouse click), then the game restarts - display intro screen/graphic, call on_startup{}, etc. Will also play the win jingle if configured via the theme.

: end_game ;

DEPRECATED - Prompts the player to press any key (Enter key, space bar, touch or mouse click), then the game restarts - display intro screen/graphic, call on_startup{}, etc. (deprecated - use win_game, or lose_game instead)

: set_graphic graphic = "GRAPHIC_ID" target = "LOCATION_ID" ;

Changes the default graphic for a location to a different graphic (visible upon next redescribe). The changed graphic will permanently be changed upon revisits or redescribes of the location.

: set_graphic graphic = "GRAPHIC_ID" target = "LOCATION_ID" immediate="true";

Changes the default graphic for a location to a different graphic (immediate update in place on screen). The changed graphic will permanently be changed upon revisits or redescribes of the location.

NOTE: This mode only really makes sense if locking the image to the top of the screen using layout = H G LOCK D X O or similar, otherwise you may be updating a graphic that has already scrolled off screen.

: print_graphic ;

Prints the current location graphic.

: print_graphic "GRAPHIC_ID";

Prints the referenced graphic directly to the screen.

: update_graphic "GRAPHIC_ID"

Changes the graphic in the 'banner' location (location graphic of the screen), to a new image. This will not be remembered when re-visiting a location, it only applies to the current screen presentation. No other UI elements are refreshed (unless possibly in auto-redescibe mode).

NOTE: This mode only really makes sense if locking the image to the top of the screen using layout = H G LOCK D X O or similar, otherwise you may be updating a graphic that has already scrolled off screen.

: get;

Gets the object that corresponds to the adjective and noun in the current parse sentence (only if object is available, and takeable in the current location).

By default, this will print a message if the object is taken, or if the object can’t be taken for some reason (too many items, not a takeable object).

: drop;

Drop the object that corresponds to the adjective and noun in the current parse sentence (only if object is available, and takeable/droppable in the current location).

By default, this will print a message if the object is dropped, or if the object can’t be dropped for some reason (not holding the object for example).

: get "OBJECT_ID";

Gets the object that corresponds to supplied object id (only if object is available, and takeable in the current location).

By default, this will print a message if the object is taken, or if the object can’t be taken for some reason (too many items, not a takeable object).

Note: This command will perform weight checks by default but these checks can be disabled in the game settings. Be very careful if using this command then moving the player immediately somewhere else. If the player can’t hold the item you are taking for them, the item may end up inaccessible (if the player can’t return to the location where the item was given). Consider the : pocket "object_id" command instead which is fail-safe.

: get "OBJECT_ID" quiet="true";

Gets the object that corresponds to supplied object id (only if object is available, and takeable in the current location).

If quiet="true" is specified, then getting will not print the default get message (from the theme system messages). A message will always be printed if a get is not possible.

Note: This command will perform weight checks by default but these checks can be disabled in the game settings. Be very careful if using this command then moving the player immediately somewhere else. If the player can’t hold the item you are taking for them, the item may end up inaccessible (if the player can’t return to the location where the item was given). Consider the : pocket "object_id" command instead which is fail-safe.

: drop "OBJECT_ID";

Drops the object that corresponds to supplied object id (only if object is available, and takeable/droppable in the current location).

By default, this will print a message if the object is dropped, or if the object can’t be dropped for some reason (not holding the object for example).

: drop "OBJECT_ID" quiet="true";

Drops the object that corresponds to supplied object id (only if object is available, and takeable/droppable in the current location).

If quiet="true" is specified, then dropping will not print the default drop message (from the theme system messages). A message will always be printed if a drop is not possible.

: examine;

Examines the object that corresponds to the adjective and noun in the current parse sentence (only if object is present).

By default, this will print the examine message (or execute the examine event handler) associated with the object.

: examine "OBJECT_ID";

Examines the object that corresponds to the adjective and noun in the current parse sentence (only if object is present).

By default, this will print the examine message (or execute the examine event handler) associated with the object.

: pocket "OBJECT_ID";

Creates an item and attempts to place it in the players pocket (or inventory), silently, if there is enough space in the inventory (uses weight + item limits).

If the player cannot take the object (too heavy or holding too many items), then the object is created in the location where the player is located when the location is redescribed or the prompt is redisplayed (whichever comes first).

If the object is placed in the inventory successfully, the operation will be quiet (no messages printed), if placing fails, then the appropriate error message (You’re holding too many items, you’re can’t take that) will be displayed.

If trying to pocket an item that the player already holds, then pocket does nothing (no error, prints nothing, just does nothing).

Pocket failing does not stop execution of subsequent commands.

: wear;

Wears the object that corresponds to the adjective and noun in the current parse sentence (only if object is available, and wearable).

: unwear;

Takes off (unwear) the object that corresponds to the adjective and noun in the current parse sentence (only if object is worn, and removable).

: wear "OBJECT_ID";

Wears the object that corresponds to supplied object id (only if object is available, and wearable).

: unwear "OBJECT_ID";

Takes off (unwear) the object that corresponds to supplied object id (only if object is worn, and removable).

: door_operation

door = "DOOR_ID"
operation = "OP" ;

Manually manipulate the state of a door barrier.

The operations with an underscore indicates that two state changes will occur at the same time. By default, these operations are silent (even if trying to unlock a non lockable door, or opening an open door, etc.).

OPS: ( open_unlock | lock_close | close | unlock )

: set_theme "THEME_ID";

Changes the current theme of the game to the specified theme, instantly updating the screen style but not updating the screen content or issuing a redescribe.

: ask_bool question = "QUESTION TO ASK?" var = "BOOL_VAR";

Asks a question and stores the result in a boolean variable.

: ask_int question = "QUESTION TO ASK?" var = "INT_VAR" min = "0" max = "10" ;

Asks for an integer (a number) in a range and stores in an integer variable. Min and max must be specified.

: ask_string question = "QUESTION TO ASK?" var = "STRING_VAR" empty_is_ok = "false" ;

Asks for a string (some text) and stores in an string variable.

: set_sentence "replacement sentence";

This will replace the current sentence with the sentence inside the double quotes. $1 can be used to substitute subject1 (adjective1, noun1), and $2 can be used to substitute subject2 (adjective2, noun2). Before substituting with patterns such as $1 and $2.

NOTE: If you call set_sentence, then you must call : disambiguate_s1; or : disambiguate_s2; immediately afterwards if you want to use any s1 or s2 functions subsequently.

(This is an advanced command).

3.7.3. Advanced Commands

These commands use the Expression Form, which will be documented more fully in a later version of the document.

Name Description

: set_string var = "STRING_VAR" {("Some " + " String " + "Expression")}

Sets a string variable to be the result of the supplied expression.

: set_integer var = "INTEGER_VAR" {( 1 + 2 + 3 )}

Sets an integer variable to be the result of the supplied expression.

3.8. Variables

3.8.1. Booleans

Boolean Variables

Booleans can be referred to simply by using the identifier of the variable inside an expression block.

e.g.

booleans {
   has_brushed_teeth : boolean "false";
}

Now inside the on_tick{} method we can write this logic.

: match "brush teeth" {
    : if (is_at "bathroom") {
       : if (has_brushed_teeth) {
          : print "You already brushed your teeth!";
       }
       : else {
          : print "You brush your teeth.";
          : set_true "has_brushed_teeth";
       }
    }
}
Boolean Operators

Boolean functions can be used inside boolean expressions.

NOTE : In this table expression1 and expression2 refer to boolean expressions.

NOTE2 : Expressions can be surrounded by () characters,to clarify the order of evaluation.

Name Operator Description

expression1 && expression2

AND

Return true if expression1 AND expression2 returns a TRUE value.

expression1 || expression2

OR

Return true if expression1 OR expression2 returns a TRUE value.

!expression1

NOT

Return true if expression1 returns a FALSE value.

expression1 == true

EQUALITY

Return true if expression1 returns a TRUE value.

expression1 == false

EQUALITY

Return true if expression1 returns a FALSE value.

expression1 != true

NON-EQUALITY

Return true if expression1 returns a FALSE value.

expression1 != false

NON-EQUALITY

Return true if expression1 returns a TRUE value.

Boolean Functions

Boolean functions can be used inside boolean expressions.

This is a non-exhaustive list, as many of the newer commands are experimental.

Name Description

is_at "LOCATION_ID"

Returns true if the player is at the referenced location.

is_present "OBJECT_ID"

Returns true if the referenced object is present (in the current players inventory, or in the current location).

is_beside "OBJECT_ID"

Returns true if the referenced object is in the current location.

is_exists "OBJECT_ID"

Returns true if the referenced object exists somewhere in the game world.

is_carried "OBJECT_ID"

Returns true if the referenced object is carried (in the current players inventory or within an accessible container held by the player).

is_holding "OBJECT_ID"

Returns true if the referenced object is directly carried by the player (not inside or atop of another held object of the player).

is_worn "OBJECT_ID"

Returns true if the referenced object is carried and worn by the player.

is_treasure "OBJECT_ID"

Returns true if the referenced object is a treasure.

is_pocketable "OBJECT_ID"

Returns true if when hypothetically taking an object it would not exceed weight or item carry limits (to be taken). If the referenced item is held by the player, then this function will return true, and a subsequent call to ": pocket" will simply do nothing. This function should not be used to test if an item is already in the inventory.

has_not_created "OBJECT_ID"

Returns true if the referenced object id has not been created (never been created one time or more). This can be useful if guarding a part of the code that creates the object, to ensure it can never be created more than once - even if it is destroyed later in the game.

is_within { outer = "location_or_zone_id" inner = "object_id" }

Returns true if the inner is within the outer .

has_stashed_all_treasure ()

Returns true if all the treasure is currently in the treasure room.

has_visited "LOCATION_ID"

Returns true if has visited location before.

is_locked "DOOR_ID"

Returns true if the referenced door is locked, false if it is unlocked.

is_blocking "DOOR_ID"

Returns true if the referenced door, block, or block_path is currently blocking. You can use this to test if a door is open or closed too.

is_can_go(1 .. 12)

Returns true if there is a unblocked connection from the current location to another location in the direction represented by the number (1 to 12). If provided number is not between 1 and 12, then this function will return false.

1 = north, 2 = northeast, 3 = east, 4 = southeast, 5 = south, 6 = southwest, 7 = west, 8 = northwest, 9 = up, 10 = down, 11 = enter, 12 = exit

is_at_initial_location "OBJECT_ID"

Returns true if the referenced object is at the same location where it was placed at the start of the game (not including any movements that happen in the on_startup{} handler).

is_just_entered ()

Returns true if the player just entered the current location (the location id is different to the location id in the previous tick).

is_first_entered ()

Returns true if the player just entered the current location for the first time. NOTE : This command will always return false if used from an on_command{} event handler.

is_mobile()

Returns true if the current client is running on a smartphone. This should return false for tablets.

is_int(STRING_EXPRESSION)

Returns true if the string expression contains an integer number

chance (n)

Returns true, n % of the time. (n is a value or an expression that evaluates to a number between 0 and 100).

noun1_is "noun"

Returns true if the 1st noun in the sentence equals the provided noun (or synonym).

Note that any noun in a noun group can be used between the double quotes here, and it will compare noun1 of the sentence with all members of the group.

noun2_is "noun"

Returns true if the 2nd noun in the sentence equals the provided noun (or synonym).

Note that any noun in a noun group can be used between the double quotes here, and it will compare noun2 of the sentence with all members of the group.

adjective1_is "adjective"

Returns true if the 1st adjective in the sentence equals the provided adjective (or synonym).

Note that any adjective in a adjective group can be used between the double quotes here, and it will compare adjective1 of the sentence with all members of the group.

adjective2_is "adjective"

Returns true if the 2st adjective in the sentence equals the provided adjective (or synonym). The second adjective must always come after the first noun.

Note that any adjective in a adjective group can be used between the double quotes here, and it will compare adjective2 of the sentence with all members of the group.

preposition_is "preposition"

Returns true if the preposition in the sentence equals the provided preposition (or synonym).

Note that any preposition in a preposition group can be used between the double quotes here, and it will compare preposition of the sentence with all members of the group.

verb_is "verb"

Returns true if the verb in the sentence equals the provided verb (or synonym).

Note that any verb in a verb group can be used between the double quotes here, and it will compare verb of the sentence with all members of the group.

adverb_is "adverb"

Returns true if the adverb in the sentence equals the provided verb (or synonym).

Note that any adverb in a adverb group can be used between the double quotes here, and it will compare adverb of the sentence with all members of the group.

3.8.2. Integers

Adventuron supports use of integer (whole number numeric) expressions.

Integer Variables

Integers can be referred to simply by using the identifier of the variable inside an expression block.

e.g.

integers {
   num_times_visited_hut : integer "0";
}

Now inside the on_tick{} method we can write this logic.

: if (number_times_visited_hut > 5) {
   : print "You really like this hut !";
}

(assume the number_times_visited_hut variable is incremented somewhere else in the code).

Integer Assignment Commands
Note
The integer variable must be declared in the integers{} section to be able to be assigned.

You can set an integer to a fixed value as follows:

: if (is_at "lair") {
   : set_integer var = "wolves_countdown"  value = "5" ;
}

You could build the number 5 from an expression if you wanted:

Advanced (can ignore if beginner)
: if (is_at "lair") {
    : set_integer var = "wolves_countdown"  {( 1 + 2 + 2 )}
}

You can reference variables on the right hand side if you want:

Advanced (can ignore if beginner)
: if (is_at "lair") {
    : set_integer var = "wolves_countdown"  {( some_other_int_var + 5 )}
}
Integer Operators
Name Operator Result Type Description

expression1 + expression2

+ (add)

Integer

Returns a value obtained by adding the integer result of expression1 and the integer result of expression2.

expression1 - expression2

- (subtract)

Integer

Returns a value obtained by subtracting the integer result of expression2 from the integer result of expression2.

expression1 * expression2

* (multiply)

Integer

Returns a value obtained by multiplying the integer result of expression1 and the integer result of expression2.

expression1 / expression2

/ (divide)

Integer

Returns a value obtained by dividing the integer result of expression1 by the integer result of expression2. Fractional parts are ignored (full integer result).

expression1 % expression2

% (modulo)

Integer

Returns the remainder of the value obtained by dividing the integer result of expression1 by the integer result of expression2.

Integer Functions

This is an abbreviated list of integer functions available in Adventuron.

Name Description

abs(EXPRESSION)

Returns a positive (absolute) version of the value returned by resolving the inner expression (always 0 or above).

locno()

Returns the locations number of the current location. If the current location does not have a location number, the will return a value less than 0.

carried()

Returns the number of items carried by the player excluding worn items (shallow).

worn()

Returns the number of items worn by the player (shallow).

(carried()+worn())

A count of all items held, and all items worn by the player (shallow).

carry_limit()

Returns the limit of the number of items that are permitted to be carried by the player. By default in adventuron, worn items are counted towards this limit.

worn_limit()

Returns the limit of the number of items that are permitted to be worn by the player. NOTE: Only use this if configured that wear and carry limits are seperate in game_settings{}, or else using this will result in an error.

linger()

Returns the number of ticks that the player has been in the current location since arriving (this is reset to zero upon entering a new location). This can be useful for per-location timed events, or messages.

ticks()

Returns the number of ticks that have been performed in the game. This will return 0 in the on_startup {} block, but the first time on_tick is executed, ticks() will contain a value of 1, incrementng by one every time the on_ticks() block is executed.

turns()

Returns the number of turns that have been performed in the game. This is the number of individual sentences processed by on_command(). This is incremented BEFORE on_command() runs. Note that a GET ALL or DROP all will be processed as multiple sentences.

inputs()

Returns the number of words the player entered

random()

Returns a number between 0 and 99 (inclusive).

random(999)

Returns a number between 0 and 999 (inclusive).

index()

The current index in a collection_iterate loop.

distance_to "LOCATION_ID"

Returns the shortest number of moves required to move to the nominated location from the current location. If the location is the same location as the current player location, then return 0, if there is no path, then returns -1, otherwise will return an integer number. Can be useful for environmental messages.

treasure_total()

Returns the total amount of treasure objects defined in the game (set the treasure="true" attribute on an object).

treasure_deposited()

Returns the total amount of treasure currently located in the treasure destination location.

weigh(OBJECT_ID)

Returns the weight of an object and contained objects (if the provided object is a container).

weigh_solo(OBJECT_ID)

Returns the weight of an object not including contained objects.

Integer Ranges

By default, an integer has a minimum value of 0. If you wish to use an integer to hold negative values then use the min="" parameter when declaring your integer.

The ABSOLUTE minumum and maximum values that an integer variable can hold are -2,147,483,648 and 2,147,483,647 (inclusive) respectively.

3.8.3. Strings

String Functions
Name Description

current_location()

Returns the id of the location the player is currently

original "verb"

Returns the verb that the player entered (untrimmed and unaliased). If the player types one word, then this is always the original verb.

original "noun1"

Returns the first noun that the player entered (untrimmed and unaliased). If the player types one word, then this may be empty. It will never be empty if the player types two words, but it may be empty if the player types three or more words and none of those words are matched nouns. When typing two words, one word is always understood as a verb and one word is understood as a noun, whether or not the verb or noun are found in the vocabulary.

parent_of "entity_id"

Returns the direct parent of an object or entity (can be a location id, an object id, 'inventory', or 'ether'. If an invalid item is specified, then "unknown" is returned. If the item is carried by the player then 'inventory' will be returned. If the item does not exist, then "ether" will be returned (ether is the parent of non exitent objects).

previous_location()

Returns the id of the location the player was in in the last tick.

item()

The current item in a collection_iterate() loop.

d()

Returns the description of the current location.

d(param1)

Returns the description of the named objects, scenery, location or page item.

definite("red_key")

Returns a definite article version of object with id "red_key". e.g. if object with id "red_key" will have description of "a red key" ('a' is an indefinite article), then this function will return "the red key" ('the' is a definite article).

strip_article("red_key")

Returns a no article version of object with id "red_key". e.g. if object with id "red_key" will have description of "a red key" ('a' is an indefinite article), then this function will return "the red key" ('the' is a definite article). Note that this function only strips indefinite articles so your object descriptions should always be specified as indefinite.

upper(param1)

Converts some input text to upper case. e.g. upper("text") would return 'TEXT'.
e.g. d("lamp") might return 'a dusty old lamp', if there existed an object with id 'lamp' that had description 'a dusty old lamp'.

lower(param1)

Converts some input text to lower case. e.g. upper("TEXT") would return 'text'.

title_case(param1)

Capitalises the first letter of every word. e.g. upper("i am GOOD") would return 'I Am Good'.

first_cap(param1)

Capitalises the first letter of a string. e.g. first_cap("i am GOOD") would return 'I am GOOD'.

Basic setting of a string:
: set_string var="nice_location_description" text="I don't know where I am.";
Advanced setting of a string (expression form):
Warning
Feel free to ignore, this is advanced behaviour.

We can use EXPRESSION FORM to dynamically calculate the value of a string.

  • An expression can be contained between "{(" and ")}" (without quotes).

  • + is used to append.

  • current_location() in the example is a string function that returns the id of the current location.

: set_string var="nice_location_description" {(
   "I am in location with id " + current_location()
)}
Appending to a string variable
Warning
Feel free to ignore, this is advanced behaviour.

Assuming we have a string with id "tmp" that contains the text "foo".

// After this, tmp has value of "Foo bar"
// (without quotes)

: set_string var="tmp" {( tmp + " bar" )}
Dynamically setting the value of a string
Warning
Feel free to ignore, this is advanced behaviour.

Printing the contents of a variable is possible using the expression form, which is a contained by these brackets as shown {( )}.

start_at = village

locations {
   village  : location "You are in the village. Type SCORE to see your score." ;
}

integers {
   // Set the default score to zero here
   score : integer "0" ;
}

on_command {
   : match "score _"  {
      // Note that CONTROL + SPACE only works on blank lines in these blocks
      // Pressing CONTROL + SPACE once will show string functions only
      // Pressing CONTROL + SPACE twice in a row will show all functions (integer, string, and boolean functions)
      : print {(
         "Your score is " +
         score +
         "."
      )}
   }
}

3.9. Ternary Operators And Typing

Adventuron supports a useful type of if then else statement that can be used within if statements and other places were expressions are used.

boolean_expression ? value_if_true : value_if_false

The value_if_true and value_if_false can be string, boolean, or integer types. They can also be subexpressions.

Here is a small piece of code involving a ternary operator.

start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

on_tick {
   : print {(
      turns() < 3 ? "Keep typing wait." : "You typed wait enough"
   )}
}

3.9.1. Advanced example

Ternary operators can also be used to build complex strings.

The following example lets the "player" toggle the values of 4 boolean variables by typing a, b, c, or d. One unconditional print statement is executed per tick. The conditional logic is found in the string expression itself via multiple ternary operator blocks.

The "<enabled<12>>" blocks of code colour code the output (see text formatting later in this document). Click here to learn more about text formatting codes.

start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

booleans {
   a : boolean "false";
   b : boolean "false";
   c : boolean "false";
   d : boolean "false";
}

on_command {

   // A is usually filtered out by the parser in the english language
   // so we use the raw sentence here
   : if (sentence_raw() == "a")  { : toggle "a" ; }

   : match "b _"  { : toggle "b" ; }
   : match "c _"  { : toggle "c" ; }
   : match "d _"  { : toggle "d" ; }
}

on_tick {
   : print {(
       "A : " + (a ? "<enabled<12>>" : "<disabled<10>>") + "\n" +
       "B : " + (b ? "<enabled<12>>" : "<disabled<10>>") + "\n" +
       "C : " + (c ? "<enabled<12>>" : "<disabled<10>>") + "\n" +
       "D : " + (d ? "<enabled<12>>" : "<disabled<10>>") + "\n"+
       "Number of true expressions : " +
       ( (a ? 1 : 0) + (b ? 1 : 0) + (c ? 1 : 0) + (d ? 1 : 0) )
   )}
}

3.10. Loops

A 'while' loop is used to repeat a set of commands until a particular condition is satisfied.

It can be used for a variety of purposes including performing calculations, and to validate inputs.

3.10.1. Input validation with a While loop

A basic while loop can be used to validate some kind of input.

start_at  = location

locations {
   location : location "You win, the answer is indeed {answer}!" ;
}

strings {
   answer : string "" ;
}

on_startup {
   : while (lower(answer) != "paris") {
      : ask_string question = "What is the capital of France?"  var = "answer" ;
   }
}

3.10.2. Calculations Using A While Loop

While loops can be used within while loops, as in the example shown below, which prints out the times tables.

start_at = my_location
locations { my_location : location "Type <TEST<4>>" ; }

integers  {
   x : integer "1" ;
   y : integer "1" ;
}

on_command {
   : match "test _"  {
      : print "Start While" ;
      : set_integer var = "x"  value = "1" ;
      : while ( x <= 12 ) {
         : set_integer var = "y"  value = "1" ;
         : while ( y <= 12 ) {
            : print {(x + " x " + y + " = " +(x*y) )}
            : increment"y";
         }
         : increment"x";
      }
      : print "End While" ;
   }
}

3.11. Inventory Limits

By default, Adventuron supports holding 10 items in the inventory, and 200 weight units (more on that later).

If you wish to change this, then you must setup an inventory limit in the game settings (not to be confused with the theme settings).

Upon executing the snippet below, type GET ALL at the prompt.

start_at = village

locations {
   village  : location "You are in the village" ;
}

objects {
   lamp  : object "a lamp"  at = "village" ;
   pen   : object "a pen"   at = "village" ;
   sword : object "a sword" at = "village" ;
   rock  : object "a rock"  at = "village" ;
}

integers {
   inventory_limit : integer "3" ;
}

game_settings {
   // By referencing an integer, we can dynamically change this limit in-game
   // using : set_integer, or using a dynamic integer.
   inventory_items_limit_var = inventory_limit
}

3.12. Common Patters

In this section we explore some common code patterns. For more advanced code patterns, search for "Cookbook" in this document (advanced users only).

3.12.1. One-time Object Creation

It’s very common operation for wanting to create an object when examining something for the first time. If an object is created one time, even if it is destroy subsequently, then has_not_created will return false.

start_at = village

locations {
   village : location "You are in the village." ;
}
objects {
   letter : object "a letter" ;
   postbox : scenery "a postbox" at = "village" ;
}

on_command {
   : if_examine "postbox"  {
      : if (has_not_created "letter") {
         : create "letter" ;
         : print "You notice a letter stuck in the postbox" ;
         : press_any_key ;
         : redescribe;
      }
   }
}

3.12.2. Keeping Score

To keep score use an integer to keep track of the score.

To print a score, use the advanced version of print. This version of print requires {( )} brackets as shown below. A piece of text to be printed is still surrounded by double quotes, but variables can now be referenced in this form. Append parts of the text together with the "+" operator as shown.

Feel free to experiment with this sample.

start_at = village

locations {
   village  : location "You are in the village.\nType JUMP to increase your score, type SCORE to see your score." ;
}

integers {
   // Set the default score to zero here
   score : integer "0" ;
}

on_command {
   : match "jump _"  {
      : if (score < 20) {
         : increment "score" ;
         : print "You do something very impressive" ;
      }
   }
   : match "score _"  {
      : print {(
         "Your score is " + score + "."
      )}
   }
}

3.13. Load / Save

Save games use the Local Storage mechanism built into modern browsers. Seamless saving and loading is dependant on setting up the game_information section properly.

If you have multiple games on the same website, then you need to setup the game_information to ensure that games won’t share the same save data.

Replace all upper case fields with your specific information

game_information {
   game_name                    = YOUR GAME NAME
   game_version                 = 0.5.0
   game_shortname               = SHORT GAME NAME
   written_by                   = YOUR NAME
   uuid                         = UNIQUE UUID
   year_of_release              = 2019
   copyright_message            = YOUR COPYRIGHT MESSAGE
   short_synopsis               = ONE SENTENCE DESCRIPTION OF GAME.
}

The UUID must be unique, as it is used to make sure that the save game information can be found if you change the short name of your game.

To calculate a unique UUID, consider using this website:

Note
Adventuron will complain if you have not set up the game_information{} section when you compile, to help you remember to do this.

Things You Need to do:

  • Create The game_information{} section.

  • Setup a UNIQUE uuid in the game_information {} section. It is EXTREMELY IMPORTANT for the uuid to be unique. (generate a unique UUID here : https://www.uuidgenerator.net/ )

  • Set the game_shortname to a unique name.

There are 5 save game slots.

Slot 0 - Autosave
Slot 1 - User Slot 1
Slot 2 - User Slot 2
Slot 3 - User Slot 3
Slot 4 - Ramsave Slot

This save date will save using browser local storage (for the website domain).

The key for the save slot is as follows (taken from game information settings):

[uuid or short game name].[gameversion].[domain].[slotnumber]

To avoid conflicts, please make a unique uuid identifier and/or game name.

If serving from Itch, then the domain will be of the virtual server that serves the iFrame. This will be unique per Itch account.

3.13.1. Autosave

If a game has the game_information {} set up, then the game will start to autosave after the first move. Going back to the same domain will display the loading screen, then after pressing enter or clicking the screen it will take the player back to the exact moment they left off.

The game is actually saved immediately as a prompt appears. The state is snapshotted, compressed, and saved every turn.

When reloading, the screen is re-rendered as it was (saved as part of the snapshot), then the prompt is redisplayed without any ticks taking place.

Autosave is supplemental to the save slot mechanism.

3.13.2. Regular Saving

If the player types "SAVE" then the player will be asked to select one of 3 slots, or to select a 4th option (cancel). If selecting a pre-existing slot, Adventuron will confirm if the player wants to overwrite the game in that slot. Saving will save the state from the turn before SAVE was entered, and will save everything, including the current screen contents.

To reload, type "LOAD" and select the slot you wish to load from. Or select the 4th option to cancel the load.

3.13.3. Ram Saving

A ramsave works just like a regular save apart from it’s instant. To perform a ramsave, the player just types "ramsave".

It saves in a fixed 4th slot, and again, uses the previous snapshot just before the prompt was displayed.

A ramload again is instant. To perform a ramload, the player just types "ramload". Adventuron will loads the game from the ramsave snapshot and re-renders the screen as it was. No ticks are executed in the load as it was actually saved after the ticks were executed.

3.13.4. Incognito Mode

As you might expect, if using a browser in a private / incognito mode, that the save data will be erased when the browser is closed.

3.14. Graphics

To add a graphic to your game, select MENU / IMPORT from the Adventuron editor.

Graphics should be PNG or GIF files, and should be 60KB or less.

Graphics should aim to be about three times wider than they are all (for traditional text adventure layouts).

For more information about adding graphics to Adventuron games, check out this youtube video.

Location automatically assign a graphic to a location if the id of the location matches the id of a graphic (see CREATING A GRAPHIC section).

You can also set the graphic of a location explicitly via graphic="your_graphic_id" in the location definition.

Graphics for locations can be altered at runtime via the : set_graphic "new_graphic_id" command. This command is also compatible with the 8-bit export.

3.14.1. Printing Graphics

If you want to print a graphic, then it’s very simple.

The following example clears the screen, and prints a picture of a skull. By default, graphics stretch all the way across the screen.

Note
If you are developing in 8-bit compatibility mode, graphics (location and ad-hoc graphics) must all be the same size (aside from the loading screen).
Display a graphic that spans 100% of the text display area
   : print_graphic "skull";
Display a graphic that spans 50% of the text display area
   : print_graphic "skull" width="50";
Display a graphic that spans 50% of the text display area, and aligned to the left side of the screen
   : print_graphic "skull" width="50";
Display a graphic that spans 50% of the text display area, and aligned to the right side of the screen
   : print_graphic "skull" width="50" align="right";

3.14.2. Loading Screen

To set a loading screen for your game, simply add the following line to your game sourcefile:

loading_screen = my_loading_screen_graphic_id

In the context of a full game sourcefile:

start_at       = my_location

loading_screen = my_loading_screen_graphic_id

locations {
   my_location : location "You are in a room." ;
}

assets {
   graphics {
       my_loading_screen_graphic_id : placeholder;
   }
}
Note
In the above example, no image will be shown. Usually you should import a PNG or GIF via the IMPORT menu, or define a graphic in other ways shown in this document.

3.15. Text Formatting

Adventuron supports various codes that can be embedded into the text to style the text.

Some codes are as-yet undocumented whilst under review so only the stable codes will be listed here.

3.15.1. Referencing The Value Of Variable From A Normal Text Block

You can also use the {} form in regular text to import the value of a string variable.

start_at = village

strings {
   day_of_week : string "Wednesday" ;
}
locations {
   village  : location "You are in the village. It is {day_of_week}." ;
}
booleans {
   is_wednesday : boolean "false" ;
}

You can also use the {boolean ? if_true_string_var : if_false_string_var} form in regular text to import the value of a string variable.

start_at = village

strings {
   wednesday : string "Wednesday" ;
   not_wednesday : string "Not Wednesday" ;
}
locations {
   village  : location "You are in the village. It is {is_wednesday ? wednesday : not_wednesday}.\nType LOOK to refresh the dynamic location description." ;
}
booleans {
   is_wednesday : boolean "false" ;
}
on_tick {
   : if (is_wednesday) {
      : set_false "is_wednesday" ;
   }
   : else {
      : set_true "is_wednesday" ;
   }
}

3.15.2. Text Formatting Codes

Note
Firstly, the ' character (apostrophe) is not escaped. This is because it is a very commonly used character.

\n is used to represent a new paragraph (a linefeed).

A print statement usually ends in an additional linefeed (unless the text is empty).

// Will print \n is how we break paragraphs.
: print "This is paragraph one.\nThis is paragraph two.";

\\ is used to represent a \ character.

// Will print \n is how we break paragraphs.
: print "\\n is how we break paragraphs.";

\" is used to represent a " character.

// Will print "Hello", he said.
: print "\"Hello\", he said.";

Use ^^ if you want to print the ^ character explicitly.

// Will print 2^4 (two to the power of four) is 16.
: print "2^^4 (two to the power of four) is 16.";

Use {{ if you want to print the { character explicitly.
Use }} if you want to print the } character explicitly.

// Will print Define objects in the objects {} block.
: print "Define objects in the objects {{}} block.";

Use << if you want to print the < character explicitly.
Use >> if you want to print the > character explicitly.

// will print 2 < 5, 5 > 2.
: print "2 << 5, 5 >> 2.";

Use [[ if you want to print the [ character explicitly.
Use ]] if you want to print the ] character explicitly.

// will [think about it]
: print "[[think about it]]";

Use `` (backtick) if you want to print the ` character explicitly.

// will print `Toast`
: print "``Toast``";

3.15.3. Right Aligning Text

You can right align a paragraph using the ^r^ tag. All paragraphs forward of the ^r^ are formatted as right aligned.

: print "^r^This paragraph is right aligned.\nAlso right aligned.\n^l^This paragraph is left aligned.";

3.15.4. Centre Aligning Text

You can centre align a paragraph using the ^c^ tag.

: print "^c^This paragraph is centre aligned.\nAlso centre aligned.\n^l^This paragraph is left aligned.";

3.15.5. Removing the paragraph break

The ^n^ tag will remove verical margins between paragraph elements. This can be useful when printing a list.

Adding ^m^ at the end will restore the paragraph space after the final paragraph.

: print "^n^No paragraph break space between paragraph 1.\nNo paragraph break space between paragraph 2.\nNo paragraph break space between paragraph 1.^m^";

3.15.6. Printing with the default text colour

// This will (by default) be the story colour if
// printed in the location description, or in
// the on_describe{} block.
//
// This will be (by default) the response colour
// (and if that is not set the story colour), if
// printed in the on_tick{} or on_post_tick {}
// blocks.
//
// This will be (by default) the warn colour
// (and if that is not set the response colour
// and if that is not set story colour), if
// printing a system error.

: print "Hello";

3.15.7. Colouring in a particular part of the text.

We can use the pattern <YOUR TEXT<PALETTE COLOUR>> to colour in some text (ignore the upper case here).

The standard text colouring rules still apply for the parts of the text that are not explicitly coloured.

: print "This part of the text is <green<4>>.";

You can also use an rgb hex code for text colouring.

: print "This part of the text is <bright red<#f00>>.";

3.15.8. Hyperlinks (Experimental) - Subject to change

Hyperlinks are supported in Adventuron via the following pattern:

: print "Click <here<4>>[https://adventuron.io] to go to the website.";

Some other uses of the […​] brackets are in development, but if you find them, don’t depend on them working in future releases.

The internal format of these brackets is subject to change.

3.15.9. Settings Colours In The Theme

Colours are configured and looked up based on the current set theme of the game, and if no theme is set then default colours will be used (which is a black background and an off-white text colour rgb(204,204,204) or non-bright white as it was on the ZX Spectrum.

Note
Colour 8 is inhabited by orange, even though orange was not a colour on the ZX Spectrum (to make it easier to map to other palettes).

3.15.10. Standard palette (0 - 15)

Standard (24-bit colours) are represented by amounts of red, green, and blue colours.

Code Colour Name Hex (12-bit)

0

black

#000

1

blue

#00c

2

red

#c00

3

magenta

#c0c

4

green

#0c0

5

cyan

#0cc

6

yellow

#cc0

7

grey

#ccc

8

orange

#f60

9

light blue

#00f

10

light red

#f00

11

light magenta

#f0f

12

light green

#0f0

13

light cyan

#0ff

14

light yellow

#ff0

15

white

#fff

Note
A later release of Adventuron will let custom palettes be set that map to 0 - 255, 256 onwards will be reserved for effects.

3.15.11. About RGB codes (Hex)

  • A bit is a computing concept. It is a something that stores a 0 or a 1.

  • All colours displayed on a computer screen are represented by combinations of primary colours, red, green, and blue (RGB).

  • Black is minimum red green and blue.

  • Pure white is maximum red, green and blue.

  • One bit can represent off or on.

  • If we had a 1 bit per red, green and blue elements, there would be 8 different colours supported.

RGB Description

000

black

001

blue

010

green

100

red

110

yellow

101

magenta

011

cyan

111

white

The #RGB code

Adventuron’s supports a "12-bit" "palette".

  • A palette is a selection of colours.

  • A 12 bit colour can be written as #000 - #fff.

  • 12 bit colour uses 4 bits per red, green, and blue channel.

  • 0 is the lowest colour intensity, f is the highest colour intensity (see table below).

  • Each slot takes a "hexidecimal" representation of a number between 0 and 15 (16 combinations).

  • Unlike "decimal" numbers which range from 0 to 9, hexidecimal numbers continue past 9, and 10 is a, 11 is b, all the way to f, which is 15.

  • 12 bit colour allows a total of a 4096 colour palette combinations (16 x 16 x 16).

  • #000 = black (0 red, 0 green, 0 blue → always read in rgb order).

  • #fff = white (15 red (max), 15 green (max), 15 blue (max))

  • That should be enough for a text adventure. More colours can be used in images in adventuron, this is just for text.

  • RGB codes are always in the order RED, GREEN, then BLUE.

  • On the web, we use 8 bits per red, green, and blue channel (24 bits total).

  • 8 bits can store 256 different values. 0 = zero intensity, 255 = maximum intensity.

For numbers 10 - 15, we use hexidecimal notation:

Hex Decimal

0

0

1

1

2

2

3

3

4

4

5

5

6

6

7

7

8

8

9

9

a

10

b

11

c

12

d

13

e

14

f

15

3.16. Default Vocabulary

Adventuron automatically adds handlers for basic text adventure verbs.

For example, if the player types GET LAMP, then Adventuron will run the system get object routine which will test noun1 against objects that are in the location with you, if they are takeable, if you have enough space in your hands to carry them, if they are too heavy, if there is more than one item that has the same noun. You don’t need to worry about coding this yourself, nor do you have to care with any of the other system command handlers.

Here follows a list of default vocabulary along with their default actions.

To override any of these patterns, simple add a match record in on_command, and any code that runs will replace the system action (the system handler will not be executed).

Note
If you match any of the synonyms of a system commands (Except for two word variants), then this will override all other synonyms of the same system command. E.g. : match "x lamp" {} will match "x", "exam", "exami", "examine", "look" (with noun lamp).
System Command Synonyms Purpose

look -

l, r, redescribe

Redescribes the current location (clears the screen, then draws the description object list, etc).

examine *

x, look, (look at), ex, exam, exami

Accesses the description or message for the examined object. If you want specific actions to be defined other than displaying a message, then you need to override examine in your on_command {} block.

get *

take, (pick up)

Gets or takes an object. Subject to the rules of taking.

drop *

(put down), discard

Drops an object. Subject to the rules of dropping (e.g. you can only drop something you are carrying).

inventory _

i, inv, inven, holding, pockets

Looks in the pockets of the player and lists the contents.

wear *

(put on)

Puts on a carried object (subject to rules of wearing).

open *

Opens an object or a door.

close *

Closes an object or a door.

lock *

Locks an object or a door.

unlock *

Unlocks an object or a door.

remove *

(take off), unwear

Removes a worn item (subject to rules of removing).

ramload _

Loads the game from an in-memory save slot (imagine this as another fixed slot).

ramsave _

Saves a game to an in-memory save slot (imagine this as another fixed slot).

load _

Loads the game from a save slot.

save _

Saves a game to a save slot.

loadf _

Loads a game from a text file.

savef _

Saves a game to a text file.

paper 0-15, #000 - #fff

Sets the background colour of the game.

pen 0-15, #000 - #fff

Sets the foreground colour of the game.

columns 16 - 120

Sets the number of characters on a row.

normal -

Sets all presentation overrides (pen, paper, columns, theme, etc) back to the author specified default values.

quit _

restart

Asks if the player wants to quit the game, then if they answer yes, restarts the game.

help _

Displays the system level help command. Recommended to tailor this in your on_command{} section.

north _

n

Tries to move north (if possible).

northeast _

ne

Tries to move northeast (if possible).

east _

e

Tries to move east (if possible).

southeast _

se

Tries to move southeast (if possible).

south _

s

Tries to move south (if possible).

southwest _

sw

Tries to move southwest (if possible).

west _

w

Tries to move west (if possible).

northwest _

nw

Tries to move northwest (if possible).

up _

u

Tries to move up (if possible).

down _

d

Tries to move down (if possible).

enter _

in

Tries to enter (if possible).

exit _

leave

Tries to exit (if possible).

exits _

Lists the current exits in the current room.

3.17. System Messages

System messages are text that Adventuron displays as standard in response to certain commands. If you examine something without an examine message the standard response might be "You see nothing special." but in your game you may wish to personalize the message to something game specific such as "Percy didn’t think that looked very interesting.".

There are lots of messages to customise, and the tooling itself will give you templates for all the system messages if you follow the upcoming procedures.

Note
The 'two' theme is a theme that is built into Adventuron, and provides a minimal textual set of system response messages, as well as formats the screen similarly to the game 'two', released in 2019.
Important
If extending the 'two' theme, then auto-complete may not work properly. Temporarly comment out 'extends = two' to fix autocompletion. This is on the bug list and will be resolved shortly.

3.17.1. Changing a specific message

start_at    = start_location
start_theme = my_theme

locations {
   start_location : location "This is the start location.";
}

themes {
   my_theme : theme {
      system_messages {
         // Press Control + Space here to see list
         // of specific system messages you can change.
      }
   }
}

3.17.2. Seeing the templates for all messages

start_at    = start_location
start_theme = my_theme

locations {
   start_location : location "This is the start location.";
}

themes {
   my_theme : theme {
      // Press Control + Space here and select 'system_messages'
      // in the dropdown menu to see list
      // of all system messages you can change.
   }
}

3.18. Treasure Hunt

A treasure hunt is a type of text adventure games where the goal of the game is to collect various valuable objects and drop them in the 'treasure room'. Adventuron can trigger this mode by declaring a "treasure_room" at the top level.

Adventuron itself will add a win game condition where all the treasures have been found.

This mode is compatible with the 8-bit code emitter.

Below is a typical treasure hunt game, but a theme has been setup where the treasure tally is displayed in the taskbar. Press CONTROL + SPACE in the 'status_bar' section to see more types of information that can be displayed on the status bar.

######################################################
## TREASURE HUNT GAME TEMPLATE                      ##
######################################################

######################################################
# Full Documentation here - https://adventuron.io/documentation/
# Control + Space - Context sensitve auto completion (MOST IMPORTANT)
# Control + S     - Save and execute
# Control + F     - Find text
# Control + C     - Copy text
# Control + X     - Cut text
# Control + V     - Paste Text
# Hold Shift + Cursor keys - Select text
######################################################

## The start location of the adventure game

start_at      = outside_cave

######################################################
#  Game metadata, set your game name, and UUID here
#  before compiling to HTML
######################################################

game_information {
   game_name        = Stings Quest II
   game_shortname   = SQ2
   written_by       = Somebody
   year_of_original = 2020
   year_of_release  = 2020
   ## Use ... https://www.uuidgenerator.net/
   #uuid             =
   short_synopsis   = Solve the adventure
   game_version     = 0.1.0
}


#######################################################################
# Uncomment next line to add a loading screen (after importing a PNG)
#######################################################################

# loading_screen = loading_screen_graphic_id


# If treasure room is supplied
# then the game is a treasure hunt

treasure_room = treasure_room

# If this line is provided then when the object list or direction list
# changes, then the location is automatically redescribed.

redescribe    = auto_beta

locations {
   outside_cave  : location "You are outside the cave of magic."  ;
   treasure_room : location "You are in the treasure room"  ;
}

connections {
   from, direction, to = [
      outside_cave, north, treasure_room,
      ## Press Control + Space on a blank line to add more entries
      ## There must always be <from location>, <direction>, <to_location>,
      ## on each line.
   ]
}

objects {
   lamp         : object "a lamp"  at = "outside_cave" msg="a <red<10>> herring.";
   spoon        : object "a spoon" at = "outside_cave" treasure = "true";
   horn         : object "a horn"  at = "outside_cave" msg="Waiting to be blown.";
   golden_horn  : object "a golden horn" treasure = "true" ;
}

on_startup {
   : print "Deposit the two treasures in the treasure room to win." ;
   : press_any_key ;
}

on_describe {
   : if (is_just_entered () && is_at "outside_cave") {
      : print "<Right click objects to see common verbs, or click directions to go in that direction.<14>>" ;
   }
}

on_command {
   : match "blow horn"  {
      : if (is_carried "horn") {
         : swap o1 = "horn"  o2 = "golden_horn" ;
         : print "You blow the horn, and the horn turns to <gold<#r>>." ;
         : success ; // Plays a success beep

      }
      : else_if (is_carried "golden_horn") {
         : print "You blow the horn, and nothing happens." ;
         : failure ;  // Plays a failure beep
      }
   }
   : match "light lamp"  {
      : if (is_carried "lamp") {
         // Sudden death is bad, just using this to demonstrate the lose game jingle !
         : print "It blows up!" ;
         : lose_game;
      }
   }
}

###############################
## Theme is entirely optional
###############################

themes {
   my_theme : theme {

      theme_settings {
         capitalization  = upper
         font            = plotter_bold_extended
         layout          = SB G D O X
         layout_mobile   = SB G DO X
         columns         = 48
         keyboard_click  = on
         success_jingle  = on
         failure_jingle  = on
         wingame_jingle  = on
         losegame_jingle = on
      }

      colors {
         treasure_pen     = #r
         pen              = #fff
         paper            = #111
         status_bar_paper = #00e
         status_bar_pen   = #fff
      }

      screen {
         paragraph_spacing_multiplier = 1
         padding_horz                 = 1
      }

      system_messages {
         inventory_list_header        = "Carrying:\s"
         object_list_header           = "Items here:\s"
         exit_list_header_concise     = "Exits:\s"
         treasure_message             = "Treasure!"
      }

      status_bar {
         // If you want to display a per-location header in the status
         // bar then comment out the fixed text line above, and uncomment this line
         // Each location will need header="" specifying too
         //: header_text;

         : fixed_text "STINGS QUEST II" ;
         : treasure_score ;

      }
   }
}

A more minimal version:

start_at      = outside_cave
treasure_room = treasure_room
redescribe    = auto_beta

locations {
   outside_cave  : location "You are outside the cave of magic."  ;
   treasure_room : location "You are in the treasure room"  ;
}

connections {
   from, direction, to = [
      outside_cave, north, treasure_room,
   ]
}

objects {
   lamp         : object "a lamp"  at = "outside_cave" msg="a <red<10>> herring.";
   spoon        : object "a spoon" at = "outside_cave" treasure = "true";
   horn         : object "a horn"  at = "outside_cave" msg="Waiting to be blown.";
   golden_horn  : object "a golden horn" treasure = "true" ;
}

on_startup {
   : print "Deposit the two treasures in the treasure room to win." ;
   : press_any_key ;
}

on_describe {
   : if (is_just_entered () && is_at "outside_cave") {
      : print "<Right click objects to see common verbs, or click directions to go in that direction.<14>>" ;
      : print "<Type 'HELP' to see a list of common commands.<13>>" ;
   }
}

on_command {
   : match "blow horn"  {
      : if (is_carried "horn") {
         : swap o1 = "horn"  o2 = "golden_horn" ;
         : print "You blow the horn, and the horn turns to <gold<#r>>." ;
      }
      : else_if (is_carried "golden_horn") {
         : print "You blow the horn, and nothing happens." ;
      }
   }
}

themes {
   my_theme : theme {
      theme_settings {
         capitalization  = upper
         font            = plotter_bold_extended
         layout          = SB G D O X
         layout_mobile   = SB G DO X
         columns         = 48
      }
      colors {
         treasure_pen     = #r
         status_bar_paper = #00e
         status_bar_pen   = #fff
      }
      screen { paragraph_spacing_multiplier = "1" padding_horz = "1"}
      system_messages {
         inventory_list_header        = "Carrying:\s"
         object_list_header           = "Items here:\s"
         exit_list_header_concise     = "Exits:\s"
         treasure_message             = "Treasure!"
      }
      status_bar {
         : fixed_text "STINGS QUEST II" ;
         : treasure_score ;
      }
   }
}

3.19. Verb/Noun Mode

Note
Only available in beta 65u and above.

To enable verb/noun mode simply specify the following line at the top of your game file:

game_type = verb_noun

Once of a key number of criticism of "parser" based text adventure games is that it can be hard to know exactly how to communicate with the game correctly.

Some games may understand the following:

  • One or two words strictly (EAST, NORTH, EAT FOOD, THROW ROPE, LIGHT LAMP).

  • Complex sentences ASK BARRY ABOUT LAKE, SHOW MEDAL TO QUEEN.

  • Mostly two word inputs, but sometimes longer sentences are required (if long sentences are required for specific actions in this type of game, then prod the player to type a longer sentence, don’t assume the player will know to do this).

Of the three types of "parser" text adventure games, the easiest to play (and write) is the VERB/NOUN type game.

The verb/noun mode of Adventuron will simplify work for both the game designer, and the player in the following ways:

For the player:

  • The HELP screen informs the player that a maximum of only two words are required in-game.

  • Typing three or more words will inform the player that a maximum of only two words are required in-game.

For the author:

  • All system-level prepositions are switched off, leaving the way to set up some prepositions in the NOUN slot.

  • Adjectives are not added to the dictionary.

  • Functions that examine any word type other than VERB and NOUN1 are disabled (error if used), this stops authors from accidently building non-verb noun games.

  • Text substitutions are disabled.

3.20. Screen Layout

Adventuron supports rearranging the screen layout, so for example, if you want to place the direction list before the description, you can do that. If you want to omit the exit list altogether, you can do that too. All of these customisations are stored per-theme, and you can switch themes at runtime during your game using : set_theme "theme_id "; .

To create a screen layout, you must first have (or create) a custom theme, then edit the 'layout' (or 'layout_mobile') setting underneath the theme_settings {} block. See the snippet below.

How To Create The theme_settings section using the editor
start_at    = start_location
start_theme = my_theme

locations {
   start_location : location "This is the start location.";
}

themes {
   my_theme : theme {
      // Press Control + Space here and select 'theme_settings'
      // in the dropdown menu to see list
      // then in the theme_settings section, press Control + Space again
      // and select 'layout' to find the layout setting.
   }
}
Sample Theme With A Custom Layout
start_at    = start_location
start_theme = my_theme

locations {
   start_location : location "This is the start location.";
}

themes {
   my_theme : theme {
      theme_settings {
         layout = D X O
      }
   }
}

Items in the layout section must be chosen from this list of layout elements. All items in a layout are rendered from top to bottom.

Option Description Top Pad Bottom Pad

SB

Adds a scroll-locked status bar.

If this is specified then the current theme MUST specify a status_bar {} section in addition to specifying status bar in the layout.A clear screen command might remove this unless configured to maintain the status bar.

Currently only works if first item in layout. Future releases will not have this constraint.

No

No

H

Header (if exists for location).

No

Yes

H -

Header (if exists for location).

No

No

G

Graphic (if exists).

No

Yes

G -

Graphic (if exists).

No

No

+ G

Graphic (if exists).

Yes

Yes

+ G -

Graphic (if exists).

Yes

No

D

Description (if exists for location)

No

Yes

HD

Header in capital letters, following by description, without a linefeed between the header and the description (space added).

No

Yes

X

Exit List (if exists for location).

No

Yes

P* "string_id"

pointer to a string id of a string variable containing text to be rendered (this can also be a dynamic string which will resolve lazily).

No

Yes

O

Object list for conspicious objects in location (if exists for location)

No

Yes

SEP "seperator_id"

horizontal line break across the screen. Currently just supports 'adv_line_red'. DO NOT USE CUSTOM SEPERATORS RIGHT NOW AS IMPLEMENTATION WILL CHANGE.

No

Yes

LOCK

Lock scrolling at this point.

This will essentially anchor all screen layout items prior to the lock to the top of the screen (will not scroll off the screen).

Note that on mobile phones that LOCK is (typically) ignored unless it follows a graphics block. This is because the description may be large. There could still be problems if displaying images that are taller than they are wide on mobile clients, so ensure your location images are in landscape orientation.

No

No

Note
Future versions of Adventuron will improve layout features so it can use multiple "window" areas of the screen, and have fine grained layout patterns and screen allocation patterns in all directions - but for this release, we only have one display area (which is very typical for classic games anyway).

3.20.1. Default Layouts

Adventuron uses relatively complex logic for figuring out the correct default layout options given other settings in the game theme.

You don’t need to understand this defaulting mechanism, just know that if you want to have complete control over your game layout you only need to change:

my_theme : theme {
   lister_objects {
      list_type = list | list_no_article | single_line | single_line_no_article | single_line_no_adjective | verbose
   }
   theme_settings {
      layout        = xxxx
      layout_mobile = xxxx
   }
}

If the mode is auto_redescribe and treasure hunt mode, then the default list_type is single_line_no_article, otherwise the default list type is verbose. The game author can override this of course.

If the list type (default or manually set) starts with list_*, then the object list will be placed after the exit list. If the list type is any other type (verbose, etc), then the object list is always placed before the exit list.

Settings "lister_objects/list_type" & "theme_settings/layout" manually is the best way to lock your game layout.

If you want to set your game to look like a QUILL era game, then the following layout is what you want:

Quill-like layout
my_theme : theme {
   lister_objects {
      list_type        = list
      list_type_mobile = single_line_no_article
   }
   theme_settings {
      layout        = G HD X O
      layout        = G HD O X
   }
}

(On mobile vertical space is super premium, so concise single line object lists are strongly advised).

3.20.2. Mobile Layout

Usually mobile is constrained differently to desktop so mobile layout can be specified to be different.

In the example shown below, mobile is omitting graphics and the status bar, also collapsing the header into the description paragraph to save vertical space.

themes {
   my_theme : theme {
      theme_settings {
         layout        = SB G D X O LOCK
         layout_mobile = HD X O
      }
   }
}

This snippet demonstrates how to reference the contents of a string, to be displayed in a location.

Later releases of Adventuron will allow per-location layout overrides.

start_at  = village

locations {
   forest  : location "You are in a forest." ;
   village : location "You are in the village." ;
}

connections {
   from, direction, to = [
      village, east, forest,
   ]
}

objects {
   lamp : object "a lamp" at = "village" ;
}

strings {
   some_dynamic_string : dynamic_string {(
      is_at "village" ? "You hear sounds of the village" :
      is_at "forest"  ? "You hear sounds of the forest"  :
      ""
   )}
}

themes {
   my_theme : theme {
      theme_settings {
         layout = H G D X P* "some_dynamic_string" O SEP "adv_line_red"
      }
   }
}

More layout options are available, to be documented later.

3.21. Hotkeys

The Adventuron editor has a number of shortcut keys that help.

Warning
Chromebooks are missing many useful keys for programmers. There are workarounds but be aware that ChromeRead more about this here.
Action / Button Description Possible Issues

Click Top Bar of Editor

(When Red) Go to line of error.

(When Blue) Show Quick Nav Bar.

N/A

Cursor Keys

Tap cursor (arrow) keys to move the blinking 'cursor' around the text area.

The cursor represents the position where the next text will be inserted when you press a regular key on the keyboard.

N/A

Hold Shift + Cursor Keys

Hold Shift and tap cursor (arrow) keys to select a redion of text.

When a region of text is selected, you can type over it by pressing another key, or copy it, or paste it, just as if you selected it with a moush.

N/A

Control + F

Search for text in the document.

May be COMMAND + F on some computers.

Control + C

Copy the selected text (to the clipboard).

May be COMMAND + C on some computers.

Control + X

Cut the selected text (to the clipboard)

May be COMMAND + X on some computers.

Control + V

Paste the selected text (from the clipboard)

May be COMMAND + V on some computers.

Page Up

Scrolls the text one page up at a time.

Some keyboards do not have a dedicated page up button.

You may need to hold two buttons at once to emulate page up.

Page Down

Scrolls the text one page down at a time.

Some keyboards do not have a dedicated page down button.

You may need to hold two buttons at once to emulate page down.

Home

Moves the cursor to the beginning of the current line (but after the leading spaces).

Some keyboards do not have a dedicated Home button.

You may need to hold two buttons at once to emulate HOME.

End

Moves the cursor to the end of the current line.

Some keyboards do not have a dedicated End button.

You may need to hold two buttons at once to emulate END.

Control + Home

Scrolls to the top of the document.

Some keyboards do not have a dedicated Home button.

You may need to hold two buttons at once to emulate HOME.

Control + End

Scrolls to the bottom of the document.

Some keyboards do not have a dedicated End button.

You may need to hold two buttons at once to emulate END.

Control + L

Goto specified line number.

May be COMMAND + L on some computers.

Control + Z

Undo the last edit

May be COMMAND + Z on some computers.

Control + Y

Redo the last undo

May be COMMAND + Y on some computers.

Control + A

Select All Text

May be COMMAND + A on some computers.

Control + S

Save All Text (to the current document buffer), and execute your game in the right hand panel.

May be COMMAND + S on some computers.

3.22. Debugging

3.22.1. Debugging With Code

Adventuron can be setup to short-circuit the on_startup {} event handler, and perform another activity upon startup. This is useful for debugging.

The on_debug {} block, if provided, will be executed INSTEAD OF the on_startup {} event handler, and this can be used to set up the game state prior to Adventuron describing the location for the first time.

Authors can use the on_debug {} event handler to move the player to a location, set variable values, move objects around, give objects to players, prior to first redescribe.

Authors can "comment-in" and "comment-out" the on_debug {} event handler by selecting the entire block then pressing CONTROL and / together. This will toggle comment markers on all the lines on and off.

Authors should put their debugging logic in on_debug {} and not modify their normal on_startup {} routine when debugging, just as best practise so as not to accidentally break the startup logic when debugging.

With debug block "commented-in":

start_at  = study

on_debug {
   // Setup the game ready for the test you want to perform.
   // After this block of code is executed, Adventuron
   // Will redescribe the location that the player is in.
   : goto     "library" ;
   : pocket   "book" ;
   : set_true "has_talked_colonel" ;
}

locations {
   study   : location "You are in the study." ;
   library : location "You are in the library." ;
}

connections {
   from, direction, to = [
      study, east, library,
   ]
}

objects {
   book : object "an old book" ;
}

booleans {
   has_talked_colonel : boolean "false" ;
}

With debug block "commented-out":

start_at  = study

// on_debug {
//    // Setup the game ready for the test you want to perform.
//    // After this block of code is executed, Adventuron
//    // Will redescribe the location that the player is in.
//    : goto     "library" ;
//    : pocket   "book" ;
//    : set_true "has_talked_colonel" ;
// }

locations {
   study   : location "You are in the study." ;
   library : location "You are in the library." ;
}

connections {
   from, direction, to = [
      study, east, library,
   ]
}

objects {
   book : object "an old book" ;
}

booleans {
   has_talked_colonel : boolean "false" ;
}

3.22.2. Debugging In Game

The version of Adventuron that runs in the editor has a number of debugging functions built-into the game engine itself (the non-editor version of adventuron has these features disabled by default to prevent game cheating).

The following debugging commands can be used at the command line.

// Will list all the variables you have declared in the game as well as their current values


showvars


// Moves player to the specified location.
// e.g. (don't type the > character)
//
// > goto library
//
// NOTE : does not redescribe automatically by default


goto <<location_id>>


// Brings the object or scenery corresponding to the object id
// into the same room as the player. NOTE: This uses the OBJECT ID
// (as declared in the objects {} block of the source code -
// not the verb or noun corresponding to the object.
// e.g. If you have declared the following object in your game code:
//      shiny_ant_1 : object "a shiny ant";
// then typing the following would bring the ant to the same location
// as the player (don't type the > character):
//
// > summon shiny_ant_1


summon <<object_id>>


// Sets a variable to a particular value (e.g. *is_noisy = true )


*variable_id = variable_value

3.22.3. Transcripts

A transcript is a way to see what players are doing with your game for the purpose of improving your design, or locating bugs.

If you are in the same room as the tester, you can observe their actions and make notes if they encounter any design problems (or bugs).

It is far more common that your testers will not be located in the same room as yourself, so Adventuron has a feature called transcripts which can help you to capture the experience of players during the testing phase of developing your game.

A transcript is a log of player actions, and game reactions to user input (in textual form). Transcripts look a lot like a two way conversation between the player and the game and studying transcripts is a wonderful way to test your assumptions about the way that your players will approach the game.

To enable recording a game transcript, ask your beta testers to type "TSTART":

> TSTART

To disable recording a game transcript, ask your beta testers to type "TSTOP":

> TSTOP

Stopping recording of the game will save a .txt file (in your default browser downloads folder) containing the transcript.

If you close the tab containing the game that is being recorded, adventuron will save the transcript when you reload the game (browser permissions make it impossible to save when the tab is closing directly).

If you reload the game or repoen the tab, transcript recording will have to be restarted, and will only start from the point where TSTART is entered.

Warning
The current transcript recording mechanism is beta, and the format is subject to change. It is provided for convenience purposes (better than nothing). A better implementation is forthcoming.

3.22.4. Testing Mobile On Desktop

Sometimes you may wish to execute different logic on mobile versus desktop. The is_mobile() boolean function can be used for this purpose.

To test this logic, you can force Adventuron to override the detected device type ( is_mobile() will follow the override ).

start_at = my_location

locations {
   my_location : location "By default, mobile devices will run in mobile mode, and desktop devices will run in desktop mode.\nYou can type <DEVICETYPE DESKTOP<12>> or <DEVICETYPE MOBILE<12>> to force adventuron to run in mobile or desktop mode.\nType <DEVICETYPE<12>> to set the devicetype to the default device type." ;
}

on_tick {
   : if (is_mobile()) {
      : print "<on_tick() : We are running on mobile.<11>>" ;
   }
   : else {
      : print "<on_tick() : We are running on desktop.<11>>" ;
   }
}

3.23. Sentence Rewriting

Warning
A completely different (and recommended) approach to matching in a later release (whilst maintaining the current method). The new method would define actions in relation to patterns of text, direct object, and indirect object, as well as describing where to look for objects in the text pattern slots, and how to imply objects where it makes sense such that verb noun may be used as a shortform.

Sometimes you want two different sentences structures to have the perform same action.

e.g.

  • use crowbar on lock ←→ break lock with crowbar

We can transform a sentence into a different sentence using the set_sentence command.

The set sentence will change the sentence that Adventuron sees downstream of the set_sentence command, meaning you don’t have to match two or more complex match patterns downstream. This also means that players are more free to use sentences in different structures, which reduces player frustration.

e.g.

   : if (verb_is "use" && noun1_is "crowbar" && original "noun2" != "") {
      : set_sentence "break $2 with $1";
   }

In the above example, $1 and $2 special values (subject1 and subject2).

  • $1 will substitute in adjective1 (if supplied) and noun1 (if supplied).

  • $2 will substitute in adjective2 (if supplied) and noun2 (if supplied).

Here is a more complete snippet of code. To build on this, you may wish to assign certain objects with certain default actions and place those objects into an if then else loop, and change the substitution verb depending on the object. Feel free to incorporate this snippet into your own code.

###################################
## Sentence re-writing
####################################
## use crowbar on lock <--> break lock with crowbar
####################################

start_at = cell

locations {
   cell : location "You are in your cell." ;
}

objects {
   crowbar : object "a crowbar" at = "inventory" ;
   lock    : scenery "a lock" at = "cell" ;
}

on_command {
   : gosub "sentence_rewriting";
   : match "break _"  {
      : if (subject1_is "lock" && subject2_is "crowbar") {
         : if (is_carried "crowbar") {
            : print "You try to break the lock with the crowbar, but it is solid." ;
         }
         : else {
            : print "You don't have it." ;
         }
      }
   }
}

subroutines {
   // NOTE :: Never print anything in the sentence re-writer, as this will override the system command handler.
   sentence_rewriting : subroutine {
      : if (verb_is "use") {
         : if (original "noun2" != "") {
            : if (subject1_is "crowbar" && (preposition_is "on" || preposition_is "with")) {
               : set_sentence "break $2 with $1" ;
            }
         }
         : else {
            : if (original "noun1" == "") {
               : print "Use what on what?";
            }
            : else {
               : print {("Use " + original "noun1" + " " + (original "preposition" == "" ? "on" : original "preposition") + " what?" )}
            }
         }
      }
   }
}

If you require more powerm then sentences can be programatically rewritten too:

Note
The $1 and $2 substitutions occur after the dynamic sentence is resolved.
strings{
  myvar : string "sentence";
}

on_command {
   // Will build 'this is my dynamically built sentence'
   : set_sentence {("this " + "is " + "my " + "dynamically " + "built " + myvar)}
}

3.24. Additional Features

3.24.1. Plurality

Note
By default, auto-pluralise is enabled.

Adventuron as standard supports auto-plurality vocabulary expansion.

Consider you place a noun 'trees' in one of your your location description.

The player might type in 'examine tree' or 'examine trees'.

If not configured to do otherwise, Adventuron, when seeing a noun ending in an 's' will de-pluralize the word and add it as an alias for a work. Adventuron also performs automatic pluralization too, and adds a plural version for nouns that don’t look as if they are plural.

Pluralized and de-pluralized noun aliases are only added the calculated alias is not explicitly defined elsewhere. The algorithms are described later in this section.

Consider this code:

start_at = forest

locations {
   forest : location "You are on the forest path.\nTall TREES tower over you on both sides." ;
}

on_command {
   : match "examine trees"  {
      : if (is_at "forest") {
         : print "Apple trees." ;
      }
   }
}

All of the following commands will respond with 'Apple Trees'.

  • EXAMINE TREE

  • EXAMINE TREES

  • LOOK TREE

  • LOOK TREES

  • LOOK AT TREE

  • LOOK AT TREES

    1. Adventuron will add the de-pluralized version of trees to the dictionary automatically.

    2. Match records automatically contribute verbs and nouns to the verb dictionary and the noun dictionary respectively.

    3. 'examine' and 'look' are already aliased by default in Adventuron, and that does not factor into the pluralization feature, just for your information.

The following code will also match the same inputs in exactly the same way, although this time Adventuron is automatically registering the pluralized the non-plural 'tree'.

start_at = forest

locations {
   forest : location "You are on the forest path.\nTall TREES tower over you on both sides." ;
}

on_command {
   : match "examine tree"  {
      : if (is_at "forest") {
         : print "Apple trees." ;
      }
   }
}
Disabling pluralisation & de-pluralization

To disable pluralisation & de-pluralization, then you can use the following setting (at the top level of your gamefile).

game_settings {
   auto_pluralize_nouns = false
}
Pluralization Algorithm (English + Spanish)
  • If a word ends in 'ss', then add 'es'.

  • Otherwise, if a word does not end in 's', then add 's'.

De-Pluralization Algorithm (English + Spanish)
  • If a word ends in 'sses' then remove the final two characters.

  • If a word ends in 's' but does not end in 'sses' then remove the final character.

3.24.2. Granular Matching

Important
Pluralized and de-pluralized aliases will only be added where the alias does not already exist in the dictionary. Aliases are always added as a last step.

See the following example …​

start_at = forest

locations {
   forest : location "You are on the forest path.\nTall TREES tower over you on both sides." ;
}

on_command {
   : match "examine tree"  {
      : if (is_at "forest") {
         : print "You look at one apple tree." ;
      }
   }
   : match "examine trees"  {
      : if (is_at "forest") {
         : print "You look at many apple trees." ;
      }
   }
}

Try typing:

  • examine tree → You look at one apple tree.

  • examine trees → You look at many apple trees.

3.24.3. Pre-Processing

Adventuron has a certain number of language-specific sentence pre-processors.

These pre-processors look for consecutive patterns of words and replace with a different word (or words). This occurs before any of the matching routines are checked in Adventuron.

This (langauge specific) feature is currently not able to be disabled, and not able to be configured. Configuration will be enabled in a later version of Adventuron.

For English:

Pattern To Replace Replaced With

PUT ON

WEAR

PUT DOWN

DROP

PICK UP

GET

TAKE OFF

REMOVE

LOOK AT

EXAMINE

AND THEN

THEN

GO <direction>

<direction>

3.24.4. Deaccenting

Note
Only used with Spanish language currently.

It is strongly advised if you are writing a game in Spanish or another language with accented characters, that you use words with accented characters in your match statements. Adventuron will automatically create de-accented versions, so you are not required to add a vocabulary entry for the de-accented version of the same word.

The de-accented aliases for all dictionary word types (verbs, nouns, adverbs, adjects, prepositions) are added only where the aliases do not conflict with an existing dictionary entry (in the same word type category).

(For nouns only) This de-accenting step is perform immediately before the pluralization (and de-pluralization) pass.

start_at = forest
language = spanish

locations {

   // English translation -- You are in a dark room.
   //                        There is a flickering lamp on the wall.
   //                        ---------------------------------------
   //                        lámpara == lamp
   forest : location "Estás en un cuarto oscuro. En la pared hay una lámpara parpadeante." ;

}

on_command {
   // examine lamp
   // Prints "The lamp is out of reach.".
   : match "examinar lámpara"  {
      : print "La lámpara está fuera de alcance.";
   }
}
Warning
Inline pluralization and de-pluralization, if you want your game to support accented and de-accented versions of the same word, then you need to always use the accented vversions of the words internally. It’s impossible for Adventuron to accurately guess which accent to use.

3.25. Search

If you are editing a larger adventure game (more than 1,000) lines then a search function becomes essential if you wish to be productive.

For examine, let’s assume for example, that you have written a game and you have created a barrier called 'river' and now you want to edit the barrier, and at the same time change the description of the river location, and possibly relocate an NPC away from the river.

That’s a lot of logic to change, and manually scanning through thousands of lines of code is likely to be time consuming and error prone.

This is where the search functionality comes in.

Press CONTROL + F, then a textbox will appear at the top-right of the editor.

Type 'river' and it will move the screen to the first instance of 'river' in your game source file.

find

Press ENTER to cycle through every instance of the word 'river' in your text.

Note
Putting double quotes in your search textbox will find command subjects easier.

When editing Adventuron it sometimes becomes very necessary to move around different sections quickly, and to look for certain commands.

Let’s say you are looking for the place in the code where you create an apple and you know the name of your apple object id is 'apple' then a quick method of doing that is to search for "apple" - with the double quotes also typed into the search box. This will show you everywhere in the code where the apple id is a subject.

Type this into the searchbox to search for places where apple is the subject of an adventuron command
"apple"

Such a query might locate the following lines of code (each line would have to be iterated over using the arrow buttons - or pressing enter).

    : create "apple";

or

    : destroy "apple";

or

    : if (has_not_created "apple") {
       // something
    }

If you had just typed apple (without the double quotes), then the search function would just show you every instance of the word apple, including apples that are used conversationally in your game.

Note
Search for name of a section, then a space, then an open brace to find all instances of that section.

e.g.

Type this into the searchbox to search for the on_command {} section
on_command {
Type this into the searchbox to search for the objects {} section
objects {
Type this into the searchbox to search for the themes {} section
themes {
Note
Type a colon, then a space, then the name of a command you are looking for to find a command.
Warning
It is important for your commands to be well formatted to benefit from these searches. Don’t delete spaces between : and the command name in your source

e.g.

Type this into the searchbox to find all instances of the destroy command.
: destroy
Type this into the searchbox to find all instances of lose_game (this would probably work just as well without the leading : as it’s a very unique word).
: lose_game

To search for any text just type the name of the text you are looking for, for example, if you looking for a conversation about the castle, type "castle" (without the double quotes).

Warning
Be aware that this will also match anywhere in the code where castle is present, including commands, sections, and subjects. But using search is many many times faster than manually scanning thousands of lines of code for the word.

INFO: (Advanced users only) Regular expression searches are also supported. Click the ".*" icon to switch on regular expression search mode.

3.25.2. Closing The Search Panel

Click the small 'x' icon at the top right of the search panel to close the search panel. You can bring it back by pressing CONTROL + F again.

3.25.3. Search And Replace

(ADVANCED USERS ONLY) By clicking the + icon underneath the search textbox, you can access a replace text box.

3.26. Fonts

The font preference is stored within the theme. If no theme is provided then the default Adventuron theme will be used.

Adventuron has a number of fonts that are included in the engine itself (Bamburgh, DAAD, Clairsys_10, Delta_10, etc).

Multiple themes can be specified in the themes section, and can be change at runtime during the game.

start_at    = x
start_theme = my_theme

locations {x:location"This is the DAAD font";}

themes {
   my_theme : theme {
      theme_settings {
         font = daad
      }
   }
}
Note
To learn more about the license of the embedded fonts, type "*CREDITS" inside the game window, and also at the bottom of this document.

3.26.1. Importing A Custom Font

Adventuron can import a font by selecting MENU / Import, then selecting a truetype font.

Your imported font will be added in the assets / fonts {} section of the Adventuron document.

Custom fonts should always start with the prefix 'userfont_'.

assets {
   fonts {
      userfont_myfont : base64_ttf "BASE64HERE";
   }
}

3.26.2. ZX Origins Fonts

A recommended source of high quality 'old school' pixel fonts is the "ZX Origins" collection, by Damien Guard.

Damien is very talented, and I consider this to be the premier collection of 8x8 old-school fonts available today.

Below is a list of the ZX Origins fonts that are available (as of October 2020). If you are viewing this on mobile, then zooming in is recommended.

spooky zxorigins

The ZX Origins fonts are available here.

To import the fonts, find a font (or fonts) you would like to import for your game, and click the download button per-font to download a zipfile containing the font assets. Unzip the contents of the zip, and then (using the steps described in the previous section) import the font into adventuron by selecting the relevant .ttf file.

The "ZX Origins" fonts were designed to be 8 pixels by 8 pixels, but Adventuron will automatically scale the fonts for the players screen size.

Adventuron does not ship with the ZX Origins fonts as standard, authors are required to download and import any fonts they wish to use for their game.

ZXOrigins

Licenses to the ZX Origins are very permissive, and the general license is printed here, but it is the author’s resposibility to double check the license per font they import.

ZX Origins License Terms (author needs to confirm license per-font they import)
This font is part of the ZX Origins font collection Copyright (c) 1988-2020 Damien Guard.

Formal licenses are complicated and burdensome so here's the deal. These are some acceptable use examples:

1. Use it in your game (commercial or non-commercial)
2. Print something on a t-shirt
3. Use the embedded font file on your site
4. Set your favorite terminal or OS to use it

Ideally with a credit like "<fontname> font by DamienG https://damieng.com/zx-origins" *if* you have a credits section. If you don't that's fine. Either way dropping me an email at damieng@gmail.com to let me know what you used it for is appreciated.

The only unacceptable use is redistributing this font as a font. i.e. re-hosting the files on your own site or bundling it with other art assets. I have put a lot of time into these and my only reward is seeing download counts on my site which is ad-free so it seems unfair other people would re-host these files on their site and make $ from Google Adwords etc.

If you need to modify the font for your usage - either to add characters (this collection is pure ASCII + copyright + pound sign right now) or if a few are bothering you just change the credit to "Font based on <fontname> by DamienG" or something.

Thanks and enjoy!

[)amien

3.26.3. Squashed Fonts

Some fonts may feel fairly squashed or cluttered vertically.

Example:

font 1

There are two steps that should be performed to make fonts be spaced out. The first is to adjust the line height per imported font.

FIRSTLY, After you import the font into adventuron, press control + f and search for 'experimental_line_height_ratio', and change 1.0 to 1.5 (1.25 is another good value if 1.5 is too much for the font).

Try to make sure that, for pixel fonts that the line ratio multiplier multiplied by the vert_pixels is an integer amount (doesn’t leave a decimal point part). Failure to do this may involve some fonts moving around when the player presses ENTER.

In context, it will look like this:

assets {
   fonts {
      userfont_fontname : base64_ttf
          horz_pixels = "8"
          vert_pixels = "8"
          font_scale_multiplier = "1.0"
          experimental_line_height_ratio = "1.5"
          snap_vert = "true"
          "BASE 64 DATA HERE"
      ;
   }
}

SECONDLY, you may find that the spacing between paragraphs looks a little too close. This should be resolved in your theme:

e.g.

themes {
   theme {

      // Other theme settings here.

      screen {
          paragraph_spacing_multiplier = 1
      }

   }
}

After making these modification, your text will start to look less cluttered and more readable.

font 2

Full Example Of Uncluttered Font Settings

Here is a full example, which includes the 'scribe' font encoded as base64. Remember, you will never need to copy or paste or type in the base64 of the font manually, always use the "import" menu item in the Adventuron Classroom editor.

start_at = lakeside

locations {
   lakeside       : location "You are by the side of a lake. You are by the side of a lake. You are by the side of a lake. You are by the side of a lake. You are by the side of a lake. You are by the side of a lake." header = "Lakeside" ;
   forest         : location "You are in a forest." ;
   treetop        : location "You are in a treetop." ;
   outside_castle : location "You are outside the castle." ;
   castle         : location "You are inside the castle." ;
}

connections {
   from, direction, to = [
      lakeside,       north, outside_castle,
      outside_castle, north, castle,
      lakeside,       east,  forest,
      forest,         up,    treetop,
   ]
}

objects {
   ladder  : object  "a ladder" at = "lakeside" ;
   lamp    : object  "a lamp" at = "lakeside" ;
   spoon   : object  "a spoon" at = "lakeside" ;

}

assets {

      // Font should be attributed to Damien Guard somewhere in your on_startup {}
      // https://damieng.com/typography/zx-origins/scribe

      fonts {
      userfont_scribe_eire : base64_ttf horz_pixels = "8" vert_pixels = "8" font_scale_multiplier = "1.0" experimental_line_height_ratio = "1.5" snap_vert = "true" "AAEAAAARAQAABAAQTFRTSCBTXV4AAAOEAAAAZ09TLzJleFn0AAABmAAAAGBWRE1YYiBpeQAAA+wAAAXgY21hcA7cE2IAABMsAAACZGN2dCAEXABkAAAXOAAAABRmcGdtBlmcNwAAFZAAAAFzZ2FzcAAXAAkAAJxkAAAAEGdseWZfuN4cAAAXTAAAf+RoZG14YHxTnAAACcwAAAlgaGVhZBZa2ecAAAEcAAAANmhoZWEGQQOEAAABVAAAACRobXR4M0gnEAAAAfgAAAGMbG9jYdwJ/VgAAJcwAAAAyG1heHACcwL7AAABeAAAACBuYW1l4Dn4gwAAl/gAAAN8cG9zdFtKX0cAAJt0AAAA7XByZXCCvJjLAAAXBAAAADIAAQAAAAEAAJv9cRdfDzz1ABkDIAAAAADYiCBnAAAAANuFd9IAAP84AyACWAAAAAkAAgAAAAAAAAABAAACvAAAAGQDIAAAAAADIAABAAAAAAAAAAAAAAAAAAAAYwABAAAAYwA6AAUAAAAAAAEAAAAAAAoAAAIAAsAAAAAAAAMDGgGQAAUAAAIwAggAAABwAjACCAAAAX4AKADICAoAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAEVOVlkAAAAAAKkCvAAAAGQCWADIAAAAAQAAAAAB9AK8AAAAIAAAAyAAAAIUAAACFAAAAyAAAAMgAAADIAAAAyAAZAMgAAADIAAAAyAAyAMgAMgDIADIAyAAZAMgAGQDIADIAyAAZAMgASwDIABkAyAAZAMgASwDIABkAyAAZAMgAGQDIABkAyAAZAMgAGQDIABkAyAAZAMgASwDIADIAyAAZAMgAGQDIADIAyAAZAMgAGQDIABkAyAAZAMgAGQDIABkAyAAZAMgAGQDIABkAyAAZAMgAMgDIABkAyAAZAMgAGQDIABkAyAAZAMgAGQDIABkAyAAZAMgAGQDIABkAyAAZAMgAGQDIABkAyAAZAMgAGQDIABkAyAAyAMgAMgDIABkAyAAyAMgAMgDIAAAAyAAAAMgAGQDIABkAyAAAAMgAGQDIABkAyAAZAMgAAADIADIAyAAyAMgAGQDIAEsAyAAAAMgAAADIABkAyAAZAMgAGQDIAAAAyAAZAMgAGQDIAAAAyAAAAMgAAADIAAAAyAAAAMgAGQDIABkAyABLAMgAGQDIAAAAyAAAAMgAAADIADIAAAAYwEBAQEBAQEBAQE7TAEBAQEBAQEBAQEBNzcBAQEBAQEBAQEBAQFMAUxMN0wBAQFMAQEBAQEBNztMAQEBAQEBAQE7AQEBTAE3TAE3AQEBAUw3AQFMAQFMNwEBATcBAQEBTAEBAQAAAAABAAEBAQEBAAwA+Aj/AAgABv/+AAkAB//9AAoACP/9AAsACf/9AAwACf/9AA0ACv/8AA4AC//8AA8ADP/8ABAADP/8ABEADf/7ABIADv/7ABMAD//7ABQAD//7ABUAEP/6ABYAEf/6ABcAEv/6ABgAEv/6ABkAE//5ABoAFP/5ABsAFf/5ABwAFf/5AB0AFv/4AB4AF//4AB8AGP/4ACAAGP/4ACEAGf/3ACIAGv/3ACMAG//3ACQAG//3ACUAHP/2ACYAHf/2ACcAHv/2ACgAHv/2ACkAH//1ACoAIP/1ACsAIf/1ACwAIf/1AC0AIv/0AC4AI//0AC8AJP/0ADAAJP/0ADEAJf/zADIAJv/zADMAJ//zADQAJ//zADUAKP/yADYAKf/yADcAKv/yADgAKv/yADkAK//xADoALP/xADsALf/xADwALf/xAD0ALv/wAD4AL//wAD8AMP/wAEAAMP/wAEEAMf/vAEIAMv/vAEMAM//vAEQAM//vAEUANP/uAEYANf/uAEcANv/uAEgANv/uAEkAN//tAEoAOP/tAEsAOf/tAEwAOf/tAE0AOv/sAE4AO//sAE8APP/sAFAAPP/sAFEAPf/rAFIAPv/rAFMAP//rAFQAP//rAFUAQP/qAFYAQf/qAFcAQv/qAFgAQv/qAFkAQ//pAFoARP/pAFsARf/pAFwARf/pAF0ARv/oAF4AR//oAF8ASP/oAGAASP/oAGEASf/nAGIASv/nAGMAS//nAGQAS//nAGUATP/mAGYATf/mAGcATv/mAGgATv/mAGkAT//lAGoAUP/lAGsAUf/lAGwAUf/lAG0AUv/kAG4AU//kAG8AVP/kAHAAVP/kAHEAVf/jAHIAVv/jAHMAV//jAHQAV//jAHUAWP/iAHYAWf/iAHcAWv/iAHgAWv/iAHkAW//hAHoAXP/hAHsAXf/hAHwAXf/hAH0AXv/gAH4AX//gAH8AYP/gAIAAYP/gAIEAYf/fAIIAYv/fAIMAY//fAIQAY//fAIUAZP/eAIYAZf/eAIcAZv/eAIgAZv/eAIkAZ//dAIoAaP/dAIsAaf/dAIwAaf/dAI0Aav/cAI4Aa//cAI8AbP/cAJAAbP/cAJEAbf/bAJIAbv/bAJMAb//bAJQAb//bAJUAcP/aAJYAcf/aAJcAcv/aAJgAcv/aAJkAc//ZAJoAdP/ZAJsAdf/ZAJwAdf/ZAJ0Adv/YAJ4Ad//YAJ8AeP/YAKAAeP/YAKEAef/XAKIAev/XAKMAe//XAKQAe//XAKUAfP/WAKYAff/WAKcAfv/WAKgAfv/WAKkAf//VAKoAgP/VAKsAgf/VAKwAgf/VAK0Agv/UAK4Ag//UAK8AhP/UALAAhP/UALEAhf/TALIAhv/TALMAh//TALQAh//TALUAiP/SALYAif/SALcAiv/SALgAiv/SALkAi//RALoAjP/RALsAjf/RALwAjf/RAL0Ajv/QAL4Aj//QAL8AkP/QAMAAkP/QAMEAkf/PAMIAkv/PAMMAk//PAMQAk//PAMUAlP/OAMYAlf/OAMcAlv/OAMgAlv/OAMkAl//NAMoAmP/NAMsAmf/NAMwAmf/NAM0Amv/MAM4Am//MAM8AnP/MANAAnP/MANEAnf/LANIAnv/LANMAn//LANQAn//LANUAoP/KANYAof/KANcAov/KANgAov/KANkAo//JANoApP/JANsApf/JANwApf/JAN0Apv/IAN4Ap//IAN8AqP/IAOAAqP/IAOEAqf/HAOIAqv/HAOMAq//HAOQAq//HAOUArP/GAOYArf/GAOcArv/GAOgArv/GAOkAr//FAOoAsP/FAOsAsf/FAOwAsf/FAO0Asv/EAO4As//EAO8AtP/EAPAAtP/EAPEAtf/DAPIAtv/DAPMAt//DAPQAt//DAPUAuP/CAPYAuf/CAPcAuv/CAPgAuv/CAPkAu//BAPoAvP/BAPsAvf/BAPwAvf/BAP0Avv/AAP4Av//AAP8AwP/AAAAAFwAAAGgJCwkGBgkJCQkJCQkICAkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQsJCQkJCQkJCQkICQkJCQkJCQkJCQkJCQoJCQkJCQkJCQkJCQkJCQkJCQkJCQAAAAoLCgcHCgoKCgoKCgoLCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCwoKCgoKCgoKCgkKCgoKCgoKCgoKCgoKCwoKCgoKCgoKCgoKCgoKCgoKCgoKAAAACwwLBwcLCwsLCwsLCwoLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCgsKCgsKCwsLCgsLCwsLCwsLCgsLCwsLCwsLCwsLCwoLCwoLCwsLCwsMCwsLCgsLCgsLCwsLCwsLCwoLCwsAAAAMDQwICAwMDAwMDAwLCwwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwNDA0NDA0MDAwNDAwMDAwMDA0NDAwMDAwMDAwNDAwMDQwMDQwMDAwMDAwMDAwNDAwNDAwMDAwMDAwMDQwMDAAAAA0PDQkJDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ4NDg4NDg0NDQ4NDQ0NDQ0NDw4NDQ0NDQ0NDQ0NDQ0ODQ0ODQ0NDQ0NDg0NDQ4NDQ4NDQ0NDQ0NDQ0ODQ0NAAAADxAPCgoPDw8PDw8PEA8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PEA8PDw8PDw8PDw8PDw8QDw8PDw8PDw8PDw8PDw8PDw8PDw8AAAAQERALCxAQEBAQEBAPDxAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBEQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBEQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABETEQsLERERERERERAQERERERERERERERERERERERERERERERERERERERERERERERERERERERERExERERERERERERAREREREREREREREREREhERERERERERERERERERERERERERAAAAExQTDQ0TExMTExMTExITExMTExMTExMTExMTExMTExMTExMTExMTEhMSEhMSExMTEhMTExMTExMTEhMTExMTExMTExMTExITExITExMTExMUExMTEhMTEhMTExMTExMTExITExMAAAAVFxUODhUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUWFRYWFRYVFRUWFRUVFRUVFRcWFRUVFRUVFRUVFRUVFhUVFhUVFRUVFRYVFRUWFRUWFRUVFRUVFRUVFhUVFQAAABgZGBAQGBgYGBgYGBcXGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgY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AHUAbABhAHIAVgBlAHIAcwBpAG8AbgAgADEALgAwADAAMABTAGMAcgBpAGIAZQBFAGkAcgBlAC0AUgBlAGcAdQBsAGEAcgBEAGEAbQBpAGUAbgAgAEcAdQBhAHIAZABEAGEAbQBpAGUAbgAgAEcAdQBhAHIAZABoAHQAdABwAHMAOgAvAC8AZQBuAHYAeQB0AGUAYwBoAC4AYwBvAG0AaAB0AHQAcABzADoALwAvAGQAYQBtAGkAZQBuAGcALgBjAG8AbQACAAAAAAAA/84AZAAAAAEAAAAAAAAAAAAAAAAAAAAAAGMAAAECAAIAAwAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGQAaABsAHAAdAB4AHwAgACEAIgAjACQAJQAmACcAKAApACoAKwAsAC0ALgAvADAAMQAyADMANAA1ADYANwA4ADkAOgA7ADwAPQA+AD8AQABBAEIARABFAEYARwBIAEkASgBLAEwATQBOAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAF4AXwBgAGEAhQCLAAQETlVMTAAAAAAAAAMACAACABAAAf//AAM=";


      }
}

themes {
   theme {
      screen {
          paragraph_spacing_multiplier = 1
      }

      status_bar {
         : fixed_text "THE CHRISTMAS CAVE OF MAGIC" ;
         : header_text;
      }

      colors {
         status_bar_paper = 9
         status_bar_pen = 14
      }

      theme_settings {
         font = userfont_scribe_eire
      }
   }
}

3.26.4. Unicode Mappings

Note
Only the default Adventuron font (Bamburgh) adds arrows presently. Imported fonts by default do not display arrow characters.
Note
Unicode slot customization for arrows will be added in a future release of Adventuron.
Direction Unicode

North

0x2191

NE

0x2b08

East

0x2192

SE

0x2b0a

South

0x2193

SW

0x2b0b

West

0x2190

NW

0x2b09

Up

0x2b71

Down

0x2b73

If you want to make your own font for your own game, you need to tell Adventuron that your font supports these arrows as follows:

assets {
   fonts {
      userfont_myfont : base64_ttf "BASE64HERE" supports_arrows = "true" ;
   }
}

TODO : Need to document how to switch off arrows from fonts that support arrows (text decoration).

3.26.5. Google Fonts

Support for Google fonts will be added soon.

3.27. Grammar

Adventuron uses the Rion object notation, and Rion allows for blocks to be defined in multiple ways, as shown the examples below:

// Form 1

lamp : object {
   text = a dusty lamp
   at   = forest
   msg  = A very very dusty lamp
}

// Form 2

lamp : object {
   text = "a dusty lamp"
   at   = "forest"
   msg  = "A very very dusty lamp"
}

// Form 3

lamp : object "a dusty lamp" at="forest" msg="A very very dusty lamp." ;

// Form 4 (hybrid)

lamp : object "a dusty lamp" {
   at   = "forest"
   msg  = A very very dusty lamp
}

3.28. Reserved IDs

Objects IDs and location IDs are not permitted to be one the following:

all

ambiguous

back

blocked

cannot_move

current_location

direct

error

ether

forward

indirect

inventory

inventory_notworn

inventory_worn

it

not_created

player

player_zone

root

s1

s2

story

surface

unknown

3.29. Reporting Bugs

If you have a bug to report regarding adventuron, please report here (github account required).

3.30. Collections (Advanced Users Only)

Warning
This section is rather advanced, and 99% may never need these features so feel free to ignore.

Collections are data structures that can hold multiple values. You create them using the collections {} section (lots of code snippets later).

There are currently only two types of collections.

  • list - Stores items in insertion order, duplicates permitted.

  • set - Stores items in insertion order, duplicates will be ignored (slower insertion performance).

Collections were used in THE PATH to semi-randomize the order of the obsticles, but there are many other uses of collections.

In Adventuron, Collections can only store string values, but those string values can be converted to an integer number by using the int() function.

3.30.1. collection_clear

This will clear down (remove all items) from a collection.

   : collection_clear "my_list_1";

3.30.2. collection_get

collection_get is a string function that returns a string result

start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

collections {
   my_list : list {
      items     = [
         one,
         two,
         three,
         4,
         5
      ]
   }
}

on_startup {
   // collection_get will always return a string type
   : print {(
      collection_get{
         collection -> ("my_list")
         index -> ( 2 )
      }
   )}
   // Will print 20, 4th list element multiplied by 3rd list element
   // We add the + "" at the end to cast to a string.
   : print {( (int(collection_get{ collection -> ("my_list") index -> ( 4 ) }) *
      int(collection_get{ collection -> ("my_list") index -> ( 3 ) })) + "" )}
   : press_any_key ;
}

3.30.3. collection_count

Counts the number of elements in a collection.

: if (collection_count("my_list") > 0) {
   : print "There is more than one item in the list";
}

3.30.4. collection_intersect

start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

collections {
   my_list_1 : list {
      items = [  dog, cat, poodle ]
   }
   my_list_2 : list {
      items = [  dog, poodle ]
   }
   my_list_3 : list;
}

on_startup {
   // store the common items between list 1 and list 2 in list 3
   : collection_intersect {
      collection_1 = my_list_1
      collection_2 = my_list_2
      result       = my_list_3
   }
   : collection_iterate "my_list_3" {
      : print {(item())}

   }
   : press_any_key ;

}

3.30.5. collection_iterate

start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

collections {
   my_list : list {
      items     = [
         one,
         two,
         three,
         four,
         five
      ]
   }
}

on_startup {
   // Iterates over each element in 'my_list'
   // The item() function will return the string
   // at the current element. item() always returns
   // a string, so you will need to wrap in int()
   // to process as a number.
   : collection_iterate "my_list" {
      : print {(item())}
   }
   : press_any_key ;
}

3.30.6. collection_modify

start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

collections {
   my_list : list;
}

strings {
   tmp : string ;
}

on_startup {

   : collection_push { collection = "my_list" content -> ("one") }
   : collection_push { collection = "my_list" content -> ("two") }
   : collection_push { collection = "my_list" content -> ("three") }
   : collection_push { collection = "my_list" content -> ("four") }
   : collection_push { collection = "my_list" content -> ("five") }
   : collection_modify { collection = "my_list" index -> (0) content -> ("ONE") }
   : collection_modify { collection = "my_list" index -> (2) content -> ("THREE") }

   : collection_iterate "my_list" {
      : print {(item())}
   }
   : press_any_key ;
}

3.30.7. collection_push

start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

collections {
   my_list : list;
}

on_startup {

   : collection_push { collection = "my_list" content -> ("one") }
   : collection_push { collection = "my_list" content -> ("two") }
   : collection_push { collection = "my_list" content -> ("three") }
   : collection_push { collection = "my_list" content -> ("four") }
   : collection_push { collection = "my_list" content -> ("five") }

   : collection_iterate "my_list" {
      : print {(item())}
   }
   : press_any_key ;

}

3.30.8. collection_pop

start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

collections {
   my_list : list;
}

strings {
   tmp : string ;
}

on_startup {

   : collection_push { collection = "my_list" content -> ("one") }
   : collection_push { collection = "my_list" content -> ("two") }
   : collection_push { collection = "my_list" content -> ("three") }
   : collection_push { collection = "my_list" content -> ("four") }
   : collection_push { collection = "my_list" content -> ("five") }

   : collection_iterate "my_list" {
      : print {(item())}
   }

   : print "-----";
   : collection_pop  { collection = "my_list" var = "tmp" }
   : print {(tmp)}
   : collection_pop  { collection = "my_list" var = "tmp" }
   : print {(tmp)}
   : collection_pop  { collection = "my_list" var = "tmp" }
   : print {(tmp)}
   : collection_pop  { collection = "my_list" var = "tmp" }
   : print {(tmp)}
   : collection_pop  { collection = "my_list" var = "tmp" }
   : print {(tmp)}
   : press_any_key ;
}

3.30.9. collection_remove

start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

collections {
   my_list : list {
      items     = [
         one,
         two,
         three,
         4,
         5
      ]
   }
}

on_startup {
   : collection_remove { collection -> ("my_list") index -> (1) }
   : print {( collection_get{ collection -> ("my_list") index -> ( 2 ) } )}
   : press_any_key ;
}

3.30.10. collection_sort

Note
In the following example, the item() function returns the textual content of the next item in the list.
start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

collections {
   my_list : list {
      items     = [
         one,
         two,
         three,
         four,
         five
      ]
   }
}

on_startup {
   : collection_sort collection = "my_list" algorithm = "shuffle" ;
   : collection_iterate "my_list" {
      : print {(item())}
   }
   : press_any_key ;
}

3.30.11. collection_subtract

start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

collections {
   my_list_1 : list {
      items = [  dog, cat, poodle ]
   }
   my_list_2 : list {
      items = [  dog, poodle ]
   }
   my_list_3 : list;
}

on_startup {
   // store the common items between list 1 and list 2 in list 3
   : collection_subtract {
      collection_1 = my_list_1
      collection_2 = my_list_2
      result       = my_list_3
   }
   : collection_iterate "my_list_3" {
      : print {(item())}

   }
   : collection_clear "my_list_1";
   : press_any_key ;

}

3.30.12. collection_union

Stores the common elements between two collections in a third collection. Duplicates are removed.

start_at = my_location

locations {
   my_location : location "You are in a room." ;
}

collections {
   my_list_1 : list {
      items = [  dog, cat, poodle ]
   }
   my_list_2 : list {
      items = [  dog, poodle, bat ]
   }
   my_list_3 : list;
}

on_startup {
   // store the common items between list 1 and list 2 in list 3
   : collection_union {
      collection_1 = my_list_1
      collection_2 = my_list_2
      result       = my_list_3
   }
   : collection_iterate "my_list_3" {
      : print {(item())}

   }
   : press_any_key ;

}

3.30.13. Listing subobjects

start_at = my_location

locations {
   my_location      : location "You are in a room." ;
}

objects {

   cupboard : scenery "{cupboard_description}"
      at             = "my_location"
      container_type = "bag"
   ;

   book     : object "a book" at = "cupboard" ;

   bowl     : object "a bowl" at = "cupboard" ;

}

collections {
   list_object_buffer : list;
}

strings {
   cupboard_description : string;
}

on_pre_describe {
   : if (is_present "cupboard") {
      : set_string var = "cupboard_description"  text = "a cupboard" ;
      : if (child_count "cupboard" > 0) {
         : look_inside
            of               = "cupboard"
            extract_the      = "description"
            store_results_in = "list_object_buffer"
            make_known       = "true"
         ;
         : print_list_verbose  "list_object_buffer"
            lead_in       = " (containing "
            final_part    = ")"
            append_to_var = "cupboard_description"
         ;
      }
   }
}

3.31. Language Support

If you want to write a game in a different language, here is a template for changing the system verbs, directions, and system messages …​.

Note
Native support of language is difficult, and this approach uses the English language parser rules underneath. This template only useful only for VERB / NOUN style games.
######################################
#  Translation example
#
#  NOTE : Only really works on VERB NOUN style languages
#
#  STEPS
#
#  (1) Associate translated verbs with the system verbs
#  (2)
#
######################################

start_at     = my_location

######################
## NOTE : We are still internally using English language parser grammar rules
######################

language     = english

start_theme  = mytheme

locations {
   my_location : location "You are in a room." ;
}

#############################
## Step 1
#############################

vocabulary {

   // Here we assocated new words with the already supported english system vocab
   : verb / aliases = [examine,   examinetranslated   ]
   : verb / aliases = [get,       gettranslated       ]
   : verb / aliases = [drop,      droptranslated      ]
   : verb / aliases = [inventory, inventorytranslated ]
   : verb / aliases = [look,      looktranslated, looktranslated2, looktranslated3 ]
   : verb / aliases = [quit,      quittranslated      ]
   : verb / aliases = [help,      helptranslated      ]

}


themes {
   mytheme : theme {

      ##########################################
      ## Step two - rewrite system messages
      ##          - order of the compass directions matters, and must be translated in full (all 12)
      ##########################################
      system_messages {
         compass                                        = [north, northeast, east, southeast, south, southwest,  west, northwest, up, down, enter, exit]
         compass_short                                  = [n, ne, e, se, s, sw, w, nw, u, d, in, out]
         all_treasures_found_win_game                   = Congratulations, you found all the treasures. You have won!
         already_in_container                           = ${entity} is already inside the ${entity2}.
         ask_new_game                                   = Would you like to start a new game?
         ask_quit                                       = Do you wish to quit the game?
         be_more_specific                               = Be more specific ...\s
         cannot_carry_any_more                          = You cannot carry any more items.
         cannot_carry_any_more_weight                   = It's too heavy for you to carry.
         cant_see_one_of_those                          = You can't see one of those.
         cant_take                                      = You can't take it.
         dont_have_one_of_those                         = You don't have one of those!
         exit_list_additional_exits_are_located_verbose = Additional exits are located\s
         exit_list_end_text                             =
         exit_list_end_text_verbose                     = .
         exit_list_from_here_you_can_go_verbose         = You can go\s
         exit_list_header_concise                       = Exits :\s
         exit_list_last_sep_verbose                     = \sand\s
         exit_list_sep_verbose                          = ,\s
         exit_list_there_are_no_obvious_exits           = There are no obvious exits.
         exit_list_to_the_verbose                       = to the
         exit_list_you_can_also_go_verbose              = You can also go\s
         gamebook_question                              = Select An Option ...
         i_cant_do_that                                 = Not right now.
         invalid_choice                                 = Invalid choice.
         inventory_list_empty                           = Nothing
         inventory_list_end_text                        = .
         inventory_list_final_separator                 = \sand\s
         inventory_list_header                          = You are carrying:\s
         inventory_list_header_verbose                  = You are carrying\s
         inventory_list_separator                       = ,\s
         it_is_dark                                     = It is dark. You can't see a thing.
         must_remove_first                              = Try taking it off first.
         not_carried                                    = You can't ${verb} something you are not carrying.
         not_present                                    = ${entity} is not here.
         nothing_here                                   = There is nothing here.
         nothing_to_get                                 = You look around but can't see any ${noun} anywhere!
         object_list_empty                              = Nothing
         object_list_end_text                           = .
         object_list_final_separator                    = \sand\s
         object_list_header                             = You see :\s
         object_list_header_verbose                     = You see\s
         object_list_separator                          = ,\s
         ok                                             = OK
         on_drop                                        = You drop ${entity}.
         on_get                                         = You take ${entity}.
         on_put                                         = You put ${entity} inside ${entity2}.
         on_put_non_container                           = ${entity} is not a container.
         on_put_non_surface                             = ${entity} is not a surface.
         on_remove                                      = You take off ${entity}.
         on_wear                                        = You wear ${entity}.
         post_quit                                      = You have quit the game.
         prior_prompt                                   = What Now?
         prompt                                         = >>
         question_prompt_char                           = ?
         restore_from_autosave                          = Restore from Autosave?
         there_is_nothing_you_can                       = There is nothing you can ${verb} at the moment.
         treasure_message                               =
         treasure_suffix                                =
         unknown_noun                                   = This game does not require use of the word "${noun}".
         unknown_verb                                   = This game does not require use of the word "${verb}".
         worn_suffix                                    = \s(worn)
         you_already_wear                               = You are already wearing that.
         you_are_already_carrying                       = You already have ${entity}.
         you_are_not_holding                            = You are not holding ${entity}.
         you_cant_go_that_direction                     = You can't go that way.
         you_cant_wear                                  = You can't wear that.
         you_cant_wear_anything_else                    = You can't wear anything else without removing something first.
         you_dont_wear                                  = You are not wearing that.
         you_see_nothing_special                        = You see nothing special.
      }
   }

}

A smaller example of how to alias system verbs (in this case open and unlock).

start_at = room_1

locations {
   room_1  : location "You are in room 1. A door leads east." ;
   room_2 : location "You are in room 2. A door leads west." ;
}

connections {
   from, direction, to = [
      room_1, east, room_2,
   ]
}

objects {
   key : object "a key" at = "inventory" ;
}

vocabulary {
   : verb / aliases = [unlock, aaa]
   : verb / aliases = [open, bbb]
}

barriers {
   my_door : door {
      from = room_1
      to   = room_2
      key  = key
   }
}

3.32. Spanish Vocabulary

Below is a list of the standard vocabulary mappings into Spanish.

English Meaning Spanish Mappings

GO

"ir"

NORTH

"n", "norte"

WEST

"o", "oeste"

SOUTH

"s", "sur"

EAST

"e", "este"

NORTHEAST

"ne", "noreste"

NORTHWEST

"no", "noroeste"

SOUTHEAST

"se", "sureste"

SOUTHWEST

"so", "suroeste"

EXIT

"salir"

ENTER

"entrar"

UP

"arriba", "subir", "sube"

DOWN

"abajo", "bajar", "baja"

DROP

"soltar", "dejar"

TAKE_AMERICAN

"obtener", "coger", "tomar"

TAKE_NON_AMERICAN

"obtener", "coger"

LOOK

"mirar", "m"

EXAMINE

"examinar", "exam", "ex", "x"

INVENTORY

"inventario","i"

REMOVE

"quitar"

WEAR

"vestir", "desgaste", "poner"

SAVE

"salvar", "guardar", "grabar"

LOAD

"carga", "cargar","restaurar"

QUIT

"fin"

ARTICLES

"el", "la","lo", "los", "las", "del", "un", "una", "unos", "unas"

VERB_IT_SUFFIXES

"mela","melo","la","lo"

OOPS

"uy"

GOTO

"viaje"

BLIP

"blip"

MUSIC

"música", "musica"

HELP

"help", "ayuda"

TURNS

"vueltas"

OFF

"desactivar", "off"

ON

"activar", "on"

RAMSAVE

"ramsave"

RAMLOAD

"ramload"

OPEN

"abrir", "abierto", "carta"

CLOSE

"cerrar"

LOCK

"cerradura"

UNLOCK

"desbloquear"

DOOR

"puerta"

PUSH

"empuje"

PULL

"tirar"

WAIT

"espere", "esperar"

OBJECTS

"objetos"

OUT_OR_FROM

"fuera", "de"

IN_OR_INTO

"en", "a"

PUT

"poner", "colocar"

ALL

"todas", "todo"

SEARCH

"búsqueda", "buscar", "encontrar"

GRAPHICS

"gr\u00e1ficos","graficos"

SCORE

"marcar", "puntuaci\u00f3n"

TIME

"hora"

EXITS

"salidas", "x"

EXCEPT

"excepci\u00F3n", "excepcion"

YES

"s\u00ed", "si", "y", "yes"

NO

"no", "n"

DEBUG

"depurar", "debug"

REWIND

"rebobinar", "deshacer"

REPLAY

"repetición", "rehacer"

DEFAULT1

"predeterminado", "default"

3.33. Links / Contact Info

Documentation + Videos

Games

Chatroom

Forum

  • If you want to ask questions, the Interactive Fiction Community Forum is frequently monitored. If it is an Adventuron specific question, use Adventuron as the prefix of your subject (or add Adventuron as the tag).

Game Jams

Game jams are game competitions that anyone is free to enter.

Usually they have a theme or a set of rules that each participant must abide by in order to add some structure and to make it interesting.

  1. Adventuron Cavejam 2019 - Remix The Cave of Magic.

  2. Adventuron Halloween Jam - Make a Spooky Game.

  3. Treasure Hunt Jam - Make a text only 'treasure hunt' style game with limited word use.

  4. The Next Adventure Jam - Make a game with graphics using a bright vibrant palette.

  5. An Adventuron Christmas Jam - Make a game with the theme of "Christmas". Ran Nov 17th to Dec 21st, 2020.

  6. Text Adventure Literacy Jam - Create a TEXT ADVENTURE game suitable for children with no prior experience. Lots of prizes to be won including a Raspberry Pi 400 Desktop Computer. Runs Feb 25th to March 31st, 2021.

Text Adventure Literacy Project

Game Design Resources

  • Puzzle Dependency Charts, the 2014 blog post on how to build puzzle chains by Monkey Island co-creator, Ron Gilbert.

  • Puzzlon, a puzzle dependency chart creation tool by Chris Ainsley (desktop PC required) Sample Diagram. Please note that Puzzlon does not code puzzles, it only visualises puzzle dependencies, and even though the UI is similar to Adventuron, it is a completely independant system and is open to non Adventuron users.

  • Text Adventure Design in 2020 by Chris Ainsley.

  • Look, Search, & Examine by Chris Ainsley.

Other Media Coverage

Interviews

Open Sourced Games

Some game authors have released the source code to their games.

Note
Open source is not the same as public domain, be sure to check the game licenses.

Blog Posts

Pixel Art Editors

Note
Adventuron Draw coming soon.

Graphics must be imported into Adventuron as PNG or GIF files. These external links are provided as a courtesy, please check the individual licenses of these tools.

Browser based :

Desktop based :

Visual Studio Code Plugin

Warning
Currently only syntax highlights (colours in the text). Future versions may add autocomplete functionality.

Visual Studio Code is a very popular text editors aimed at coders.

You can find a syntax highlighter for the object notation (used by Adventuron) in the VSCode marketplace, for free - here.

License

Created text adventures can be exported as HTML for non-commercial use.

Games exported to 8-bit text adventure engines are subject to those licenses.

Full details here.

Contact

Adventuron was developed by Chris Ainsley, and is copyright of Adventuron Software Limited.

Full credits are available here.

3.34. Cookbook (Advanced Users Only)

Click here to see a collection of code snippets.

4. Developing For 8-Bit

Click here to learn about developing games for 8-bit computers.

Warning
Please read this before developing a game for 8-bit. Not all features of Adventuron are mappable.
1920px ZX Spectrum Plus3
Figure 9. ZX Spectrum +3, public domain image (Wikipedia)
snext
Figure 10. ZX Spectrum Next, image from https://www.specnext.com (Copyright fair use)

5. Uploading to itch.io

Click here to learn how to upload your game to itch.io .

6. Troubleshooting

Adventuron Hangs on loading (Lots of messages apologising for the wait)

The first port of call is to hold CONTROL and press F5 in your browser window.

It is possible that your browser is caching a partially loaded version of the page and this will reload everything (refreshing the cache).

Control + Space doesn’t work in Opera

Opera browser decided that it wants CONTROL + SPACE for itself, and mapped this to its search functionality.

This means that code completion is not able to be used in Opera BY DEFAULT.

There is a remedy however.

Go to the Opera Menu (in the top left of the browser), then select SETTINGS from the menu.

Then go to the bottom of the setting spage, and click ADVANCED, then in that very long page of setttings, locate the setting:

CONFIGURE SHORTCUTS

In this page, locate an item that says "Ctrl + Space" and hover over it and click the X icon. This will allow Adventuron to use CONTROL + SPACE for itself.

Recursion Error

If you see an error message like the following, it (likely) means that you have accidentally triggered an infinite redescribe loop.

DEBUGEXCEPTION : Redescribe recursion detected in T2, T3 or T4 blocks.

or

DEBUGEXCEPTION : Class$S300: (RangeError) : Maximum call stack size exceeded

When executing the code shown below, start the game, and move west. An error will be displayed in the gameplay window.

start_at = village

locations {
   village  : location "You are in the village" ;
   forest_1 : location "You are in a forest" ;
   forest_2 : location "You are in a spooky forest" ;
}
connections {
   from, direction, to = [
      village, east, forest_1,
      forest_1, east, forest_2,
   ]
}
on_describe {
   : if (is_at "forest_1") {
      : redescribe;
   }
}

The cause of the error is this block of code.

on_describe {
   : if (is_at "forest_1") {
      : redescribe;
   }
}

Adventuron does the following logic upon describing a location (simplified to illustrate the point):

  1. Hide (or disable) the prompt.

  2. Describe the location

  3. Run the on_describe {} block

  4. Run the on_tick {} block.

  5. Update some system settings.

  6. Show the prompt again ready for next input.

During step 3 (on_describe{})and step 4 (on_tick{}), Adventuron allows the author to execute the : redescribe command, which will go back to step 2, and move forward again. This is sometimes necessary, for example, a cut scene may occur, and some story delivered, then at the end of it, we wish to redisplay the location afresh.

The recursion error happens if the redescribe is not sufficiently "guarded". That is, every time it redescribes, it re-runs the redescribe.

To stop this from happening, make sure that your redescribe is guarded, so that when you redescribe, it doesn’t just redescribe again.

e.g.

   : if (is_at "forest_1" && is_just_entered()) {
      : redescribe;
   }

Why isn’t my sound playing?

Adventuron uses a permissions system that requires active consent for playing sounds and music. Graphics consent is assumed true but can be revoked with GRAPHICS OFF.

If your sound isn’t playing when in development, check the following diagnostics

on_command {
   : match "permissions _" {
      : print {( "sysvar_features_sound : "   + sysvar_bool "sysvar_features_sound" )}
      : print {( "sysvar_features_music : "   + sysvar_bool "sysvar_features_music" )}
      : print {( "sysvar_features_blip : "    + sysvar_bool "sysvar_features_blip" )}
      : print {( "sysvar_has_asked_blip : "   + sysvar_bool "sysvar_has_asked_blip" )}
      : print {( "sysvar_has_asked_music : "  + sysvar_bool "sysvar_has_asked_music" )}
      : print {( "sysvar_has_asked_sound : "  + sysvar_bool "sysvar_has_asked_sound" )}
      : print {( "sysvar_blip_enabled : "     + sysvar_bool "sysvar_blip_enabled" )}
      : print {( "sysvar_sound_enabled : "    + sysvar_bool "sysvar_sound_enabled" )}
      : print {( "sysvar_music_enabled : "    + sysvar_bool "sysvar_music_enabled" )}
      : print {( "sysvar_sfx_enabled : "      + sysvar_bool "sysvar_sfx_enabled" )}
      : print {( "sysvar_ambient_enabled : "  + sysvar_bool "sysvar_ambient_enabled" )}
      : print {( "sysvar_graphics_enabled : " + sysvar_bool "sysvar_graphics_enabled" )}
   }
}

7. Text Adventure Literacy

Adventuron supports to the text adventure literacy project, which is an open initiative to teach younger players how to play text-based games.

TALP games must be designed to teach absolute beginners how to play text adventure games, in-game.

Read more about the Text Adventure Literacy Project here..

The following games are recommended:

8. Licenses / Acknowledgements

Adventuron Classroom License

Adventuron & Adventuron Classroom is licensed for personal non-commercial use.

Adventuron Classroom License
Adventuron Classroom - Personal Non Commercial Use EULA

Copyright of Adventuron Software Limited, 2017-2020, all rights reserved.

Licensed for personal non-commercial use only.

Adventuron is intended to be a CREATIVE TOOL. Adventuron should NOT be used to recreate or resemble existing game titles WITHOUT EXPRESS PERMISSION of all copyright holders.

In no event will Adventuron Software Limited be liable for any loss or damage including without limitation, indirect or consequential loss or damage, or any loss or damage whatsoever arising from loss of data or profits arising out of, or in connection with, the use of this website.

All adventure data is stored locally, and not transmitted nor stored on the server. Some functions may communicate with the server but no personal information will be transmitted.

Adventuron's engine / generated HTML gamefiles are not licensed for commercial use.

By clicking on the "I Agree" button below, you agree to NOT infringe upon any copyright. In addition, by clicking the "I Agree" button you also agree to the use of cookies and web storage for storing data pertinent to the application purpose.

"Adventuron Classroom" Tutorial Documentation

This tutorial is written by Chris Ainsley, and copyright of Adventuron Software Limited.

This tutorial may not be redistributed on any other domain than adventuron.io.

The Cave of Magic

The Cave of Magic was designed and written by Chris Ainsley is placed into the public domain.

The graphics in the DX version of the game were created and are copyright of Ricardo Oyón. Ricardo has licensed the graphics for use with Adventuron’s tooling but the graphics should not be re-used anywhere else without express permission.

Excalibur: Sword of Kings

The original ZX Spectrum version of Excalibur was written in 1987 by Ian Smith and Shaun McClure.

The version used in this course written by Chris Ainsley based on the behaviour of the original.

The source code used in this tutorial was written by Chris Ainsley and is copyright of Adventuron Software Limited.

Excalibur: Sword of Kings (all versions) is Copyright of Adventuron Software Limited, All Rights Reserved.

Adventuron Engine License

Adventuron’s game engine is licensed for non-commercial use only.

Full license text here:

/* ADVENTURON Engine 1.0.0 - NON COMMERCIAL USE EULA                               */
/* Copyright (C) 2017 - 2021 Adventuron Software Limited                           */
/*                                                                                 */
/* ADVENTURON Engine is permitted to be redistributed for personal non-commercial  */
/* use except when game content contains one or more of the following items:       */
/*  (1) Hate Speech (such as racism, sexism, ableism, homophobia, religious
        hatred, etc).                                                              */
/*  (2) Content for which you do not own the intellectual property rights.         */
/*  (3) Adult content (including innuendo), express or implied, that is not        */
/*      clearly marked/warned via the title screen as such.                        */
/*  (4) Pornograpic Content.                                                       */
/*  (5) Illegal content.                                                           */
/*  (6) Grossly offensive material, express or implied.                            */
/*  (7) Content involving the exploitation of minors, express or implied.          */
/*  (8) Libellous speech or content, express or implied.                           */
/*  (9) Harassment, threats or intimidation, express or implied.                   */
/*                                                                                 */
/* The software is provided "as is", without warranty of any kind, express or      */
/* implied, including but not limited to the warranties of merchantability,        */
/* fitness for a particular purpose and noninfringement. In no event shall         */
/* the authors or copyright holders be liable for any claim, damages or            */
/* other liability, whether in an action of contract, tort or otherwise,           */
/* arising from, out of or in connection with the software or the use or           */
/* other dealings in the software.                                                 */

Adventuron’s brand name and image is trademark of Adventuron Software Limited.

The platform (editor / tutorial / etc), is strictly not for redistribution.

Libraries Used By Adventuron Engine (1.0.0)

Supporting Library Licenses:

/* ------------------------------------------------------------------------------- */
/* OPEN SOURCE LICENSES                                                            */
/* ------------------------------------------------------------------------------- */
/* GWT - https://github.com/gwtproject                                             */
/*                                                                                 */
/* Apache Version 2.0 License                                                      */
/* http://www.gwtproject.org/terms.html                                            */

/* Elemental 2 - https://github.com/google/elemental2                              */
/* Apache Version 2.0 License                                                      */
/* http://www.gwtproject.org/terms.html                                            */
/* Blazing Chain LZW Library :                                                     */

/* https://github.com/tommyettinger/BlazingChain                                   */

/* MIT License                                                                     */

/* Copyright (c) 2016 Tommy Ettinger                                               */

/* Permission is hereby granted, free of charge, to any person obtaining a copy    */
/* of this software and associated documentation files (the "Software"), to deal   */
/* in the Software without restriction, including without limitation the rights    */
/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell       */
/* copies of the Software, and to permit persons to whom the Software is           */
/* furnished to do so, subject to the following conditions:                        */

/* The above copyright notice and this permission notice shall be included in all  */
/* copies or substantial portions of the Software.                                 */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR      */
/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,        */
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE     */
/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER          */
/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,   */
/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE   */
/* SOFWARE.                                                                        */

/*! howler.js v2.0.14 | (c) 2013-2018, James Simpson of GoldFire Studios | MIT License | howlerjs.com */

/* ------------------------------------------------------------------------------- */

/* JSZip - A Javascript class for generating and reading zip files                 */
/* <http://stuartk.com/jszip>                                                      */

/* (c) 2009-2014 Stuart Knightley <stuart [at] stuartk.com>                        */
/* Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. */

/* JSZip uses the library zlib.js released under the following license :           */
/* zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License       */

/* ------------------------------------------------------------------------------- */

/* Beepbox by John Nesky*/

/*
Copyright (C) 2018 John Nesky

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/* ------------------------------------------------------------------------------- */

/* GWT Promptly - https://github.com/ainslec/gwt-promptly                          */
/*
 * Copyright 2017, Chris Ainsley
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

Libraries Used by Adventuron Platform - Including Adventuron and Adventuron Classroom (1.0.0)

The platform uses the same open source licenses as the engine, some privately licensed non-open-source libraries, and the following open source libraries:

/* DOMINO UI - https://github.com/DominoKit/domino-ui */

/*
 * Copyright 2019, Domino UI Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* Ace Editor - https://github.com/ajaxorg/ace */
/* Copyright (c) 2010, Ajax.org B.V. */
/* All rights reserved.
/*
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions are met: */
/*     * Redistributions of source code must retain the above copyright */
/*       notice, this list of conditions and the following disclaimer. */
/*     * Redistributions in binary form must reproduce the above copyright */
/*       notice, this list of conditions and the following disclaimer in the */
/*       documentation and/or other materials provided with the distribution. */
/*     * Neither the name of Ajax.org B.V. nor the */
/*       names of its contributors may be used to endorse or promote products */
/*       derived from this software without specific prior written permission. */

/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
/* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY */
/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */
/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */


/* ACE GWT https://github.com/daveho/AceGWT */
/* MIT License - Copyright (c) 2011 - 2019 David Hovemeyer & AceGWT Contributers */

/* asciidoctor.js - https://github.com/asciidoctor/asciidoctor.js */

/* The MIT License
 *
 * Copyright (C) 2014-2019 Dan Allen, Guillaume Grossetie, Anthonny Quérouil and the Asciidoctor Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
 /* akjava / GWTJSZip by Aki Miyazaki                                               */
  /* Apache Version 2.0 License                                                      */
  /* https://github.com/akjava/GWTJSZip/blob/master/LICENSE                          */
  /* FileSaver.js - https://github.com/eligrey/FileSaver.js */
  /* Copyright © 2016 Eli Grey. */
  /* MIT License */


 /* Mali Font - https://github.com/cadsondemak/Mali */

 /* Copyright 2018 The Mali Project Authors
  * (https://github.com/cadsondemak/Mali)
  *
  * This Font Software is licensed under the SIL Open Font License, Version 1.1.
  * This license is copied below, and is also available with a FAQ at:
  * http://scripts.sil.org/OFL
  */

Acknowledgements

  • Thank you to Mark Harrison for the excellent art present in the embedded version of this document, in addition to his superb work in the Retro Gamer full page ad (issue 193). Check out Mark’s Facebook group here.

  • Thank you to the creators of the AsciiDoc documentation format, and the AsciiDoctor team, for the amazing AsciiDoctor JS project.

  • Thank you to the GWT project, and especially to Colin Alworth for his support and passion behind the project.

  • Thank you to Nick Manarin for the really rather good ScreenToGif utility, which was used in the production of this documentation.

  • Thank you to the Domino UI team, for their excellent UI framework (used in the documentation).

  • Thank you to Andy Green, Shaun McClure, Steve Horsley, Gareth Pitchford, Tim Gilberts, Richard Pettigrew, Mark Hardisty, and others for their encouragement and support.

  • Thank you to Shaun McClure and Ian Smith for writing Excalibur - which I believe was an ideal adventure game with which to teach the concepts of building a basic adventure.

  • Thank you to Alternative Software Limited for selling the rights to Excalibur, and to Ian & Shaun for their blessing of the sale.

  • Thank you to the Font Awesome team for their icon set, and to the Mali Font creators for an excellent legible yet fun font.

  • Thank you to John Wilson, Gareth Pitchford, and Richard Pettigrew for being early adopters of the system.

  • Thank you to Andrés Samudio for making the DAAD system, and the DAAD system font public domain, and for his enthusiastic support of this project.

  • Thank you to Paul Van Der Laan, for making the Clairsys font, and for making the Clairsys 10 variant, both available under the SIL font license.

  • Thank you to Fergus McNeill for allowing commercial and non-commercial use of the Delta 4 font (adapted as the Delta 10 font).

  • Thank you to Ricardo Oyón for donating the wonderful graphics used in The Cave of Magic DX (tutorial A), plus for his supplemental art (including the volcano landscape used at the top of the user guide).

Resources / License

Documentation + Videos

Games

Chatroom

Forum

  • If you want to ask questions, the Interactive Fiction Community Forum is frequently monitored. If it is an Adventuron specific question, use Adventuron as the prefix of your subject (or add Adventuron as the tag).

Game Jams

Game jams are game competitions that anyone is free to enter.

Usually they have a theme or a set of rules that each participant must abide by in order to add some structure and to make it interesting.

  1. Adventuron Cavejam 2019 - Remix The Cave of Magic.

  2. Adventuron Halloween Jam - Make a Spooky Game.

  3. Treasure Hunt Jam - Make a text only 'treasure hunt' style game with limited word use.

  4. The Next Adventure Jam - Make a game with graphics using a bright vibrant palette.

  5. An Adventuron Christmas Jam - Make a game with the theme of "Christmas". Ran Nov 17th to Dec 21st, 2020.

  6. Text Adventure Literacy Jam - Create a TEXT ADVENTURE game suitable for children with no prior experience. Lots of prizes to be won including a Raspberry Pi 400 Desktop Computer. Runs Feb 25th to March 31st, 2021.

Text Adventure Literacy Project

Game Design Resources

  • Puzzle Dependency Charts, the 2014 blog post on how to build puzzle chains by Monkey Island co-creator, Ron Gilbert.

  • Puzzlon, a puzzle dependency chart creation tool by Chris Ainsley (desktop PC required) Sample Diagram. Please note that Puzzlon does not code puzzles, it only visualises puzzle dependencies, and even though the UI is similar to Adventuron, it is a completely independant system and is open to non Adventuron users.

  • Text Adventure Design in 2020 by Chris Ainsley.

  • Look, Search, & Examine by Chris Ainsley.

Other Media Coverage

Interviews

Open Sourced Games

Some game authors have released the source code to their games.

Note
Open source is not the same as public domain, be sure to check the game licenses.

Blog Posts

Pixel Art Editors

Note
Adventuron Draw coming soon.

Graphics must be imported into Adventuron as PNG or GIF files. These external links are provided as a courtesy, please check the individual licenses of these tools.

Browser based :

Desktop based :

Visual Studio Code Plugin

Warning
Currently only syntax highlights (colours in the text). Future versions may add autocomplete functionality.

Visual Studio Code is a very popular text editors aimed at coders.

You can find a syntax highlighter for the object notation (used by Adventuron) in the VSCode marketplace, for free - here.

License

Created text adventures can be exported as HTML for non-commercial use.

Games exported to 8-bit text adventure engines are subject to those licenses.

Full details here.

Contact

Adventuron was developed by Chris Ainsley, and is copyright of Adventuron Software Limited.

Full credits are available here.