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.
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.
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.
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. |
2.2. Tutorial B - 180 minute
Tutorial B is about 180 minutes.
Note
|
This is the tutorial that is built into Adventuron Classroom. |
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 (Beta 71)
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.
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.
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
Note
|
Adventuron requires that you specify objects with a leading article (if the object has an article), even if you don’t want to list your object with an article. Adventuron will convert to indefinate articles to definate articles when printing out a message referring to a particular object but it cannot guess which article should be used all by itself. |
Object Type | Details |
---|---|
object |
A normal takeable/droppable object. |
scenery |
An immovable object (cannot be picked up). |
objects { blue_spoon : object "a blue spoon"; }
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. |
objects { blue_spoon : object "a blue spoon" at="barn"; }
objects { hat : object "a stylish hat" at="barn" wearable="true"; }
objects { // Wearable is implicitly true if an object is initially worn hat : object "a stylish hat" at="inventory" worn="true"; }
objects { boulder : scenery "a huge boulder" at = "cliff"; }
objects { steel_bar : object "a steel bar" weight = "50" ; }
objects { grass : object "the grass" at="the_green" listed = "false" ; }
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". |
3.2.3. Non Listed Objects
You may wish to manually describe the presence of an object (or scenery object) in your location (usually via the on_describe {} section) without listing the object in the standard object list.
To do this, simply mark an object (or scenery object) as listed="false".
Non-listed 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" listed="false" msg="Sturdy"; gravestone : scenery "a gravestone" at="graveyard" listed="false" msg="Died 1692."; }
Non-listed 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).
start_at = waterfall locations { waterfall : location "You are standing at the base of the waterfall." } objects { elf : scenery "an elf" at="waterfall" listed="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
Note
|
Advanced users of Adventuron can use dynamic_boolean type booleans (in conjunction with block_when, and block_when_not) to create complex blocking conditions. |
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.
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.
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:
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. |
: exits ; |
Lists the exits in a location. |
: 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. |
: clear "VAR ID"; |
Will set a boolean to false, an integer to 0, a string to an empty string, or a collection to an empty collection. If used with dynamic variables, this command does nothing. |
: debug_vars; |
Prints all variables. |
: debug_sentence; |
Prints the current parsed sentence (useful for debugging the parser). |
: 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. |
: 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). |
: 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). |
: 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). |
: get "OBJECT_ID"; |
Gets the object that corresponds to supplied object id (only if object is available, and takeable in the current location). |
: 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). |
: drop "OBJECT_ID"; |
Drops the object that corresponds to supplied object id (only if object is available, and takeable/droppable in the current location). |
: 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). |
: examine; |
Examines the object that corresponds to the adjective and noun in the current parse sentence (only if object is present). |
: examine "OBJECT_ID"; |
Examines the object that corresponds to the adjective and noun in the current parse sentence (only if object is present). |
: 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). |
: 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 |
Manually manipulate the state of a door barrier. |
: 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. |
: split text="one two three" sep=" " result="my_list" ; |
Will create a collection from a string. |
: iterate "ITERATION CATEGORY" filter → (FILTER EXPRESSION) { … } |
Loop over elements and perform the operations in the { … } block (see the ITERATION section for more details). The filter attribute is optional. |
: clear "varname"; |
Clears the value of a collection (makes empty) , a boolean (sets false) , a string (makes empty) or an integer (makes 0) type. |
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_at "TRAIT_ID" |
Returns true if the player is at a location that has the referenced trait set. |
is_present "OBJECT_ID" |
Returns true if the referenced object is present (in the current players inventory, or in the current location). |
is_present "TRAIT_ID" |
Returns true if at least one object with the referenced trait 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_beside "TRAIT_ID" |
Returns true if at least one object with the referenced trait is in the current location. |
is_exists "OBJECT_ID" |
Returns true if the referenced object exists somewhere in the game world. |
is_exists "TRAIT_ID" |
Returns true if at least one object with the referenced trait 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_carried "TRAIT_ID" |
Returns true if at least one object with the referenced trait 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_holding "TRAIT_ID" |
Returns true if at least one object with the referenced trait 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_worn "OBJECT_ID" |
Returns true if at least one object with the referenced trait 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. |
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_debugger_available() |
Returns true if the current client is running on outside of a development environment (standalone). This |
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). |
noun2_is "noun" |
Returns true if the 2nd noun in the sentence equals the provided noun (or synonym). |
adjective1_is "adjective" |
Returns true if the 1st adjective in the sentence equals the provided adjective (or synonym). |
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. |
preposition_is "preposition" |
Returns true if the preposition in the sentence equals the provided preposition (or synonym). |
verb_is "verb" |
Returns true if the verb in the sentence equals the provided verb (or synonym). |
adverb_is "adverb" |
Returns true if the adverb in the sentence equals the provided verb (or synonym). |
item_has_trait "trait_id" |
Returns true if the current iteration item has a particular trait. |
is_first_iteration() |
Returns true if the first item in the iterator. |
is_final_iteration() |
Returns true if the last item in the current iterator. |
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:
: if (is_at "lair") { : set_integer var = "wolves_countdown" ( 1 + 2 + 2 ); }
You can reference variables on the right hand side if you want:
: 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 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. |
min(expr1, expr2, ….) |
Returns the minimum value from 2 or more integer expressions |
max(expr1, expr2, ….) |
Returns the maximum value from 2 or more integer expressions |
index() |
Returns the current iteration index (if inside an iterator). |
iterate_size() |
Returns the current number of items we are iterating over in the current scope (stack based implementation). |
previous_iterate_size() |
Returns the number of items in the last executed iterator (even if zero iterations occurred). |
count "ITERATION CATEGORY" |
Counts the number of elements in an iteration category (without having to iterate). |
choice_index() |
Will retreive the index of the currenly executed choice. |
choice_count() |
Gives you the number of choices (from the perspective of a choice handler). |
choice_buffer_count() |
Returns the number of choices in the choice buffer (subtely different to choice_count()). |
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 |
---|---|
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). |
current_location() |
Returns the id of the location the player is currently |
previous_location() |
Returns the id of the location the player was in in the last tick. |
item() |
The current item in a 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'. |
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'. |
choice_payload() |
(to be used in an add_choice handler) |
chosen() |
Returns the last choice selection. This will be the text of the choice, if no payload was specified. It will be the payload of the choice, if a payload was specified. |
construct_string { from = "my_list" sep = " " } |
Constructs a string from a collection |
pop() |
Pops an item from the stack (to be used in conjunction with : push command). |
one_of "collection_id" |
Selects an element from a collection at random. |
one_of "_inventory" |
Selects an element from the player inventory at random. |
one_of "ITERATOR_TARGET" |
Selects an element from any of the iterator targets (documented in the "Iterate" section). |
one_of (arg1,arg2,arg3,….) |
Selects one of a group of inner string functions at random. |
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. Iterate
The iterate command is used to over a list or set of data, usually over a list of ids.
A filter() parameter can be used to further specialise the iteration (example shown below). The filter expression to filter down the results prior to iteration, and sets up the item() string function to contain the current item. Using this, a boolean expression returning false will be omitted from the iteration set.
: iterate "_locations" { // Loops over ids of every location } : iterate "_entities" { // Loops over ids of every object } : iterate "_entities" filter -> (is_exists(item())) { // Loops over ids of every object that exists } : iterate "_ether" { // Loops over ids of every object that does not exists } : iterate "_inventory" { // Loops over ids of every object held by the player (directly) } : iterate "_inventory_deep" { // Loops over ids of every object held by the player // (directly or indirectly) } : iterate "_inventory_notworn" { // Loops over ids of every object held by the player that is not worn } : iterate "_inventory_notworn_wearable" { // Loops over ids of every object held by the player that is not worn but wearable } : iterate "_inventory_worn" { // Loops over ids of every object held and worn by the player } : iterate "_exits" { // Loops over the long description of the current player location exits } : iterate "_exits_visible" { // Loops over the long description of the visible exits of the current player location } : iterate "_beside" { // Loops over ids of every object directly in the current location } : iterate "_beside" filter-> (item_has_trait "t_hot" && item_has_trait "t_mettalic" == false ) { // Loops over ids of every object directly in the current // location that has the trait 't_hot' but does not have // the trait 't_metallic' } : iterate "_beside_listed" { // Loops over ids of every listed object directly in the // current location } : iterate "_beside_notlisted" { // Loops over ids of every non-listed object directly in the // current location } : iterate "_traits" { // Loops over ids of user defined trait (not system traits) } : iterate "_stats" { // Loops over ids of user defined stats (not system stats). } : iterate "_collections" { // Loops over ids of user defined collections. } : iterate "_graphics" { // Loops over ids of graphics. } : iterate "_themes" { // Loops over ids of themes. } : iterate "_strings" { // Loops over ids of string variables (dynamic and non dynamic). } : iterate "_integers" { // Loops over ids of integer variables (dynamic and non dynamic). } : iterate "_booleans" { // Loops over ids of boolean variables (dynamic and non dynamic). } : iterate "_sentence" { // Loops over raw parsed sentence elements. } : iterate "_treasures" { // Loops over all treasure objects } : iterate "_zones_in" { // Loops over zones the player is currently in. } : iterate "_s1_universal" { // Loops over all objects ids that match the first adjective and noun. } : iterate "_s1_known" { // Loops over all objects ids (for known objects) // that match the first adjective and noun. } : iterate "_s1_disambiguate" { // Loops over all objects ids (for disambiguated objects) // that match the first adjective and noun. } : iterate "_s1_known" filter -> (item_has_trait "t_wet") { // Loops over all objects ids (for known objects) // that match the first adjective and noun. // and that have the trait 't_wet'. } : iterate "_s1_known" filter -> ( is_carried (item()) ) { // Loops over all objects ids (for known objects) // that match the first adjective and noun. // and that are carried } : iterate "_s1_known" filter -> ( is_carried (item()) && item_has_trait "t_wet") { // Loops over all objects ids (for known objects) // that match the first adjective and noun. // and that are carried and have the 't_wet' trait set. } : iterate "_s2_universal" { // Loops over all objects ids that match the first adjective and noun. } : iterate "_s2_known" { // Loops over all objects ids (for known objects) // that match the second adjective and noun. } : iterate "_s2_disambiguate" { // Loops over all objects ids (for disambiguated objects) // that match the second adjective and noun. } : iterate "<<specific trait id>>" { // Loops over ids of all objects with this specific trait set. } : iterate "<<specific collection id>>" { // Loops over all elements of this particular collection. } : iterate "<<specific location or page id>>" { // Loops over all objects(directly) contained in the page or location. } : iterate "<<specific zone id>>" { // Loops over all locations specifically registered against the zone } : iterate "<<specific zone id>>" { // Loops over all locations specifically registered against the zone }
: iterate "collection id or one of the following categories" { : print ( "Iteration index " + index() + ", item " + item() + (is_first_iteration() ? " - FIRST" : "") + (is_final_iteration() ? " - LAST" : "") ); } : print ( "Number of items in previous iteration loop : " + count() );
System Iteration Id | Description |
---|---|
_locations |
All the locations (or pages) in the game. Except the ether." |
_pages |
All the pages (or locations) in the game. Except the ether." |
_entities |
All items in the objects {} section. Except the 'player' character." |
_traits |
All the traits in the game, excluding system traits." |
_stats |
All the stats in the game, excluding system stats" |
_inventory |
Everything held or worn by the player." |
_inventory_notworn |
Everything held but not worn by the player." |
_inventory_notworn_wearable |
Everything held but not worn by the player, that is also wearable." |
_inventory_worn |
Everything held and worn by the player." |
_inventory_deep |
Everything recursively held by the player." |
_ether |
Everything in the ether (things currently not existing)." |
_beside |
Everything in the current player location, excluding the player character." |
_beside_listed |
Everything in the current player location, that is listed." |
_beside_notlisted |
Everything in the current player location, that is not listed." |
_booleans |
All boolean variables in the game." |
_integers |
All integers in the game." |
_strings |
All strings in the game." |
_collections |
All collections in the game." |
_graphics |
All graphics in the game" |
3.12. Choices
3.13. Basic Choices
Adventuron lets authors add items to the CHOICE BUFFER. If you call : choose, when the choice buffer is full, then the player will be presented with the choices that have been added, and the selected choice will be available via the chosen() String function, as shown below.
In the example below, item() is the id of the current iteration item. The payload is the VALUE that will be placed into the chosen() string function (after calling : choose; ). If no payload were provided, then the textual value of the choice would be loaded into choice() instead.
start_at = my_location locations { my_location : location "You are in a room." ; } collections { list_1 : list { items = [ spoon, fork, knife, onion, garlic, spork ] } } on_startup { : iterate "list_1" { // Payload is optional here. : add_choice text -> (item()) payload -> (item() + "!!!!") ; } : choose "Select an option" ; : print ("You selected : " + chosen()) ; : press_any_key ; }
3.14. Advanced Choices
The add_choice command is very powerful and you can optionally place code to execute inside the command itself.
start_at = my_location locations { my_location : location "You are in a room." ; } collections { list_1 : list { items = [ spoon, fork, knife, onion, garlic, spork ] } } on_startup { : iterate "list_1" { // Payload is optional here. : add_choice text -> (item()) payload -> (item()) { // Be careful NOT to use item() inside an add_choice block, as these blocks are // executed during the choose() command, therefore the iterator is already finished // at this time. If you wish to access the item() within your handler, use the payload attribute // to set the payload for this particualr choice, and it can be accessed via choice_payload() : print ("Choice Index Selected : " + choice_index() + ", Choice Payload : " + choice_payload()); } } : choose "Select an option" ; : print ("You selected : " + chosen()) ; : press_any_key ; }
3.15. 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 }
If you want to have seperate wear limits and inventory limits, then provide the 'inventory_worn_items_limit_var'.
If you do not provide an override for the 'inventory_worn_items_limit_var' then default item carry limit (10) or the explicit item limit (inventory_worn_items_limit_var) will apply across carried and worn items.
Supplying 'inventory_worn_items_limit_var' will seperate the worn limit from the carry limit.
In the code below, the player is allowed to carry 3 items that are not worn, and is allowed to wear 2 items.
start_at = my_location locations { my_location : location "You are in a room." ; } objects { vest : object "a vest" at = "inventory" wearable = "true" initially_worn = "true" ; hat : object "a hat" at = "inventory" wearable = "true" initially_worn = "true" ; gloves : object "a pair of gloves" at = "inventory" wearable = "true" ; spanner : object "a spanner" at = "inventory" ; spoon : object "a spoon" at = "inventory" ; } game_settings { inventory_worn_items_limit_var = wear_limit inventory_items_limit_var = item_limit } integers { item_limit : integer "3" ; wear_limit : integer "2" ; }
3.16. 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.16.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.16.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.17. 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.17.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.17.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.17.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.17.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.18. 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 tall (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.18.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). |
: print_graphic "skull";
: print_graphic "skull" width="50";
: print_graphic "skull" width="50";
: print_graphic "skull" width="50" align="right";
3.18.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.19. 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.19.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.19.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.19.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.19.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.19.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.19.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.19.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.19.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.19.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.19.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.19.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.20. Default Vocabulary
3.20.1. Default Verbs
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). |
To disable standard verbs, use the following setting. Adventuron is still able to recognise verbs and nouns by their position in the users command by looking at the placement of words.
System verbs are useful because they allow multiple words to be associated with the same action.
game_settings { add_standard_verbs = false }
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, (go in) |
Tries to enter (if possible). |
exit _ |
leave, out, (go out) |
Tries to exit (if possible). |
exits _ |
Lists the current exits in the current room. |
3.20.2. Default Prepositions
(English-Centric documentation here)
Adventuron enabled a number of standard prepositions. These prepositions are a basic set which should be useful for most games however more prepositions can be added in the vocabulary {} section as needed.
System prepositions are automatically disabled in verb_noun mode (or when using the TALP template - which enabled verb noun mode).
To manually disable the default prepositions, use this setting:
game_settings { add_standard_prepositions = false }
Here is the list of standard prepositions added by Adventuron, sorted into groups.
Prepositions Groups | on, onto | in, into, inside | under, underneath | out |
---|---|---|---|---|
to |
from |
for |
at |
about |
3.21. 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.21.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.21.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.22. 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.23. 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.24. 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.
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. } }
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. |
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 listed 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. |
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.24.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:
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.24.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.24.3. Extending Themes
If you find yourself having multiple themes with 90% of the same settings, make use of the "extends=" attribute.
Using this will apply all settings from the extended theme, then apply your differences atop of that.
themes { base_theme : theme { // Hundreds of lines of stuff } special_theme: theme { extends = base_theme // Only describe differences to be applied } }
3.25. Hotkeys
The Adventuron editor has a number of shortcut keys, that when learned, can accelerate your development speed.
Warning
|
Chromebooks are missing many useful keys for programmers. Read more about this here. |
Action / Button | Description | Possible Issues |
---|---|---|
Click Top Bar of Editor |
(When Red) Go to line of error. |
N/A |
Cursor Keys |
Tap cursor (arrow) keys to move the blinking 'cursor' around the text area. |
N/A |
Hold Shift + Cursor Keys |
Hold Shift and tap cursor (arrow) keys to select a redion of text. |
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. |
Page Down |
Scrolls the text one page down at a time. |
Some keyboards do not have a dedicated page down button. |
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. |
End |
Moves the cursor to the end of the current line. |
Some keyboards do not have a dedicated End button. |
Control + Home |
Scrolls to the top of the document. |
Some keyboards do not have a dedicated Home button. |
Control + End |
Scrolls to the bottom of the document. |
Some keyboards do not have a dedicated End button. |
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.26. Debugging
3.26.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.26.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.26.3. Transcripts
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. |
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.
Starting taking a transcript
To enable recording a game transcript, ask your beta testers to type "TSTART":
> TSTART
Adding comments in a transcript
To add a comment to your game transcript (that is not a command submitted to the game, type a backtick character (`) then your text.
The command will not be submitted to the game, and a game 'tick' will not be consumed by the game (the game world will not execute any event handlers).
> `I think there should be an examine message for the trees here.
Stopping taking a transcript
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.
3.26.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.27. 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.28. Additional Features
3.28.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
-
Adventuron will add the de-pluralized version of trees to the dictionary automatically.
-
Match records automatically contribute verbs and nouns to the verb dictionary and the noun dictionary respectively.
-
'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.28.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.28.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.28.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.28.5. Dynamic Variables (Advanced Users Only)
Adventuron has a feature where dynamic strings, dynamic integers, and dynamic booleans.
Dynamic variables make it simple to keep track of complex state in the world by packaging up complex expressions so that they can be represented as if they are a simple variable.
Dynamic variables contain an inner complex expression betwen ( and ) characters.
The result of the expression should match the containing type
-
dynamic_boolean … requires a boolean result.
-
dynamic_integer … requires an integer result.
-
dynamic_string … requires a string result.
booleans { is_carrying_light_source : dynamic_boolean ( is_carried "lit_lamp" || is_carried "lit_torch" ); is_dark : dynamic_boolean ( (hour >= 17 || hour <= 6) && is_carrying_light_source == false ); } strings { darkness_messages : dynamic_string ( is_dark ? "It is dark. You see nothing at all" : "" ); } integers { cents_carried : integer "200"; dollars_carried : dynamic_integer ( cents_carried / 100 ); }
A good place to use a dynamic variable is in a barrier.
Not shown here, but it is possible to place complex blocking logic in a dynamic boolean using this pattern.
start_at = lakeside template = talp locations { lakeside : location "You are by the side of a lake."; forest : location "You are in a forest." ; 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, ] } objects { guard : scenery "a guard" at = "outside_castle" ; } booleans { is_guard_blocking : dynamic_boolean ( is_present "guard" ) ; } barriers { barrier_castle : block { location = castle message = The guard will not let you pass. block_when = is_guard_blocking } } on_command { : match "banish guard" { : print "The guard goes away !" ; : destroy "guard" ; } }
3.29. 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.
3.29.1. Starting To Search
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.
Press ENTER to cycle through every instance of the word 'river' in your text.
Subject Search
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.
"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.
Section Search
Note
|
Search for name of a section, then a space, then an open brace to find all instances of that section. |
e.g.
on_command {
objects {
themes {
Command search
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.
: destroy
: lose_game
Universal search
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.29.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.29.3. Search And Replace
(ADVANCED USERS ONLY) By clicking the + icon underneath the search textbox, you can access a replace text box.
3.30. 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.30.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.30.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.
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.
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.
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.30.3. Squashed Fonts
Some fonts may feel fairly squashed or cluttered vertically.
Example:
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.
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/AAAAAFwAAAGgJCwkGBgkJCQkJCQkICAkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQsJCQkJCQkJCQkICQkJCQkJCQkJCQkJCQoJCQkJCQkJCQkJCQkJCQkJCQkJCQAAAAoLCgcHCgoKCgoKCgoLCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCwoKCgoKCgoKCgkKCgoKCgoKCgoKCgoKCwoKCgoKCgoKCgoKCgoKCgoKCgoKAAAACwwLBwcLCwsLCwsLCwoLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCgsKCgsKCwsLCgsLCwsLCwsLCgsLCwsLCwsLCwsLCwoLCwoLCwsLCwsMCwsLCgsLCgsLCwsLCwsLCwoLCwsAAAAMDQwICAwMDAwMDAwLCwwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwNDA0NDA0MDAwNDAwMDAwMDA0NDAwMDAwMDAwNDAwMDQwMDQwMDAwMDAwMDAwNDAwNDAwMDAwMDAwMDQwMDAAAAA0PDQkJDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ4NDg4NDg0NDQ4NDQ0NDQ0NDw4NDQ0NDQ0NDQ0NDQ0ODQ0ODQ0NDQ0NDg0NDQ4NDQ4NDQ0NDQ0NDQ0ODQ0NAAAADxAPCgoPDw8PDw8PEA8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PEA8PDw8PDw8PDw8PDw8QDw8PDw8PDw8PDw8PDw8PDw8PDw8AAAAQERALCxAQEBAQEBAPDxAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBEQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBEQEBAQEBAQEBAQEBAQEBAQEBAQEAAAABETEQsLERERERERERAQERERERERERERERERERERERERERERERERERERERERERERERERERERERERExERERERERERERAREREREREREREREREREhERERERERERERERERERERERERERAAAAExQTDQ0TExMTExMTExITExMTExMTExMTExMTExMTExMTExMTExMTEhMSEhMSExMTEhMTExMTExMTEhMTExMTExMTExMTExITExITExMTExMUExMTEhMTEhMTExMTExMTExITExMAAAAVFxUODhUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUWFRYWFRYVFRUWFRUVFRUVFRcWFRUVFRUVFRUVFRUVFhUVFhUVFRUVFRYVFRUWFRUWFRUVFRUVFRUVFhUVFQAAABgZGBAQGBgYGBgYGBcXGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGRgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGRgYGBgYGBgYGBgYGBgYGBgYGBgYAAAAGxwbEhIbGxsbGxsbGxwbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGhsaGhsaGxsbGhsbGxsbGxsbGhsbGxsbGxsbGxsbGxobGxobGxsbGxscGxsbGhsbGhsbGxsbGxsbGxobGxsAAAAdHx0TEx0dHR0dHR0dHx0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0eHR4eHR4dHR0eHR0dHR0dHR8eHR0dHR0dHR0dHR0dHh0dHh0dHR0dHR4dHR0eHR0eHR0dHR0dHR0dHh0dHQAAACAhIBUVICAgICAgICAhICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgISAgICAgICAgICAgICAgICAgICAgICAgISAgICAgICAgICAgICAgICAgICAgAAAAISIhFhYhISEhISEhICIhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhICEhISEhISEhISEhISEiISEhISEhISEhISEhISEhISEhISEAAAAlJyUZGSUlJSUlJSUlJyUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUmJSYmJSYlJSUmJSUlJSUlJScmJSUlJSUlJSUlJSUlJiUlJiUlJSUlJSYlJSUmJSUmJSUlJSUlJSUlJiUlJQAAACorKhwcKioqKioqKisrKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKyoqKioqKioqKisqKioqKioqKioqKioqKyoqKioqKioqKioqKioqKioqKioqAAAALjAuHx8uLi4uLi4uLzAuLi4uLi4uLi4uLi8vLi4uLi4uLi4uLi4uLi4vLy8vLi4uLy4uLi4uLi8vLi4uLi4uLi4uMC4uLi4uLy4uLy4uLi4vLy4uLi4uLi8uLi4vLi4uLi8uLi4AAAAyMzIhITIyMjIyMjIzMzIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjMyMjIyMjIyMjIzMjIyMjIyMjIyMjIyMjMyMjIyMjIyMjIyMjIyMjIyMjIyMgAAADY4NiQkNjY2NjY2Njc4NjY2NjY2NjY2NjY3NzY2NjY2NjY2NjY2NjY2Nzc3NzY2Njc2NjY2NjY3NzY2NjY2NjY2Njg2NjY2Njc2Njc2NjY2Nzc2NjY2NjY3NjY2NzY2NjY3NjY2AAAAOjs6Jyc6Ojo6Ojo6Ozs6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo7Ojo6Ojo6Ojo6Ozo6Ojo6Ojo6Ojo6Ojo7Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoAAABDREMtLUNDQ0NDQ0NDRENDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NCQ0JCQ0JDQ0NCQ0NDQ0NDQ0NCQ0NDQ0NDQ0NDQ0NDQkNDQkNDQ0NDQ0RDQ0NCQ0NCQ0NDQ0NDQ0NDQkNDQwAAAEtMSzIyS0tLS0tLS0tMS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0pLSkpLSktLS0pLS0tLS0tLS0pLS0tLS0tLS0tLS0tKS0tKS0tLS0tLTEtLS0pLS0pLS0tLS0tLS0tKS0tLAAAAAAAAAwAAAAMAAAIQAAEAAAAAABwAAwABAAABvAAGAaAAAAAAAMsAAQAAAAAAAAAAAAAAAAAAAAEAAgAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAMAYgAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4APwBAAEEAAABCAEMARABFAEYARwBIAEkASgBLAEwATQBOAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAF4AXwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAABhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAQAVAAAABAAEAADAAAAAAANACEAXwB+AKMAqf//AAAAAAANACAAIgBhAKMAqf//AAH/9QAA/+L/4f+9/7gAAQAAAAAADAAAAAAAAAAAAAAAAwBiAAQAVAAAABAAEAADAAAAAAANACEAXwB+AKMAqf//AAAAAAANACAAIgBhAKMAqf//AAH/9QAA/+L/4f+9/7gAAQAAAAAADAAAAAAAAAAAAAAAAwBiuAAALEu4AAlQWLEBAY5ZuAH/hbgARB25AAkAA19eLbgAASwgIEVpRLABYC24AAIsuAABKiEtuAADLCBGsAMlRlJYI1kgiiCKSWSKIEYgaGFksAQlRiBoYWRSWCNlilkvILAAU1hpILAAVFghsEBZG2kgsABUWCGwQGVZWTotuAAELCBGsAQlRlJYI4pZIEYgamFksAQlRiBqYWRSWCOKWS/9LbgABSxLILADJlBYUViwgEQbsEBEWRshISBFsMBQWLDARBshWVktuAAGLCAgRWlEsAFgICBFfWkYRLABYC24AAcsuAAGKi24AAgsSyCwAyZTWLBAG7AAWYqKILADJlNYIyGwgIqKG4ojWSCwAyZTWCMhuADAioobiiNZILADJlNYIyG4AQCKihuKI1kgsAMmU1gjIbgBQIqKG4ojWSC4AAMmU1iwAyVFuAGAUFgjIbgBgCMhG7ADJUUjISMhWRshWUQtuAAJLEtTWEVEGyEhWS0AuAAAKwG6AAEAAQACKwG/AAEALAAkABwAFAAMAAAACCsAugACAAQAByu4AAAgRX1pGEQAAAAQAGQAAAAA/5wAAAH0AAACvAAAAAIAAAEsArwCWAAKABUAv7sABgABAAcABCu7ABEAAQASAAQruAAGELgAANC4AAYQuQABAAH0uAAGELkAAwAB9LgABhC4AAnQuAARELgAC9C4ABEQuQAMAAH0uAARELkADgAB9LgAERC4ABTQALoABQAGAAMrugABAAIAAyu4AAUQuAAA3LgABRC4AAjQuAABELgACtC4AAEQuAAL0LgAABC4AAzQuAACELgADdC4AAUQuAAP0LgABhC4ABHQuAAFELgAE9C4AAAQuAAV0DAxEzMVIxUjFSM1MzUhMxUjFSMVIzUzNWTIZGRkZAGQyGRkZGQCWGRkZGTIZGRkZMgAAAACAAAAAAK8AfQAHAAhAU27ABIAAQATAAQruAASELkAEAAB9LgAANC4ABAQuQABAAH0uQAEAAH0uQAGAAH0uAAEELgACdC4AAMQuAAK0LgABhC4AAvQuAABELgADdC4AAAQuAAP0LgAEhC4ABfQuAARELgAGNC4ABMQuAAZ0LgAEBC4ABvQuAABELgAHdC4ABAQuAAe0LgAABC4AB/QuAABELgAINAAuAAARVi4AAAvG7kAAAAGPlm4AABFWLgABC8buQAEAAY+WbgAAEVYuAAOLxu5AA4AAj5ZuAAARVi4ABIvG7kAEgACPlm6AAsADAADK7gABBC4AAjcuAAH3LgAAtC4AA4QuAAK3LgADBC4ABDQuAAMELgAFNC4AAoQuAAW0LgAF9C4AAgQuAAY0LgAGdC4AAcQuAAa0LgAGRC4AB3QuAAe0LgAFxC4AB/QuAAg0LgAHhC4ACHQMDEBMxUzNTMVMxUjFTMVIxUjNSMVIzUjNTM1IzUzNRcjFTM1ASxkZGRkyGTIZGRkZMhkyGRkZAH0ZGRkZGRkZGRkZGRkZGTIZGQAAAAAAQBk/zgCvAJYACIBlLsAFgABABMABCu4ABYQuQAJAAH0uAAA0LgACRC5AAEAAfS5AAMAAfS4AAEQuAAF0LgAAhC4AAbQuAAWELgAB9C4ABAQuAAI0LgAABC4AArQuAADELgAC9C4AAEQuAAN0LgAAhC4AA7QuAAWELgAD9C4ABYQuQARAAH0uAABELgAF9C4AAIQuAAY0LgACRC4ABnQuAAAELgAGtC4ABYQuAAb0LgAEBC4ABzQuAARELgAHdC4ABYQuAAf0LgAEBC4ACDQuAAJELgAIdAAuAAQL7gAAEVYuAAgLxu5ACAABj5ZuAAARVi4AA4vG7kADgAEPlm4AABFWLgADS8buQANAAI+WboAAwAEAAMrugAbABUAAyu4ACAQuAAC3LgAAdy4AAIQuAAG0LgAB9C4AAQQuAAI0LgAGxC4AArQuAAJ3LgADhC4AAzcuAAS0LgAE9C4AA0QuAAU3LgAExC4ABbQuAAX0LgAFBC4ABjQuAAZ0LgABBC4ABzQuAAJELgAHdC4AAcQuAAe0LgAH9C4AAEQuAAi0DAxATMVMxUjNSEVMxUzFSMVIRUjNSM1MxUhNSM1IzUjNTM1MzUB9GRkZP7UyMhk/tRkZMgBLGTIZGTIAljIZGRkZMhkZMhkZGRkZGRkZAAAAAUAAP+cArwB9AAgACUAKgAvADQCcLsAIgABAB4ABCu4ACIQuAAA0LgAAC+4ACIQuQABAAH0uAAT0LgAAtC4AAEQuQALAAH0uQADAAH0uAABELkAGwAB9LkAEgAB9LgABNC4AAsQuQAIAAH0uQAFAAH0uAAK0LgACBC4AA3QuAAFELgAD9C4AAMQuAAR0LgAAhC4ABTQuAAiELgAFdC4ABUvuAAAELgAFtC4AB4QuAAX0LgAIhC4ABnQuAAZL7gAABC4ABrQuAAAELgAH9C4ABsQuAAh0LgAGxC4ACTQuAABELgAJtC4ABsQuAAn0LgAARC4ACnQuAATELgAKtC4AAsQuAAr0LgAAxC4ACzQuAASELgALdC4AAsQuAAu0LgABRC4ADDQuAALELgAMdC4AAUQuAAz0AC4AABFWLgAAC8buQAAAAY+WbgAAEVYuAAGLxu5AAYABj5ZuAAARVi4ABAvG7kAEAAEPlm4AABFWLgAFi8buQAWAAQ+WbgAAEVYuAAPLxu5AA8AAj5ZuAAS3LgALNy4AAzQuAAL3LgAAtC4AAYQuAAE3LgAA9y4AAQQuAAI0LgACdC4AAMQuAAK0LgAEBC4AA7cuAAU0LgAFdC4ABjQuAAZ0LgAEhC4ABrQuAAb0LgALBC4ABzQuAAMELgAHdC4AAkQuAAe0LgAH9C4ACHQuAAi0LgAAxC4ACPQuAALELgAJNC4ACIQuAAl0LgAAxC4ACbQuAALELgAJ9C4ACwQuAAo0LgADBC4ACnQuAALELgAKtC4AAwQuAAr0LgAGxC4AC3QuAAu0LgALBC4AC/QuAAuELgAMNC4ADHQuAAZELgAMtC4ADPQuAAxELgANNAwMRMzFTM1MzUzFSMVIxUzFSMVIzUjFSMVIzUzNTM1IzUzNRcjFzM1FyMVMzUXIxUzNRcjFTM1ZMhkyGRkZMhkyGTIZGRkyGRkZQFkZGRkyGRkZGRkAfTIZGRkZGTIZMhkZGRkZMhkZGRkZGRkZGRkZGRkAAABAAD/nAK8AlgAJgG/uwAeAAEAHwAEK7sACAABACMABCu7AAQAAQAJAAQruAAIELgAANC4AAgQuQABAAH0uQADAAH0uAABELgABdC4AAIQuAAG0LgAHhC4AAvQuAAjELgADdC4AB8QuQAOAAH0uAAJELgAD9C4AAEQuAAR0LgAAhC4ABLQuAABELkAEwAB9LgABBC4ABXQuAADELgAFtC4ABMQuAAX0LgAARC4ABnQuAACELgAGtC4AAkQuAAb0LgAHhC4ACHQuAAIELgAJdAAuAAARVi4AAIvG7kAAgAGPlm4AABFWLgABi8buQAGAAY+WbgAAEVYuAAkLxu5ACQABj5ZuAAARVi4ABgvG7kAGAAEPlm4AABFWLgAHC8buQAcAAQ+WbgAAEVYuAAPLxu5AA8AAj5ZuAACELgAAdy4AAIQuAAE3LgAAhC4AAfQuAAPELgACty4AAncuAAPELgADNy4ABwQuAAO3LgADBC4ABDQuAAR0LgACRC4ABLQuAAKELgAFNC4ABXQuAAOELgAFtC4ABfQuAAa0LgAG9C4AB7QuAAf0LgAFRC4ACDQuAAh0LgACRC4ACLQuAACELgAJdC4AAEQuAAm0DAxATMVMxUjNSMVMxUhFTMVMzUzNTMVIxUzFSM1IxUhNSM1MzUzNTM1ASzIZGTIZP7UZMhkyGRkyGT+1GRkZGQCWGRkZMhkZGRkyGTIZGRkZMhkyGQAAQDIASwB9AJYAAoAWbsABgABAAcABCu4AAYQuAAA0LgABhC5AAEAAfS4AAYQuQADAAH0uAAGELgACdAAugAFAAYAAyu6AAEAAgADK7gABRC4AADcuAAFELgACNC4AAEQuAAK0DAxATMVIxUjFSM1MzUBLMhkZGRkAlhkZGRkyAABAMj/nAK8AlgAFADuuAAVL7gAD9C4AA8vuAANELgADdy4AA8QuAAN3EEDAJAADQABXUEDABAADQABXUEDAFAADQABXUEDAPAADQABXUEDADAADQABXUEDAHAADQABXUEDALAADQABXUEDANAADQABXbkACAAB9LgABNC4AA8QuQAGAAH0uAANELkADAAB9LgADRC4ABHQuAAGELgAE9C4AAgQuAAW3AC4AABFWLgACi8buQAKAAQ+WboAAQACAAMrugARAA4AAyu4AAEQuAAF3LgAChC4AAbcuAAKELgACNy4AAzQuAAN0LgAAhC4ABLQuAABELgAFNAwMQEhFSMVIxEzFTMVITUjNSM1MzUzNQGQASzIZGTI/tRkZGRkAlhkZP7UZGRkyGTIZAABAMj/nAK8AlgAFAEouAAVL7gADdC4AA0vuAAC3EEDAAAAAgABXUEPACAAAgAwAAIAQAACAFAAAgBgAAIAcAACAIAAAgAHXUENAKAAAgCwAAIAwAACANAAAgDgAAIA8AACAAZduQADAAH0uAACELgAENxBAwAAABAAAV1BDwAgABAAMAAQAEAAEABQABAAYAAQAHAAEACAABAAB11BDQCgABAAsAAQAMAAEADQABAA4AAQAPAAEAAGXbkABQAB9LgADRC5AAgAAfS4AAIQuAAJ0LgADRC4ABHQuAAFELgAFtwAuAAARVi4AAovG7kACgAEPlm6AAEAAgADK7oABQAGAAMruAAKELgACNy4AAzQuAAN0LgAChC4AA7cuAABELgAENy4AAIQuAAS0LgAARC4ABTQMDETIRUzFTMVIxUjFSE1MzUzESM1IzXIASxkZGRk/tTIZGTIAlhkyGTIZGRkASxkZAAAAAABAGQAAAJYAfQAEAB5uAARL7gAAC+5AAEAAfS4AAXQuAARELgACdC4AAkvuQAIAAH0uAAJELgADdC4AAAQuAAP0AC4AABFWLgAAC8buQAAAAY+WbgAAEVYuAAILxu5AAgAAj5ZugANAAoAAyu6AAMABAADK7gAChC4AAbQuAADELgADtAwMQEzFTMVIxUjFSM1IzUzNTM1AZBkZGTIZGRkyAH0ZGTIZGRkyGQAAQBkAAACvAH0AAwAYbsABgABAAcABCu4AAYQuAAA0LgABhC5AAEAAfS4AAYQuAAL0AC4AABFWLgAAC8buQAAAAY+WbgAAEVYuAAGLxu5AAYAAj5ZugADAAQAAyu4AAQQuAAI0LgAAxC4AArQMDEBMxUzFSEVIzUjNSE1AZBkyP7UZMgBLAH0yGTIyGTIAAAAAQDI/zgB9ABkAAoAjLsABgABAAcABCu4AAYQuAAA0LgABhC5AAEAAfS4AAYQuQADAAH0uAAGELgACdAAuAAARVi4AAQvG7kABAAEPlm4AABFWLgACC8buQAIAAQ+WbgAAEVYuAACLxu5AAIAAj5ZugAFAAYAAyu4AAQQuAAA3LgAAhC4AAHcuAAFELgACdC4AAEQuAAK0DAxJTMVIxUjFSM1MzUBLMhkZGRkZGRkZGTIAAAAAQBkAMgCvAEsAAQAEwC6AAEAAgADK7gAARC4AATQMDETIRUhNWQCWP2oASxkZAAAAQEs/5wB9AAAAAQAKrsAAQABAAAABCu4AAAQuAAD0AC4AABFWLgAAi8buQACAAQ+WbgAANwwMSEzFSM1ASzIyGRkAAABAGT/OAJYAlgAFAEJuwAKAAEACwAEK7gAChC5AAgAAfS5AAYAAfS5AAQAAfS4AADQuAAEELkAAQAB9LgAABC4AAPQuAAKELgADdC4AAkQuAAO0LgACBC4AA/QuAAHELgAENC4AAYQuAAR0LgABRC4ABLQuAAEELgAE9AAuAAARVi4AAIvG7kAAgAGPlm4AABFWLgAEi8buQASAAY+WbgAAEVYuAAILxu5AAgABD5ZuAAARVi4AAwvG7kADAAEPlm6AAkACgADK7gAAhC4AAHcuAACELgABNy4AAXQuAAIELgABty4AAkQuAAN0LgABhC4AA7QuAAP0LgABRC4ABDQuAAR0LgAAhC4ABPQuAABELgAFNAwMQEzFSMVIxUjFSMVIzUzNTM1MzUzNQH0ZGRkZGRkZGRkZAJYZMjIyGRkyMjIZAACAGT/nAK8AlgAEAAdAXS7ABQAAQAMAAQruwAGAAEABwAEK7gAFBC5ABcAAfS4AADQuAAGELgAAdC4AAYQuAAa0LgAGi+4AALQuAACL7gABhC5AAQAAfS4ABQQuAAJ0LgACS+4AAoQuAAN0LgAFBC4AA7QuAAOL7gAFxC4AA/QuAAHELgAEdC4ABcQuAAS0LgAEi+4AAcQuAAY0LgAGC+4AAcQuAAc0AC4AABFWLgAAi8buQACAAY+WbgAAEVYuAAOLxu5AA4ABj5ZuAAARVi4ABEvG7kAEQAGPlm4AABFWLgACC8buQAIAAQ+WbgAAEVYuAAHLxu5AAcAAj5ZuAACELgAAdy4AAcQuAAE3LgACBC4AAbcuAAK0LgAC9C4AA4QuAAM3LgAAhC4AA/QuAABELgAENC4AAIQuAAS0LgADBC4ABPQuAAU0LgABBC4ABXQuAAW0LgACxC4ABfQuAAY0LgAFhC4ABnQuAAa0LgAFBC4ABvQuAAc0LgAAhC4AB3QMDEBIRUzESMVIxUhNSMRMzUzNRcjFyMTMxUzNzMTIzUBLAEsZGRk/tRkZGTIyQFlAWTHAWMBZAJYZP5wZGRkAZBkZGRk/tRkZAEsZAAAAAEBLP+cAfQCWAAIAFG7AAEAAQAGAAQruAABELkAAAAB9LgAA9C4AAAQuAAH0AC4AAAvuAAARVi4AAYvG7kABgAGPlm4AABFWLgAAi8buQACAAQ+WbgABhC4AATcMDEBMxEjESM1MzUBkGRkZGQCWP1EAfRkZAAAAAEAZP+cAlgCWAAeAYG7AA8AAQAOAAQruAAPELgAANC4AA8QuQASAAH0uQAIAAH0uQAGAAH0uAAB0LgABhC5AAMAAfS4AAIQuAAF0LgAEhC4AAnQuAADELgAC9C4AAkQuAAR0LgACBC4ABPQuAAHELgAFNC4AAYQuAAV0LgAAhC4ABbQuAAIELgAF9C4AAcQuAAY0LgADxC4ABnQuAAQELgAGtC4AA4QuAAb0LgADxC4AB3QuAAQELgAHtAAuAAARVi4AAIvG7kAAgAGPlm4AABFWLgAGC8buQAYAAY+WbgAAEVYuAAcLxu5ABwABj5ZuAAARVi4AAwvG7kADAAEPlm6AAUABgADK7gAAhC4AAHcuAACELgABNy4AAwQuAAI3LgAB9y4AAwQuAAK3LgADtC4AA/QuAAIELgAENC4ABHQuAAHELgAEtC4AAYQuAAT0LgABBC4ABTQuAAV0LgAAhC4ABbcuAAX0LgAAhC4ABnQuAAXELgAGtC4ABvQuAACELgAHdC4AAEQuAAe0DAxEyEVMxUjFSMVIxUhFSE1MzUzNTM1MzUjNSMVIzUzNcgBLGRkZGQBLP4MZGRkZGTIZGQCWGTIZGRkZGRkZGRkZGRkZAAAAAEAZP+cArwCWAAeAVm7ABEAAQAQAAQruwAGAAEAGQAEK7gAEBC4AADQuAAGELkABAAB9LkAAgAB9LgABBC4AAfQuAADELgACNC4AAIQuAAJ0LgABBC4AAvQuAADELgADNC4ABEQuAAN0LgABhC4ABPQuAAFELgAFNC4AAQQuAAV0LgAAxC4ABbQuAAGELgAF9C4AAUQuAAY0LgABhC4ABvQuAAFELgAHNC4ABAQuAAd0AC4AABFWLgADC8buQAMAAQ+WbgAAEVYuAALLxu5AAsAAj5ZugABAAIAAyu6AAUABgADK7gAARC4AATcuAALELgACNy4AAfcuAAMELgACty4AA7QuAAP0LgACxC4ABDcuAAPELgAEtC4ABPQuAAQELgAFNC4ABXQuAAIELgAFtC4ABfQuAAGELgAGNC4AAcQuAAZ0LgABBC4ABrQuAAFELgAG9C4AAIQuAAc0LgAARC4AB7QMDETIRUjFSMVMxUzFSMVITUjNTMVITUzNSM1IzUzNSE1ZAJYZGRkZGT+cGRkASxkZMjI/nACWGRkZGTIZGRkZGRkZGRkZAAAAQBk/5wCvAJYABYA97sABgABABEABCu7AAoAAQAHAAQruAAGELkABAAB9LgAANC4AAQQuQABAAH0uAAAELgAA9C4AAoQuAAN0LgABxC4AA/QuAAGELgAE9C4AAUQuAAU0LgABBC4ABXQALgAAEVYuAACLxu5AAIABj5ZuAAARVi4AAgvG7kACAAGPlm4AABFWLgAFC8buQAUAAY+WbgAAEVYuAAOLxu5AA4ABD5ZuAACELgAAdy4AAIQuAAE3LgABdC4AAQQuAAQ3LgADNC4AAvcuAAG0LgAAhC4AAnQuAAMELgAEdC4AAUQuAAS0LgAE9C4AAIQuAAV0LgAARC4ABbQMDEBMxUjFSMVIREzETMVIxUjNSE1MzUzNQEsZGRkASxkZGRk/nBkZAJYZMhkASz+1GTIyMjIZAAAAAIAZP+cArwCWAAcACEBabsAHgABABoABCu7AAgAAQARAAQruAAeELgAANC4AAAvuAAIELgAAdC4AB4QuQADAAH0uAAIELkABQAB9LgACdC4AB4QuAAL0LgACy+4AAAQuAAM0LgAGhC4AA3QuAAeELgAD9C4AA8vuAAAELgAENC4AAUQuAAT0LgAERC4ABXQuAADELgAF9C4AAAQuAAb0LgAAxC4AB3QuAAdL7gAAxC4ACDQuAAgL7gACBC4ACPcALgAAEVYuAAKLxu5AAoABD5ZuAAARVi4AAkvG7kACQACPlm6AAEAAgADK7oABQAGAAMruAABELgAG9y4AATQuAAKELgACNy4AAzQuAAN0LgACRC4AA7cuAANELgAENC4ABHQuAAOELgAEtC4ABPQuAAGELgAFNy4AAYQuAAW0LgAFBC4ABjQuAAFELgAGtC4AAEQuAAc0LgAGxC4AB3QuAAFELgAHtC4AAYQuAAf0LgABRC4ACHQMDETIRUhFSEVMxEjFSE1IzUzFSE1MzUjNSMVIzUzNRcjFzM1yAH0/nABLGRk/nBkZAEsZGTIyGRjZAFjAlhkZGT+1GRkZGRkZGRkyMjIZGQAAAIAZP+cArwCWAAaACMByLsAFAABABUABCu7ABAAAQAgAAQruAAUELkAHAAB9LgAANC4AAAvuAAQELkAGwAB9LgAAdC4AAEvuAAQELgAA9C4AA8QuAAE0LgAGxC4AAXQuAAFL7gAHBC4AAfQuAAHL7gAFBC4AAnQuAAcELgADNC4AAwvuAAbELgADdC4AA0vuAAbELgAEdC4ABEvuAAUELgAF9C4AAoQuAAY0LgAHBC4ABnQuAAZL7gAFBC4AB7QuAAKELgAH9C4AB8vuAAbELgAItC4ACIvuAAQELgAJdwAuAAARVi4AAMvG7kAAwAGPlm4AABFWLgABy8buQAHAAY+WbgAAEVYuAAZLxu5ABkABj5ZuAAARVi4ABIvG7kAEgAEPlm4AABFWLgAES8buQARAAI+WboAAQACAAMruAADELgABNy4AAIQuAAG0LgABBC4AAjQuAAJ0LgAERC4AArcuAASELgAHdy4AAvcuAAM3LgAChC4AA7QuAAP0LgAEhC4ABDcuAAU0LgAFdC4AAkQuAAW0LgAF9C4AAIQuAAY0LgAARC4ABrQuAAPELgAG9C4ABzQuAAVELgAH9C4ACDQuAAdELgAIdC4ACLQuAAcELgAI9AwMQEhFTMVIzUhFSMVMzUhFTMVIxUhNSMRMzUzNQEhFyMHITUzJwEsASxkZP7UZGQBLGRk/nBkZGQBK/7UAWQBAS1kAQJYZGRkZMhkZMhkZAGQZGT+cGRkZGQAAQBk/5wCvAJYABQAvrsAEQABAAAABCu4ABEQuQAIAAH0uQAGAAH0uQAEAAH0uAARELgACdC4AAgQuQALAAH0uAAIELgADdC4AAcQuAAO0LgABhC4AA/QuAAFELgAENC4AAAQuAAT0AC4AABFWLgACC8buQAIAAQ+WboAAQACAAMrugAFAAYAAyu4AAEQuAAE3LgACBC4AArcuAAEELgADtC4AAUQuAAP0LgAAhC4ABDQuAAEELgAEtC4AAUQuAAT0LgAARC4ABTQMDETIRUjFSMVIxEjNTM1MzUzNSEVIzVkAlhkZGTIZGRk/tRkAlhkZMj+1MjIZGRkyAAAAwBk/5wCvAJYABQAHQAmAe27AAwAAQANAAQruwAFAAEAGwAEK7gADBC4AADQuAAFELgAAdC4AAUQuQADAAH0uAAH0LgABRC4AAnQuAACELgACtC4AAwQuAAP0LgADBC4ABPQuAAQ0LgADRC4ABHQuAAFELgAFdC4ABUvuAAMELkAFgAB9LgADBC4ABjQuAATELgAGdC4ABkvuAACELgAHNC4ABwvuAAFELgAHtC4ABYQuAAf0LgADBC4ACHQuAATELgAItC4ABsQuAAj0LgABRC4ACXQuAACELgAJtAAuAAARVi4AAMvG7kAAwAGPlm4AABFWLgAEy8buQATAAY+WbgAAEVYuAAWLxu5ABYABj5ZuAAARVi4AB0vG7kAHQAGPlm4AABFWLgACi8buQAKAAQ+WbgAAEVYuAAJLxu5AAkAAj5ZugABAAIAAyu4AAMQuAAE3LgABdC4AAkQuAAG3LgAChC4AAjcuAAM0LgADdC4AAkQuAAO3LgAExC4ABDcuAAOELgAEdy4AAIQuAAS0LgAARC4ABTQuAACELgAFdC4AAUQuAAX0LgAGNC4ABAQuAAZ0LgAGtC4ABgQuAAb0LgAHNC4AAYQuAAe0LgAH9C4AA4QuAAg0LgAIdC4AA0QuAAi0LgAI9C4ACEQuAAk0LgAJdC4AB8QuAAm0DAxEyEVMxUjFTMVIxUhNSM1MzUjNTM1BSEVIwchNTM1EyEVIxUhNTM1yAGQZGRkZP5wZGRkZAGP/tVkAQEtYwH+1GQBLGQCWGRkyMhkZGTIyGRkZGRkZP7UZGRkZAAAAAEAZP+cArwCWAAiAbK7ABQAAQAdAAQruwAYAAEAFQAEK7gAFBC5ABIAAfS4AADQuAAYELkABgAB9LgAAdC4AAYQuQADAAH0uAACELgABdC4ABgQuAAH0LgAFBC4AAnQuAATELgACtC4ABgQuAAL0LgABxC4AAzQuAAGELgADdC4AAIQuAAO0LgAGBC4AA/QuAAHELgAENC4ABUQuAAa0LgAFBC4ABvQuAATELgAHNC4ABQQuAAf0LgAExC4ACDQuAASELgAIdAAuAAARVi4AAIvG7kAAgAGPlm4AABFWLgAEC8buQAQAAY+WbgAAEVYuAAgLxu5ACAABj5ZuAAARVi4AAgvG7kACAAEPlm4AABFWLgABy8buQAHAAI+WboAFgAVAAMruAACELgAAdy4AAcQuAAE3LgADNC4AAXQuAAIELgABty4AArQuAAL0LgADBC4AA3QuAACELgADty4AA/QuAACELgAEdC4AA8QuAAS0LgAE9C4AAwQuAAY3LgAFNC4ABnQuAANELgAGtC4ABvQuAAYELgAHNC4ABQQuAAd0LgAExC4AB7QuAAf0LgAAhC4ACHQuAABELgAItAwMQEhFTMRIxUjFSE1ITUzESM1IxUjFTM1MxUjFSM1IzUzNTM1ASwBLGRkZP7UASxkZMhkyGRkyGRkZAJYZP5wZGRkZAEsZGTIZGRkZMhkZAAAAAIBLAAAAfQBkAAEAAkAVrsAAQABAAAABCu4AAAQuAAD0LgAABC4AAXQuAABELgABtC4AAAQuAAI0AC4AABFWLgABy8buQAHAAI+WboAAQACAAMruAABELgABNC4AAcQuAAF3DAxATMVIzURMxUjNQEsyMjIyAGQZGT+1GRkAAAAAgDI/zgB9AGQAAQADwDAuwALAAEADAAEK7gACxC4AADQuAALELkAAQAB9LgACxC4AAPQuAALELgABdC4AATQuAABELgABtC4AAsQuQAIAAH0uAALELgADtC4AAAQuAAP0AC4AABFWLgACS8buQAJAAQ+WbgAAEVYuAANLxu5AA0ABD5ZuAAARVi4AAcvG7kABwACPlm6AAoACwADK7oAAQACAAMruAABELgABNC4AAkQuAAF3LgABxC4AAbcuAAKELgADtC4AAYQuAAP0DAxATMVIzURMxUjFSMVIzUzNQEsyMjIZGRkZAGQZGT+1GRkZGTIAAEAZP+cAfQBkAAUAP+7AAYAAQAPAAQruAAGELkABAAB9LgAANC4AAQQuQABAAH0uAAAELgAA9C4AAQQuAAH0LgAABC4AAjQuAABELgACdC4AAQQuAAL0LgAABC4AAzQuAAGELgADdC4AAUQuAAO0LgABhC4ABHQuAAFELgAEtC4AAQQuAAT0AC4AABFWLgACi8buQAKAAQ+WbgAAEVYuAAJLxu5AAkAAj5ZugABAAIAAyu4AAIQuAAE3LgACRC4AAbcuAAF3LgAChC4AAjcuAAM0LgADdC4AAYQuAAO0LgAD9C4AAQQuAAQ0LgABRC4ABHQuAACELgAEtC4AAMQuAAT0LgAARC4ABTQMDEBMxUjFSMVMxUzFSM1IzUjNTM1MzUBkGRkZGRkZGTIyGQBkGRkZGRkZGRkZGQAAAACAGQAZAK8AZAABAAJACMAugAGAAcAAyu6AAEAAgADK7gAARC4AATQuAAGELgACdAwMRMhFSE1FSEVITVkAlj9qAJY/agBkGRkyGRkAAAAAAEAyP+cAlgBkAAUAP+7AAEAAQAAAAQruAABELkAAwAB9LkABQAB9LgAAxC4AAfQuAAEELgACNC4AAEQuAAJ0LgAAhC4AArQuAAAELgAC9C4AAEQuAAN0LgAAhC4AA7QuAADELgAD9C4AAQQuAAQ0LgAARC4ABHQuAACELgAEtC4AAAQuAAT0AC4AABFWLgACi8buQAKAAQ+WbgAAEVYuAAJLxu5AAkAAj5ZugABAAIAAyu4AAIQuAAE3LgACRC4AAbcuAAF3LgAChC4AAjcuAAM0LgADdC4AAYQuAAO0LgAD9C4AAQQuAAQ0LgABRC4ABHQuAACELgAEtC4AAMQuAAT0LgAARC4ABTQMDETMxUzFTMVIxUjFSM1MzUzNSM1IzXIZGTIyGRkZGRkZAGQZGRkZGRkZGRkZAAAAAACAGT/nAK8AlgAGAAdAVa7ABQAAQAVAAQruwAGAAEABwAEK7gAFBC4AADQuAAGELgAAdC4AAYQuQADAAH0uAAUELkAEQAB9LkACAAB9LgAERC4AAnQuAARELgAGdC4AArQuAAHELgAC9C4AAgQuAAM0LgABhC4AA3QuAACELgADtC4AAcQuAAP0LgACBC4ABDQuAAZELgAEtC4ABQQuAAX0LgAERC5ABoAAfS4ABEQuAAc0LgACRC4AB3QALgAAEVYuAACLxu5AAIABj5ZuAAARVi4ABAvG7kAEAAGPlm4AABFWLgAGy8buQAbAAQ+WboABwAIAAMruAACELgAAdy4AAIQuAAE3LgAARC4AA7cuAAF3LgABxC4AArQuAAGELgAC9C4AAQQuAAM0LgADdC4AAIQuAAR0LgADhC4ABLQuAANELgAFNC4ABXQuAAOELgAFtC4AAEQuAAY0LgAGxC4ABncMDETIRUzFSMVIxUjNTM1MzUjNSMVIxUjNTM1EzMVIzXIAZBkZGTIyGRkyGRkZGRkZAJYZMhkZGRkZGRkZGTI/ahkZAAAAwBk/5wCvAJYABIAIwAqAia7ABYAAQAOAAQruAAWELkAGQAB9LgAANC4ABkQuQAhAAH0uQAGAAH0uAAB0LgAIRC5ACYAAfS5AAMAAfS5AAIAAfS4AAXQuAADELgAB9C4AAIQuAAJ0LgABhC4AArQuAAWELgAC9C4AAsvuAAMELgAD9C4ABYQuAAQ0LgAEC+4ABkQuAAR0LgAFRC4ABLQuAAmELgAE9C4ABkQuAAU0LgAFC+4ABUQuAAY0LgAAhC4ABrQuAAaL7gAIRC4ABzQuAAg0LgAHdC4ABkQuAAe0LgAFRC4AB/QuAAmELgAItC4AAIQuAAk0LgAExC4ACXQuAAhELgAJ9C4ACAQuAAo0LgAAhC4ACnQuAAGELgAKtAAuAAARVi4AAIvG7kAAgAGPlm4AABFWLgAEC8buQAQAAY+WbgAAEVYuAATLxu5ABMABj5ZuAAARVi4AAovG7kACgAEPlm4AABFWLgACS8buQAJAAI+WbgAAhC4AAHcuAAJELgABty4AAXcuAAKELgACNy4AAzQuAAN0LgAEBC4AA7cuAAV0LgAD9C4AAIQuAAR0LgAARC4ABLQuAACELgAFNC4ABUQuAAW0LgABhC4ABfQuAAY0LgADRC4ABnQuAAa0LgAGBC4ABvQuAAc0LgABRC4AB3QuAAVELgAH9y4ACbQuAAg0LgAFhC4ACHQuAAi0LgAAhC4ACPQuAAiELgAJNC4ACXQuAAFELgAKNC4ACUQuAAq0DAxASEVMxEjFTMVIxUhNSMRMzUzNRcjFyMTMxUhNSM1IzUzNTM1FyMVIxUzNQEsASxkZGRk/nBkZGTIyQFlAWQBK8dkZGRkZGTIAlhk/tRkZGRkAZBkZGRk/tRkZGRkZGRkZGTIAAACAGT/nAMgAlgAFgAbARO7AAwAAQANAAQruAAMELgAANC4AAwQuQAYAAH0uQACAAH0uAAX0LgAFy+4AAHQuAABL7gAAhC5AAMAAfS4AAnQuAAE0LgAAxC5AAUAAfS4AAMQuQAHAAH0uAAEELgACtC4AAwQuQAPAAH0uAAMELgAEdC4AAsQuAAS0LgAGBC4ABTQuAAUL7gADBC4ABXQuAALELgAFtC4ABMQuAAZ0LgAAhC4ABrQALgAAEVYuAAILxu5AAgABD5ZuAAARVi4AAwvG7kADAAEPlm6AAAAFQADK7oABAAKAAMruAAAELgAAty4AAgQuAAG3LgADtC4AA/QuAAEELgAENC4AAIQuAAS0LgAAhC4ABfQuAAEELgAGdAwMQEzFTMVMxUzFSM1IRUjNTM1MzUzNSM1FyMXMycBLMhkZGTI/tTIZGRkZMdkAWQBAljIyMhkyMhkyMhkZMjIyAAAAAMAZP+cArwCWAAQABcAHAFTuwAaAAEADQAEK7sABQABABUABCu4AAUQuAAB0LgABRC5AAMAAfS4AAfQuAAFELgACdC4AAIQuAAK0LgABRC4ABHQuAARL7gAGhC4ABLQuAACELgAFtC4ABYvuAAFELgAGNC4AAUQuAAb0LgAAhC4ABzQALgAAEVYuAADLxu5AAMABj5ZuAAARVi4AA8vG7kADwAGPlm4AABFWLgAEi8buQASAAY+WbgAAEVYuAAXLxu5ABcABj5ZuAAARVi4AAovG7kACgAEPlm4AABFWLgACS8buQAJAAI+WboAAQACAAMruAADELgABNy4AAXQuAAJELgABty4AAoQuAAI3LgADNC4AA3QuAACELgADtC4AAEQuAAQ0LgAAhC4ABHQuAAGELgAFNy4AAUQuAAV0LgAFtC4AAYQuAAY0LgAGdC4AA0QuAAa0LgAG9C4ABkQuAAc0DAxEyEVMxUjFTMVIxUhNTMRIzUFIRUzNTM1EyEVITVkAfRkZGRk/gxkZAHz/tXIYwH+1AEsAlhkZMjIZGQB9GRkyGRk/tTIyAAAAQBk/5wCvAJYABoBOrsAFAABABUABCu7AAMAAQACAAQruAAUELkACAAB9LgAANC4AAIQuAAF0LgAFBC4AAnQuAAIELgAC9C4AAIQuAAN0LgAAxC4AA/QuAACELgAEdC4ABQQuAAX0LgACRC4ABjQuAAIELgAGdC4AAMQuAAc3AC4AABFWLgAAi8buQACAAY+WbgAAEVYuAAGLxu5AAYABj5ZuAAARVi4ABgvG7kAGAAGPlm4AABFWLgAEi8buQASAAQ+WbgAAEVYuAANLxu5AA0AAj5ZuAACELgAAdy4AAIQuAAE3LgAAhC4AAfQuAAEELgACNC4AAnQuAANELgACty4ABIQuAAM3LgAChC4AA7QuAAP0LgADBC4ABDQuAAR0LgAFNC4ABXQuAAJELgAFtC4ABfQuAACELgAGdC4AAEQuAAa0DAxASEVMxUjNSEVIxEzFSE1MxUjFSE1IxEzNTM1ASwBLGRk/tRkZAEsZGT+cGRkZAJYZGRkZP7UZGRkZGQBkGRkAAACAGT/nAK8AlgAEAAZASq7ABMAAQANAAQruwADAAEAEQAEK7gAERC4AAHQuAABL7gAAxC5AAYAAfS4AAMQuAAH0LgAAxC4ABbQuAAWL7gACNC4AAgvuAARELgACdC4AAkvuAARELgAFNC4ABEQuAAY0LgAGC8AuAAARVi4AAIvG7kAAgAGPlm4AABFWLgADi8buQAOAAY+WbgAAEVYuAARLxu5ABEABj5ZuAAARVi4AAovG7kACgAEPlm4AABFWLgACS8buQAJAAI+WbgAAhC4AAHcuAACELgABNy4AAkQuAAG3LgAChC4AAjcuAAM0LgADdC4AAIQuAAP0LgAARC4ABDQuAACELgAEtC4AA0QuAAT0LgAFNC4AAYQuAAV0LgAFtC4AAQQuAAX0LgAGNC4AAIQuAAZ0DAxEyEVMxUzESMVIxUhNTMRIzUFIxEzNzMRIydkAZBkZGRk/nBkZAGPx8cBY2MBAlhkZP7UZGRkAfRkZP4MZAEsZAAAAAEAZP+cArwCWAAUAJy4ABUvuAADL7kAAgAB9LgAFRC4ABHQuAARL7kACgAB9LgABdC4AAMQuAAH0LgAAxC4AAvQuAACELgADdC4AAIQuAAW3AC4AABFWLgADi8buQAOAAQ+WboAAQAEAAMrugAHAAgAAyu4AAEQuAAC3LgADhC4AArcuAAOELgADNy4AAoQuAAQ0LgAEdC4AAQQuAAS0LgAARC4ABTQMDETIRUjNSEVIRUhFSE1MxUhNTMRIzVkAlhk/tQBLP7UASxk/ahkZAJYyGTIZMhkyGQB9GQAAAAAAQBk/5wCvAJYABIAgLgAEy+4AAMvuQACAAH0uAATELgAD9C4AA8vuQAKAAH0uAAF0LgAAxC4AAfQuAACELgAFNwAuAAARVi4AAwvG7kADAAEPlm6AAEABAADK7oABwAIAAMruAABELgAAty4AAwQuAAK3LgADtC4AA/QuAAEELgAENC4AAEQuAAS0DAxEyEVIzUhFSEVIRUzFSE1MxEjNWQCWGT+1AEs/tRk/tRkZAJYyGTIZMhkZAH0ZAABAGT/nAK8AlgAIAFluwAaAAEAGwAEK7sAFAABABgABCu4ABoQuQAIAAH0uAAA0LgAFBC5AAIAAfS4ABQQuAAD0LgAAhC4AAXQuAAaELgACdC4AAgQuAAL0LgAGBC4AA3QuAACELgAD9C4AAIQuAAV0LgAGhC4AB3QuAAJELgAHtC4AAgQuAAf0LgAFBC4ACLcALgAAEVYuAADLxu5AAMABj5ZuAAARVi4AAcvG7kABwAGPlm4AABFWLgAHy8buQAfAAY+WbgAAEVYuAAULxu5ABQABD5ZuAAARVi4ABgvG7kAGAAEPlm4AABFWLgADS8buQANAAI+WboAAQACAAMrugATABAAAyu4AAMQuAAE3LgAAhC4AAbQuAAEELgACNC4AAnQuAANELgACty4ABgQuAAM3LgAChC4AA7QuAAP0LgADBC4ABbQuAAX0LgAGtC4ABvQuAAJELgAHNC4AB3QuAACELgAHtC4AAEQuAAg0DAxASEVMxUjNSEVIxEzFTM1MzUjNSERIzUjFSE1IxEzNTM1ASwBLGRk/tRkZMhkyAEsZGT+1GRkZAJYZGRkZP7UZGRkZP5wZGRkAZBkZAAAAQBk/5wDIAJYABwAtbgAHS+4AAYvuAAdELgAGdC4ABkvuQAUAAH0uAAD0LgABhC5AAsAAfS4AAYQuAAR0LgACxC4AB7cALgAAEVYuAAOLxu5AA4ABD5ZuAAARVi4ABYvG7kAFgAEPlm6AAEAAgADK7oABQASAAMruAACELgABtC4AAEQuAAI0LgAAhC4AArQuAAOELgADNy4ABDQuAAR0LgAFNC4ABXQuAAY0LgAGdC4AAIQuAAa0LgAARC4ABzQMDETIRUjFSE1IzUhFSMRMxUhNTM1IRUzFSE1MxEjNWQBLGQBLGQBLGRk/tRk/tRk/tRkZAJYZMjIZGT+DGRkyMhkZAH0ZAAAAQDI/5wCvAJYAAwARrsABAABAAkABCsAuAAARVi4AAYvG7kABgAEPlm6AAEAAgADK7gABhC4AATcuAAI0LgACdC4AAIQuAAK0LgAARC4AAzQMDETIRUjETMVITUzESM1yAH0yMj+DMjIAlhk/gxkZAH0ZAABAGT/OAK8AlgAEgC4uwAIAAEACQAEK7sAAwABABEABCu4ABEQuAAA0LgAAxC5AAUAAfS4AAgQuAAL0LgAERC4AA3QuAAFELgAD9AAuAAARVi4AAQvG7kABAAEPlm4AABFWLgACC8buQAIAAQ+WbgAAEVYuAAMLxu5AAwABD5ZugAFAAYAAyu6AAEAAgADK7gABRC4AAnQuAAIELgACty4AAUQuAAN0LgAChC4AA7QuAAP0LgAAhC4ABDQuAABELgAEtAwMQEhFSMRIxUhNSM1MxUzNTMRIzUBkAEsZGT+1GRkyGRkAlhk/ahkZGRkZAH0ZAAAAQBk/5wCvAJYACIBersAAQABAAAABCu7AA4AAQADAAQruAAOELgABdC4AA4QuQAMAAH0uAAH0LgADBC5AAoAAfS4AAMQuAAQ0LgADhC4ABHQuAAFELgAEtC4AAwQuAAT0LgABxC4ABTQuAAKELgAFdC4AA4QuAAX0LgABRC4ABjQuAADELgAGdC4AAEQuAAb0LgAABC4AB3QuAABELkAHwAB9LgAABC4ACHQALgAAEVYuAAGLxu5AAYABj5ZuAAARVi4AAovG7kACgAGPlm4AABFWLgAIC8buQAgAAY+WbgAAEVYuAAWLxu5ABYABD5ZuAAARVi4ABwvG7kAHAAEPlm6AAgABwADK7gACBC4AADQuAAGELgABNy4AAPcuAAHELgAC9C4AAQQuAAM0LgADdC4AAMQuAAO0LgAAxC4ABDcuAAWELgAEty4ABHcuAAWELgAFNy4ABIQuAAY0LgAGdC4ABEQuAAa0LgAEBC4ABvQuAAUELgAHtC4AB/QuAAHELgAIdAwMRMzETM1MzUzNTMVIxUjFSMVMxUzFTMVIzUjNSMRIzUzESM1ZMhkZGRkZGRkZGRkyGRkyGRkAlj+1GRkZGRkZGRkZGTIZP7UZAH0ZAAAAQBk/5wCvAJYABAAlbgAES+4AAUvuAARELgADdC4AA0vuQAEAAH0uAAFELkACAAB9LgABRC4AArQuAAIELgAEtwAuAAARVi4AAovG7kACgAEPlm4AABFWLgABS8buQAFAAI+WboAAQACAAMruAAKELgABNy4AAUQuAAG3LgABBC4AAjQuAAJ0LgADNC4AA3QuAACELgADtC4AAEQuAAQ0DAxEyEVIxEhNTMVIxUhNTMRIzVkASxkASxkZP4MZGQCWGT+DGRkZGQB9GQAAQBk/5wDIAJYACABYbsAAQABAAAABCu7AAYAAQADAAQruAAGELkACwAB9LkABwAB9LkACgAB9LgADdC4AAYQuAAP0LgABxC4ABHQuAAGELgAE9C4AAMQuAAV0LgAARC4ABfQuAADELgAGdC4AAAQuAAb0LgAARC5AB0AAfS4AAAQuAAf0AC4AABFWLgAAi8buQACAAY+WbgAAEVYuAAGLxu5AAYABj5ZuAAARVi4AAovG7kACgAGPlm4AABFWLgAHi8buQAeAAY+WbgAAEVYuAAOLxu5AA4ABD5ZuAAARVi4ABovG7kAGgAEPlm4AAIQuAAB3LgAAhC4AATcuAAF0LgAAhC4AAfQuAABELgACNC4AAIQuAAL0LgADhC4AAzcuAAQ0LgAEdC4AAUQuAAS0LgAE9C4AAUQuAAU3LgAExC4ABbQuAAX0LgAERC4ABjQuAAZ0LgAHNC4AB3QuAACELgAH9C4AAEQuAAg0DAxEzMVMxUzNTM1MxUjETMVITUzESMVIzUjETMVITUzESM1ZMhkZGTIZGT+1GRkZGRk/tRkZAJYZMjIZGT+DGRkASzIyP7UZGQB9GQAAAAAAQBk/5wDIAJYAB4BT7sAAQABAAAABCu7AAkAAQADAAQruAAJELgABdC4AAkQuQANAAH0uQAIAAH0uAAP0LgACRC4ABHQuAADELgAE9C4AAEQuAAV0LgAAxC4ABfQuAAAELgAGdC4AAEQuQAbAAH0uAAAELgAHdAAuAAARVi4AAMvG7kAAwAGPlm4AABFWLgACS8buQAJAAY+WbgAAEVYuAANLxu5AA0ABj5ZuAAARVi4AB0vG7kAHQAGPlm4AABFWLgADi8buQAOAAQ+WbgAAEVYuAAYLxu5ABgABD5ZugABAAIAAyu4AAMQuAAE3LgABdC4AA4QuAAQ3LgABty4AAIQuAAI0LgAARC4AArQuAACELgADNC4ABAQuAAR0LgABhC4ABLQuAAT0LgABRC4ABTQuAAV0LgAERC4ABbQuAAX0LgAGtC4ABvQuAACELgAHNC4AAEQuAAe0DAxEzMVMxUzFTMRIzUhFSMRIzUjNSM1IxEzFSE1MxEjNWTIZGRkZAEsZGRkZGRk/tRkZAJYZMhkASxkZP2oZMhk/tRkZAH0ZAAAAgBk/5wCvAJYABAAHQF0uwAUAAEADAAEK7sABgABAAcABCu4ABQQuQAXAAH0uAAA0LgABhC4AAHQuAAGELgAGtC4ABovuAAC0LgAAi+4AAYQuQAEAAH0uAAUELgACdC4AAkvuAAKELgADdC4ABQQuAAO0LgADi+4ABcQuAAP0LgABxC4ABHQuAAXELgAEtC4ABIvuAAHELgAGNC4ABgvuAAHELgAHNAAuAAARVi4AAIvG7kAAgAGPlm4AABFWLgADi8buQAOAAY+WbgAAEVYuAARLxu5ABEABj5ZuAAARVi4AAgvG7kACAAEPlm4AABFWLgABy8buQAHAAI+WbgAAhC4AAHcuAAHELgABNy4AAgQuAAG3LgACtC4AAvQuAAOELgADNy4AAIQuAAP0LgAARC4ABDQuAACELgAEtC4AAwQuAAT0LgAFNC4AAQQuAAV0LgAFtC4AAsQuAAX0LgAGNC4ABYQuAAZ0LgAGtC4ABQQuAAb0LgAHNC4AAIQuAAd0DAxASEVMxEjFSMVITUjETM1MzUXIxcjEzMVMzczEyM1ASwBLGRkZP7UZGRkyMkBZQFkxwFjAWQCWGT+cGRkZAGQZGRkZP7UZGQBLGQAAAACAGT/nAK8AlgAEgAZAQW7AAoAAQAPAAQruwAGAAEAFgAEK7gABhC4AAHQuAAGELkAAwAB9LgAFhC4AAjQuAAIL7gABhC4ABPQuAATL7gAChC4ABTQuAAGELgAGNC4ABgvALgAAEVYuAACLxu5AAIABj5ZuAAARVi4ABAvG7kAEAAGPlm4AABFWLgAEy8buQATAAY+WbgAAEVYuAAMLxu5AAwABD5ZugAFAAYAAyu4AAIQuAAB3LgAAhC4AATcuAAGELgACNy4AAwQuAAK3LgADtC4AA/QuAACELgAEdC4AAEQuAAS0LgAAhC4ABTQuAAGELgAFdC4AAcQuAAW0LgABBC4ABfQuAAY0LgAAhC4ABnQMDETIRUzFSMVIxUjFTMVITUzESM1BSEVMzczNWQB9GRkZMhk/tRkZAHz/tXHAWMCWGRkZGTIZGQB9GRkyGRkAAAAAgBk/zgDIAJYABgAJQHYuwAcAAEAFAAEK7sABgABAAcABCu4ABwQuQAfAAH0uAAA0LgABhC4AAHQuAAGELgAItC4ACIvuAAC0LgAAi+4AAoQuAAD0LgABhC5AAQAAfS4AAnQuAAEELkACwAB9LgABBC4AA3QuAAKELgADtC4ABwQuAAR0LgAES+4ABIQuAAV0LgAHBC4ABbQuAAWL7gAHxC4ABfQuAAHELgAGdC4AB8QuAAa0LgAGi+4AAcQuAAg0LgAIC+4AAcQuAAk0AC4AABFWLgAAi8buQACAAY+WbgAAEVYuAAWLxu5ABYABj5ZuAAARVi4ABkvG7kAGQAGPlm4AABFWLgACC8buQAIAAQ+WbgAAEVYuAAMLxu5AAwABD5ZuAAARVi4ABAvG7kAEAAEPlm4AABFWLgABy8buQAHAAI+WboACQAOAAMruAACELgAAdy4AAcQuAAE3LgACBC4AAbcuAAK0LgAC9C4AAkQuAAR0LgACxC4ABLQuAAT0LgAFhC4ABTcuAACELgAF9C4AAEQuAAY0LgAAhC4ABrQuAAUELgAG9C4ABzQuAAEELgAHdC4AB7QuAATELgAH9C4ACDQuAAeELgAIdC4ACLQuAAcELgAI9C4ACTQuAACELgAJdAwMQEhFTMRIxUjFTM1MxUjFSE1IzUjETM1MzUXIxcjEzMVMzczEyM1ASwBLGRkZMhkZP7UyGRkZMjJAWUBZMcBYwFkAlhk/nBkZGRkZGRkAZBkZGRk/tRkZAEsZAAAAAIAZP+cAyACWAAcACMBlLsAFAABABkABCu7AAYAAQAgAAQruAAGELgAAdC4AAYQuQADAAH0uAAgELgACNC4AAgvuAAGELgACdC4AAIQuAAK0LgAAxC4AAvQuAAGELkADQAB9LgABhC4AA/QuAACELgAENC4ACAQuAAR0LgAES+4AAYQuAAd0LgAHS+4ABQQuAAe0LgABhC4ACLQuAAiL7gAAhC4ACPQuAAjLwC4AABFWLgAAi8buQACAAY+WbgAAEVYuAAaLxu5ABoABj5ZuAAARVi4AB0vG7kAHQAGPlm4AABFWLgADi8buQAOAAQ+WbgAAEVYuAAWLxu5ABYABD5ZugAFAAYAAyu4AAIQuAAB3LgAAhC4AATcuAAGELgACNy4AA4QuAAK3LgACdy4AA4QuAAM3LgAChC4ABDQuAAR0LgACRC4ABLQuAAIELgAE9C4AAwQuAAU0LgAFdC4ABjQuAAZ0LgAAhC4ABvQuAABELgAHNC4AAIQuAAe0LgABhC4AB/QuAAHELgAINC4AAQQuAAh0LgAItC4AAIQuAAj0DAxEyEVMxUjFSMVMxUzFTMVIzUjNSMVMxUhNTMRIzUFIRUzNzM1ZAH0ZGRkZGRkyGTIZP7UZGQB8/7VxwFjAlhkZGRkZGRkyGTIZGQB9GRkyGRkAAAAAAEAZP+cArwCWAAgAWm7ABQAAQAVAAQruwAFAAEAAQAEK7gAFBC4AADQuAAFELkABAAB9LgAARC4AAfQuAAUELgACdC4AAQQuAAL0LgABRC4AA3QuAAEELgAD9C4ABUQuQARAAH0uAAX0LgABBC4ABnQuAAUELgAG9C4ABUQuAAd0LgAFBC4AB/QuAAFELgAItwAuAAARVi4AAIvG7kAAgAGPlm4AABFWLgACC8buQAIAAY+WbgAAEVYuAAeLxu5AB4ABj5ZuAAARVi4ABAvG7kAEAAEPlm4AABFWLgAFC8buQAUAAQ+WbgAAEVYuAAPLxu5AA8AAj5ZuAACELgAAdy4AATQuAACELgABty4AAIQuAAJ0LgAHhC4AArcuAAL0LgADxC4AAzcuAAQELgADty4ABLQuAAT0LgADxC4ABbcuAATELgAGNC4ABnQuAAMELgAGtC4ABvQuAALELgAHNC4AB3QuAACELgAH9C4AAEQuAAg0DAxEyEVMzUzFSM1IRUhFTMVIxUhNSMVIzUzFSE1ITUjNTM1yAEsZGTI/tQBkGRk/tRkZMgBLP5wZGQCWGRkyGTIZMhkZGTIZMhkyGQAAAAAAQBk/5wDIAJYABAA9rgAES+4AADQuAAAL7gAC9xBAwAwAAsAAV1BAwCPAAsAAV1BAwAPAAsAAV1BAwDgAAsAAV1BAwCwAAsAAV1BAwBgAAsAAV24AAPcQQMAYAADAAFdQQMADwADAAFdQQMAjwADAAFdQQMAMAADAAFdQQMAsAADAAFdQQMA4AADAAFduQACAAH0uAALELkABgAB9LgAABC5AA0AAfS4AAAQuAAP0LgAAhC4ABLcALgAAEVYuAAILxu5AAgABD5ZugABAAQAAyu4AAEQuAAC3LgACBC4AAbcuAAK0LgAC9C4AAQQuAAM0LgAAhC4AA7QuAABELgAENAwMRMhFSM1IxEzFSE1MxEjFSM1ZAK8ZMhk/tRkyGQCWMhk/gxkZAH0ZMgAAQBk/5wDIAJYABYAorsAEgABABMABCu7AA4AAQAHAAQruAATELkABgAB9LgAAdC4ABIQuAAD0LgABxC4ABDQuAAOELgAGNwAuAAARVi4ABAvG7kAEAAEPlm6AAEAAgADK7gAEBC4AATcuAAQELgABty4AAIQuAAI0LgAARC4AArQuAACELgADNC4AAYQuAAO0LgAD9C4ABLQuAAT0LgAAhC4ABTQuAABELgAFtAwMRMhFSMRMxUzESM1IRUjESMVITUjESM1ZAEsZGTIZAEsZGT+1GRkAlhk/nBkAfRkZP4MZGQB9GQAAAEAZP+cAyACWAAYANq7AAEAAQAAAAQruAABELkAAwAB9LkABgAB9LkADgAB9LgAB9C4AA4QuQAKAAH0uAAOELkADAAB9LgACBC4AA3QuAAGELgAD9C4AAUQuAAQ0LgAAxC4ABHQuAABELgAE9C4AAIQuAAU0LgAARC5ABUAAfS4AAAQuAAX0AC4AABFWLgAEC8buQAQAAQ+WboACQAKAAMruAAJELgAANC4ABAQuAAE3LgAA9y4AAbQuAADELgADNC4AAQQuAAO0LgAD9C4ABLQuAAT0LgAAxC4ABTQuAAKELgAFtAwMRMzETMVMzUzETMVIxUjFSMVIzUjNSM1IzVkyGRkZMhkZGRkZGRkAlj+1MjIASxkyMjIyMjIZAAAAAEAZP+cAyACWAAcAQG7ABgAAQAZAAQruwAMAAEAAQAEK7gAGBC4AAPQuAABELgABdC4ABkQuQAWAAH0uAAG0LgADBC4AAfQuAALELgACNC4AAwQuQAPAAH0uQARAAH0uAAJ0LgADBC4ABPQuAALELgAFNC4AAEQuAAV0AC4AABFWLgAEC8buQAQAAQ+WbgAAEVYuAAYLxu5ABgABD5ZuAAARVi4ABIvG7kAEgACPlm4AABFWLgAFi8buQAWAAI+WboAAQACAAMruAAWELgABNy4AAjQuAAJ0LgAAhC4AArQuAABELgADNC4AAIQuAAO0LgACRC4ABTQuAAV0LgAAhC4ABrQuAABELgAHNAwMRMhFSMRMxEzETMRIzUhFSMRIzUjNSMVIxUjESM1ZAEsZGRkZGQBLGRkZGRkZGQCWGT+cAEs/tQBkGRk/ahkZGRkAlhkAAABAGT/nAMgAlgALAH7uwABAAEAAAAEK7gAARC5AAMAAfS5AAYAAfS5AA4AAfS4AAfQuAAOELkACgAB9LgADhC5AAwAAfS4AAcQuAAN0LgABhC4AA/QuAAFELgAENC4AA4QuAAR0LgABxC4ABLQuAAMELgAE9C4AAoQuAAV0LgADhC4ABfQuAAHELgAGNC4AAYQuAAZ0LgABRC4ABrQuAADELgAG9C4AAEQuAAd0LgAAhC4AB7QuAAAELgAH9C4AAEQuQAiAAH0uAABELgAI9C4AB0QuAAk0LgAAxC4ACXQuAABELgAJ9C4AB0QuAAo0LgAIhC4ACnQuAAAELgAK9AAuAAARVi4ABYvG7kAFgAEPlm4AABFWLgAHi8buQAeAAQ+WboACQAKAAMrugABAAIAAyu6AAUAEAADK7gACRC4AADQuAACELgABNy4AAIQuAAG0LgAAxC4AAfQuAACELgADNC4AAMQuAAN0LgABBC4AA7QuAAWELgAEty4ABHcuAAWELgAFNy4ABIQuAAY0LgAGdC4ABEQuAAa0LgAEBC4ABvQuAAZELgAHNC4AB3QuAAUELgAINC4ACHQuAAdELgAItC4ACPQuAARELgAJNC4ABAQuAAl0LgABBC4ACbQuAAFELgAJ9C4AAIQuAAo0LgAAxC4ACnQuAAKELgAKtC4AAEQuAAs0DAxEzMVMxUzNTM1MxUjFSMVIxUzFTMVMxUjNSM1IxUjFSM1MzUzNTM1IzUjNSM1ZMhkZGTIZGRkZGRkyGRkZMhkZGRkZGQCWMhkZMhkZGRkZGRkyGRkyGRkZGRkZGQAAAAAAQBk/5wDIAJYABwBLrsAAQABAAAABCu4AAEQuQADAAH0uQAGAAH0uQAOAAH0uAAH0LgADhC5AAoAAfS4AA4QuQAMAAH0uAAHELgADdC4AAYQuAAP0LgABRC4ABDQuAAOELgAEdC4AAcQuAAS0LgAARC4ABPQuAACELgAFNC4AAMQuAAV0LgAARC4ABfQuAACELgAGNC4AAEQuQAZAAH0uAAAELgAG9AAuAAARVi4ABIvG7kAEgAEPlm6AAkACgADK7oAAQACAAMruAAJELgAANC4AAIQuAAE3LgAAhC4AAbQuAADELgAB9C4AAIQuAAM0LgAAxC4AA3QuAAEELgADtC4ABIQuAAQ3LgAFNC4ABXQuAAEELgAFtC4AAIQuAAY0LgAAxC4ABnQuAAKELgAGtC4AAEQuAAc0DAxEzMVMxUzNTM1MxUjFSMVIxEzFSE1MxEjNSM1IzVkyGRkZMhkZGRk/tRkZGRkAljIZGTIZGRk/tRkZAEsZGRkAAABAMj/nAK8AlgAHAE6uwAZAAEAAAAEK7gAGRC5AAgAAfS5AAYAAfS5AAQAAfS5AAIAAfS4ABkQuAAJ0LgABBC4AAvQuAADELgADNC4AAIQuAAN0LgAABC4AA/QuAAZELgAEdC4AAkQuAAS0LgACBC4ABPQuAAHELgAFNC4AAYQuAAV0LgABRC4ABbQuAAEELgAF9C4AAMQuAAY0LgAABC4ABvQALgAAEVYuAAOLxu5AA4ABD5ZugABABgAAyu6AAMABAADK7gAARC4AALcuAAEELgABty4AA4QuAAI3LgAB9y4AA4QuAAK3LgACBC4AAzQuAAN0LgAENC4ABHQuAAHELgAEtC4AAYQuAAT0LgABBC4ABTQuAAFELgAFdC4AAIQuAAW0LgAAxC4ABfQuAACELgAGtC4AAMQuAAb0LgAARC4ABzQMDETIRUjFSMVIxUjFSE1MxUhNTM1MzUzNTM1IRUjNcgB9GRkZGQBLGT+DGRkZGT+1GQCWMhkZGRkZMjIZGRkZGTIAAEAyP+cAlgCWAAIAD67AAMAAQAAAAQruAAAELgAB9AAuAAARVi4AAYvG7kABgAEPlm6AAEAAgADK7gABhC4AATcuAABELgACNAwMRMhFSERIRUhEcgBkP7UASz+cAJYZP4MZAK8AAAAAQBk/zgCWAJYABQBCbsAAQABAAAABCu4AAEQuQADAAH0uQAFAAH0uQAHAAH0uQAJAAH0uAAHELgAC9C4AAgQuAAM0LgABRC4AA3QuAAGELgADtC4AAMQuAAP0LgABBC4ABDQuAABELgAEdC4AAIQuAAS0LgAABC4ABPQALgAAEVYuAACLxu5AAIABj5ZuAAARVi4ABIvG7kAEgAGPlm4AABFWLgACC8buQAIAAQ+WbgAAEVYuAAMLxu5AAwABD5ZugAJAAoAAyu4AAIQuAAB3LgAAhC4AATcuAAIELgABty4AAXcuAAJELgADdC4AAYQuAAO0LgAD9C4AAQQuAAQ0LgAEdC4AAIQuAAT0LgAARC4ABTQMDETMxUzFTMVMxUzFSM1IzUjNSM1IzVkZGRkZGRkZGRkZAJYZMjIyGRkyMjIZAAAAQDI/5wCWAJYAAgANrsAAgABAAUABCsAuAAARVi4AAIvG7kAAgAEPlm6AAEABgADK7gAAhC4AATcuAABELgACNAwMRMhESE1IREhNcgBkP5wASz+1AJY/URkAfRkAAAAAQDI/5wCvAJYABQBBLgAFS+4AA/QuAAPL7gAANxBAwAQAAAAAV1BAwBQAAAAAV1BAwCQAAAAAV1BAwDQAAAAAV25AAEAAfS4AAAQuAAE3EEDANAABAABXUEDAFAABAABXUEDAJAABAABXUEDABAABAABXbkABQAB9LgABBC4AAfQuAABELgACdC4AAAQuAAL0LgADxC5AA4AAfS4ABHQuAAAELgAE9C4AAUQuAAW3AC4AAAvuAAARVi4AAIvG7kAAgAGPlm4AABFWLgAEi8buQASAAY+WbgAAEVYuAAKLxu5AAoABD5ZugAFAAYAAyu4AAIQuAAI3LgADNC4AA3QuAAGELgADtC4AAUQuAAQ0DAxATMVMxUzFSM1IxEjESMVIzUzNTM1AZBkZGRkZGRkZGRkAlhkZMhk/nABkGTIZGQAAAAAAQAA/zgDIP+cAAQAEwC6AAEAAgADK7gAARC4AATQMDEVIRUhNQMg/OBkZGQAAAAAAgAA/5wCvAH0ABQAHwFuuwAZAAEADwAEK7sABQABAAQABCu4ABkQuQAWAAH0uAAA0LgAAC+4ABYQuQABAAH0uAAEELkABwAB9LgABBC4AAnQuAABELgAC9C4ABkQuAAN0LgADS+4ABIQuAAO0LgAGRC4ABHQuAARL7gAABC4ABPQuAABELgAFdC4ABUvuAAAELgAF9C4AAEQuAAa0LgAGi+4AAQQuAAc0LgAChC4AB3QuAABELgAHtAAuAAARVi4AAAvG7kAAAAGPlm4AABFWLgABC8buQAEAAY+WbgAAEVYuAAILxu5AAgABD5ZuAAARVi4AAwvG7kADAAEPlm4AABFWLgABy8buQAHAAI+WbgABBC4AALcuAAS0LgAA9C4AAgQuAAG3LgACtC4AAvQuAAO0LgAD9C4ABIQuAAR3LgAEhC4ABPQuAAV0LgAFtC4ABEQuAAX0LgADxC4ABnQuAAa0LgABxC4ABvcuAARELgAHdC4ABYQuAAf0DAxEzMVMzUzETMVIzUjFSE1IxEzNTM1FyMXIxEhNzM1IyfIyGRkZMhk/tRkZGTHyAFjASoBZGQBAfRkZP4MZGRkZAEsZGRkZP7UZMhkAAAAAAIAZP+cArwCWAAQABsBIbsAFQABAA8ABCu7AAYAAQADAAQruAAPELgAANC4ABUQuAAB0LgAAS+4AAYQuQAHAAH0uQAJAAH0uAAHELgAC9C4ABkQuAAM0LgADC+4ABUQuAAN0LgADS+4AAYQuAAR0LgAES+4AAMQuAAS0LgAEi+4AAYQuAAW0LgAERC4ABfQuAAXL7gABxC4ABjQuAAGELgAGtAAuAAAL7gAAEVYuAAELxu5AAQABj5ZuAAARVi4AAwvG7kADAAEPlm4AAQQuAAC3LgABtC4AAfQuAAD0LgABxC4AAjcuAAMELgACty4AA7QuAAP0LgABxC4ABHQuAAS0LgACBC4ABPQuAAPELgAFdC4ABbQuAAMELgAF9y4AAgQuAAZ0LgAEhC4ABvQMDETMxUzNTMVMxUzESMVITUjEQUjFyMDITUzJyMnZGRkyGRkZP5wZAGPyAFkAQEtZAFjAQJYyGRkZP7UZGQCWMhk/tRkyGQAAAABAGT/nAK8AfQAGgEMuwAUAAEAFQAEK7sAAwABAAIABCu4ABQQuQAIAAH0uAAA0LgAAhC4AAXQuAAUELgACdC4AAgQuAAL0LgAAhC4AA3QuAADELgAD9C4AAIQuAAR0LgAFBC4ABfQuAAJELgAGNC4AAgQuAAZ0LgAAxC4ABzcALgAAEVYuAAALxu5AAAABj5ZuAAARVi4ABIvG7kAEgAEPlm4AABFWLgADS8buQANAAI+WboAAwAEAAMruAAAELgAAty4AAbQuAAH0LgABBC4AAjQuAANELgACty4ABIQuAAM3LgAChC4AA7QuAAP0LgADBC4ABDQuAAR0LgAFNC4ABXQuAAEELgAFtC4AAcQuAAY0LgAGdAwMQEhFTMVIzUhFSMVMxUhNTMVIxUhNSMRMzUzNQEsASxkZP7UZGQBLGRk/nBkZGQB9GRkZGTIZGRkZGQBLGRkAAIAAP+cArwB9AAQAB0BOrsAFAABAAwABCu7AAYAAQAHAAQruAAGELgAAdC4AAYQuAAa0LgAGi+4AALQuAACL7gABhC5AAQAAfS4ABQQuAAJ0LgACS+4AAoQuAAN0LgAFBC4AA7QuAAOL7gABxC4ABHQuAAUELkAFwAB9LgAEtC4AAcQuAAY0LgAGC+4AAcQuAAc0AC4AABFWLgAAC8buQAAAAY+WbgAAEVYuAAILxu5AAgABD5ZuAAARVi4AAcvG7kABwACPlm4AAAQuAAC3LgABxC4AATcuAAIELgABty4AArQuAAL0LgAABC4AAzcuAACELgADtC4AA/QuAAR0LgAEtC4AAwQuAAT0LgAFNC4AAQQuAAV0LgAFtC4AAsQuAAX0LgAGNC4ABYQuAAZ0LgAGtC4ABQQuAAb0LgAHNC4ABIQuAAd0DAxESEVMxEjFSMVITUjETM1IzUFIxUjFzMVMzczNyM1AlhkZGT+1GRkyAH0yGUBZMcBYwFkAfRk/tRkZGQBLGRkZGTIZGTIZAACAGT/nAK8AfQAEAAbASm7ABQAAQAMAAQruwADAAEAEQAEK7gAFBC5ABYAAfS4AADQuAAAL7gAAxC5AAIAAfS4ABYQuAAF0LgABS+4AAMQuAAH0LgAFBC4AAnQuAAJL7gAFRC4AArQuAAVELgADdC4ABQQuAAO0LgADi+4ABYQuAAP0LgADy+4ABYQuAAS0LgAAhC4ABjQuAARELgAGtC4AAMQuAAd3AC4AABFWLgAAC8buQAAAAY+WbgAAEVYuAAILxu5AAgABD5ZuAAAELgAAty4AA7QuAAD0LgACBC4AATcuAAIELgABty4AArQuAAL0LgADhC4AA3cuAAOELgAD9C4ABHQuAAS0LgADRC4ABPQuAAEELgAFdC4ABbQuAAEELgAGNy4AA0QuAAZ0LgAEhC4ABvQMDEBIRUzESEVIRUhNSMRMzUzNRcjFyMXMzchNSM1ASwBLGT+cAGQ/gxkZGTIyQFlAWMBASxkAfRk/tRkZGQBLGRkZGTIZGRkAAABAGT/OAK8AfQAFAC8uwABAAEAAAAEK7sABwABAAYABCu4AAAQuQAEAAH0uAAGELgACdC4AAQQuAAL0LgAARC4AA3QuAABELgAEdC4AAAQuAAT0LgABxC4ABbcALgAEi+4AABFWLgAAC8buQAAAAY+WbgAAEVYuAAELxu5AAQABj5ZuAAARVi4ABAvG7kAEAACPlm4AAAQuAAC3LgAA9C4AAbQuAAH0LgACNy4AAcQuAAK0LgAC9C4AAgQuAAM0LgAEBC4AA7cMDETMxUzNSEVMxUjNSEVIxUhFSEVIxFkZGQBLGRk/tRkASz+1GQB9GRkZGRkZMhkyAK8AAABAGT/OAK8AfQAHAFRuwAYAAEAGwAEK7sACQABAAgABCu4ABsQuAAA0LgAGBC5ABUAAfS5AAQAAfS4ABUQuAAF0LgAFRC5AAcAAfS4AAgQuAAL0LgABxC4AAzQuAAYELgADdC4ABgQuAAR0LgADtC4ABsQuAAP0LgACBC4ABPQuAAHELgAFNC4AAUQuAAW0LgAFRC4ABnQuAAFELgAGtAAuAAARVi4AAAvG7kAAAAGPlm4AABFWLgACi8buQAKAAQ+WbgAAEVYuAAOLxu5AA4ABD5ZuAAARVi4ABIvG7kAEgAEPlm6AAsADAADK7oABQAGAAMruAAAELgAAty4AAAQuAAE3LgAChC4AAjcuAAH3LgACxC4AA/QuAAOELgAENy4AAsQuAAT0LgACBC4ABTQuAAV0LgABhC4ABbQuAAHELgAF9C4AAQQuAAY0LgAGdC4AAIQuAAa0LgAG9AwMRMhFSEVIxUzFTMVIxUhNSM1MxUhNSM1IzUzNSM1ZAJY/tRkyGRk/tRkZAEsyGRkyAH0ZGRkZMhkZGRkyGRkZGQAAAEAAP+cArwCWAAUAOG7AAEAAQAAAAQruwAHAAEADAAEK7gAARC5ABEAAfS5AA4AAfS4AAPQuAAHELkABgAB9LgACdC4AAEQuAAP0LgAABC4ABPQuAAHELgAFtwAuAAARVi4AAQvG7kABAAGPlm4AABFWLgAEi8buQASAAY+WbgAAEVYuAAILxu5AAgABD5ZuAAARVi4ABAvG7kAEAAEPlm4AAQQuAAB3LgABBC4AALcuAAG0LgAA9C4AAYQuAAH0LgABhC4AArcuAAHELgADNC4AA3QuAAKELgADtC4AAQQuAAT0LgAARC4ABTQMDERMxUzNSEVMxEjESM1IxUjESMRIzXIZAEsZGRkyGRkZAJYyGRk/gwBkGRk/nACWGQAAAEAyP+cAZAB9AAGAEm7AAEAAQAAAAQruAABELkAAwAB9LgAABC4AAXQALgAAEVYuAAALxu5AAAABj5ZuAAARVi4AAIvG7kAAgAEPlm4AAAQuAAE3DAxEzMRIxEjNcjIZGQB9P2oAfRkAAAAAAEAyP84AlgB9AAOALu7AAYAAQAHAAQruwABAAEAAAAEK7gABhC5AAQAAfS5AAIAAfS4AAYQuAAJ0LgABRC4AArQuAAEELgAC9C4AAMQuAAM0LgAABC4AA3QALgAAEVYuAAALxu5AAAABj5ZuAAARVi4AAIvG7kAAgAEPlm4AABFWLgABi8buQAGAAQ+WbgAAEVYuAAKLxu5AAoABD5ZugADAAQAAyu4AAMQuAAH0LgABhC4AAjcuAADELgAC9C4AAAQuAAM3DAxATMRIxUjNSM1MxUzESM1AZDIZMhkZMhkAfT9qGRkZGQB9GQAAQBk/5wCvAJYABwBQrsAAQABAAAABCu7AA4AAQAVAAQruAAOELkAAwAB9LgADhC4AAXQuAAK0LgABtC4AA4QuQAIAAH0uAAOELgACdC4AAMQuAAM0LgACBC4AA/QuAAOELgAEdC4AAoQuAAS0LgAAxC4ABPQuAABELgAF9C4AAEQuQAZAAH0uAAAELgAG9AAuAAARVi4AAYvG7kABgAGPlm4AABFWLgAGi8buQAaAAY+WbgAAEVYuAAQLxu5ABAABD5ZuAAARVi4ABgvG7kAGAAEPlm4AABFWLgAEi8buQASAAI+WbgAGhC4AAHcuAAQELgADty4AArcuAAC0LgABhC4AATcuAAD3LgAGhC4AAfQuAAEELgACNC4AAnQuAADELgAC9C4ABIQuAAM3LgADhC4ABTQuAAV0LgADBC4ABbQuAAX0LgAARC4ABzQMDETMxEzNTM1MxUjFSMVMxUzFSM1IzUjNSMRIxEjNWTIyGRkZGRkZGRkZGRkZAJY/tRkZGRkZGTIZGRk/tQCWGQAAAEBLP+cAfQCWAAGADi7AAEAAQAAAAQruAABELkAAwAB9LgAABC4AAXQALgAAEVYuAACLxu5AAIABD5ZugAAAAUAAyswMQEzESMRIzUBLMhkZAJY/UQCWGQAAAAAAQAA/5wDIAH0ABgA77sAAQABAAAABCu7AAYAAQADAAQruwAJAAEACAAEK7gACRC5AAsAAfS4AAYQuAAN0LgABhC5AA8AAfS4AAEQuAAR0LgAABC4ABPQuAAAELgAF9C4AAkQuAAa3AC4AABFWLgAAC8buQAAAAY+WbgAAEVYuAAELxu5AAQABj5ZuAAARVi4AAgvG7kACAAGPlm4AABFWLgACi8buQAKAAQ+WbgAAEVYuAAOLxu5AA4ABD5ZuAAARVi4ABIvG7kAEgAEPlm4AAgQuAAM3LgAB9y4AALQuAAMELgAENC4ABHQuAAU0LgAFdC4AAcQuAAW0DAxEzMVMzUzFTM1MxEjESMRIxEjESMRIzUzNWRkZMhkyGTIZMhkZGQB9GRkZGT9qAGQ/nABkP5wAZBkZAAAAQAA/5wCvAH0ABQA1bsAAQABAAAABCu7AAcAAQAMAAQruAABELkAEQAB9LkADgAB9LgAA9C4AAcQuQAGAAH0uAAJ0LgAARC4AA/QuAAAELgAE9C4AAcQuAAW3AC4AABFWLgAAC8buQAAAAY+WbgAAEVYuAAELxu5AAQABj5ZuAAARVi4AAgvG7kACAAEPlm4AABFWLgAEC8buQAQAAQ+WbgABBC4AALcuAAG0LgAA9C4AAYQuAAH0LgABhC4AArcuAAHELgADNC4AA3QuAAKELgADtC4AA0QuAAS0LgAE9AwMREzFTM1IRUzESMRIzUjFSMRIxEjNchkASxkZGTIZGRkAfRkZGT+DAGQZGT+cAH0ZAAAAgBk/5wCvAH0ABAAHQFKuwAUAAEADAAEK7sABgABAAcABCu4ABQQuQAXAAH0uAAA0LgABhC4AAHQuAAGELgAGtC4ABovuAAC0LgAAi+4AAYQuQAEAAH0uAAUELgACdC4AAkvuAAKELgADdC4ABQQuAAO0LgADi+4ABcQuAAP0LgABxC4ABHQuAAXELgAEtC4ABIvuAAHELgAGNC4ABgvuAAHELgAHNAAuAAARVi4AAAvG7kAAAAGPlm4AABFWLgACC8buQAIAAQ+WbgAAEVYuAAHLxu5AAcAAj5ZuAAAELgAAty4AA7QuAAD0LgABxC4AATcuAAIELgABty4AArQuAAL0LgADhC4AA3cuAAOELgAD9C4ABHQuAAS0LgADRC4ABPQuAAEELgAFdC4ABbQuAALELgAF9C4ABjQuAAWELgAGdC4ABrQuAANELgAG9C4ABIQuAAd0DAxASEVMxEjFSMVITUjETM1MzUXIxcjFzMVMzczNyM1ASwBLGRkZP7UZGRkyMkBZQFkxwFjAWQB9GT+1GRkZAEsZGRkZMhkZMhkAAAAAgBk/zgCvAH0ABIAHwFtuwABAAEAAAAEK7sAEwABAAMABCu4ABMQuQAKAAH0uAAF0LgAChC4ABzQuAAcL7gABtC4AAYvuAAKELkACAAB9LgAExC4AAvQuAADELgADdC4AAAQuQAUAAH0uAAO0LgADi+4AAEQuAAP0LgAABC4ABHQuAADELgAFdC4AAEQuAAW0LgAAxC4ABjQuAAUELgAGdC4ABMQuAAa0LgAGi+4AAsQuAAb0LgAExC4AB7QALgAEC+4AABFWLgAAC8buQAAAAY+WbgAAEVYuAAELxu5AAQABj5ZuAAARVi4AAwvG7kADAAEPlm4AABFWLgACy8buQALAAI+WbgAABC4AALcuAAD0LgABtC4AAfQuAALELgACNy4AAwQuAAK3LgADtC4AA/QuAAHELgAE9C4ABTQuAADELgAFdy4AAgQuAAX0LgAGNC4AA8QuAAZ0LgAGtC4ABgQuAAb0LgAHNC4ABUQuAAd0LgAFBC4AB/QMDETMxUzNSEVMxEjFSMVIzUjFSMRBSMXIxUzBzM3MzcjNWRkZAEsZGRkyGRkAZDJAWRkAcgBYwFkAfRkZGT+1GRkZMgCvGRkyGRkyGQAAgBk/zgDIAH0ABQAIQGVuwAZAAEAEQAEK7sABQABAAQABCu4ABkQuAAA0LgAAC+4ABkQuQAbAAH0uQAMAAH0uAAB0LgABBC5AAcAAfS4AAQQuAAJ0LgAGxC4AA3QuAANL7gAGRC4AA/QuAAPL7gAGRC4ABPQuAATL7gADxC4ABTQuAAMELgAFdC4ABUvuAAbELgAFtC4ABYvuAANELgAF9C4AA0QuAAa0LgADBC4ABzQuAAcL7gABBC4AB7QuAAJELgAH9C4AAwQuAAg0LgABRC4ACPcALgAAEVYuAAALxu5AAAABj5ZuAAARVi4AAQvG7kABAAGPlm4AABFWLgABi8buQAGAAQ+WbgAAEVYuAAMLxu5AAwABD5ZugAHAAgAAyu4AAQQuAAC3LgAEtC4ABPQuAAV0LgAFtC4AAPQuAAGELgACty4AAvQuAAHELgADdC4AAsQuAAO0LgAD9C4AAoQuAAQ3LgAFhC4ABfcuAAQELgAGdC4ABrQuAAPELgAG9C4ABzQuAAaELgAHdC4AB7QuAAXELgAH9C4ABYQuAAh0DAxEyEVMzUzETMVIzUjFSM1IzUjETM1BSMVIwczBzM3MzUjJ8gBLGRkZMhkyGRkZAErx2QBZQHIAWRkAQH0ZGT9qGTIZGRkASxkZGTIZGTIZAABAAD/nAK8AfQAIgFcuwABAAEAAAAEK7sADAABABEABCu4AAwQuQAKAAH0uAAF0LgAChC5AAcAAfS4AAYQuAAJ0LgAChC4AA3QuAAGELgADtC4AAwQuAAP0LgACxC4ABDQuAAMELgAFdC4AAsQuAAW0LgAChC4ABfQuAAGELgAGNC4AAEQuAAb0LgAABC4AB3QuAAAELgAIdAAuAAARVi4AAAvG7kAAAAGPlm4AABFWLgABC8buQAEAAY+WbgAAEVYuAAOLxu5AA4ABD5ZuAAARVi4ABwvG7kAHAAEPlm4AABFWLgADS8buQANAAI+WbgAABC4AALcuAAD0LgABtC4AAfQuAANELgACNy4AAYQuAAX3LgACty4AAncuAAOELgADNy4ABDQuAAR0LgAChC4ABLQuAAIELgAFNC4ABXQuAAHELgAGNC4ABnQuAAXELgAGtC4ABcQuAAe0LgAGRC4ACDQuAAh0DAxEzMVMzUhFTMVIxUjFTMVIzUjNSM1MzUzNSEVIxEjESM1MzVkZGQBLGRkZGRkZGTIZP7UZGRkZAH0ZGRkyGRkZGRkZGRkZP5wAZBkZAAAAAEAZP+cAlgB9AAgAYK7ABIAAQATAAQruAASELgAANC4ABIQuQAJAAH0uQAFAAH0uAAB0LgABRC5AAMAAfS4AAIQuAAG0LgAEhC4AAfQuAAFELgAC9C4AAIQuAAM0LgAAxC4AA3QuAAFELgAD9C4AAIQuAAQ0LgAEhC4ABXQuAAIELgAFtC4AAUQuAAX0LgAAhC4ABjQuAAJELgAGdC4ABIQuAAb0LgACBC4ABzQuAATELgAHdC4ABIQuAAf0LgACBC4ACDQALgAAEVYuAAALxu5AAAABj5ZuAAARVi4ABAvG7kAEAAEPlm4AABFWLgADy8buQAPAAI+WboAAwAEAAMrugAJAAoAAyu4AAAQuAAC3LgABtC4AAfQuAAEELgACNC4AA8QuAAM3LgAC9y4ABAQuAAO3LgAEtC4ABPQuAAMELgAFNC4ABXQuAATELgAFtC4ABfQuAAVELgAGNC4ABnQuAALELgAGtC4AAoQuAAb0LgABBC4ABzQuAAJELgAHdC4AAcQuAAe0LgAH9AwMRMhFTMVIzUhFTMVMxUzFSMVITUjNTMVITUjNSM1IzUzNcgBLGRk/tTIZGRk/tRkZAEsZMhkZAH0ZGRkZGRkZGRkZGRkZGRkZAABAGT/nAK8AfQAFgDkuwAQAAEAEQAEK7sADAABAAkABCu4AAwQuAAB0LgAEBC5AAQAAfS4ABAQuAAF0LgABBC4AAfQuAAJELgADtC4ABAQuAAT0LgABRC4ABTQuAAMELgAGNwAuAAARVi4AAAvG7kAAAAGPlm4AABFWLgADi8buQAOAAQ+WbgAAEVYuAAJLxu5AAkAAj5ZuAAAELgAAty4AAAQuAAE3LgACRC4AAbcuAAOELgACNy4AAYQuAAK0LgAC9C4AAgQuAAM0LgADdC4ABDQuAAR0LgABBC4ABLQuAAT0LgAAhC4ABTQuAAV0DAxEyEVIRUjFTMVMzUzFSMVITUjETM1IzVkAlj+1GRkyGRk/tRkZMgB9GRkyGRkZGRkASxkZAAAAAEAAP+cAyAB9AAYAQS7AAEAAQAAAAQruwAMAAEABQAEK7gAARC5ABUAAfS5AAQAAfS4AAwQuQAQAAH0uAAH0LgABRC4AAnQuAAQELkADQAB9LgABRC4ABHQuAABELgAE9C4AAAQuAAX0LgADBC4ABrcALgAAEVYuAAALxu5AAAABj5ZuAAARVi4AAovG7kACgAGPlm4AABFWLgADi8buQAOAAQ+WbgAAEVYuAASLxu5ABIABD5ZuAAARVi4AAUvG7kABQACPlm4AALcuAASELgABNy4AAIQuAAG0LgAB9C4AAoQuAAI3LgABBC4AAzQuAAN0LgAENC4ABHQuAAU0LgAFdC4AAgQuAAW0LgAF9AwMREzETMVMzUzESM1MxEzFSM1IxUhNSMRIzXIZMhkZMhkyGT+1GRkAfT+cGRkASxk/gxkZGRkAZBkAAAAAQAA/5wCvAH0ABwBQbsAAQABABoABCu7ABIAAQADAAQruAABELkAAAAB9LkABAAB9LgAEhC4AAXQuAASELkAEAAB9LgAB9C4ABAQuQAOAAH0uAAJ0LgADhC5AAwAAfS4AAQQuAAT0LgAAxC4ABTQuAABELgAFdC4AAAQuAAX0LgAABC4ABvQuAAYELgAHNAAuAAARVi4AAAvG7kAAAAGPlm4AABFWLgACi8buQAKAAY+WbgAAEVYuAAWLxu5ABYABD5ZuAAARVi4ABQvG7kAFAACPlm6AAQAAwADK7gAFBC4AALcuAAEELgABty4AAoQuAAI3LgAB9y4AAgQuAAM0LgADdC4AAcQuAAO0LgABhC4AA/QuAAEELgAENC4AAUQuAAR0LgAAhC4ABLQuAAT0LgABxC4ABjQuAAGELgAGdC4AA0QuAAa0LgAG9AwMRMzETM1MzUzNTM1MxUjFSMVIxUjFSMVIxEjNTM1ZGRkZGRkZGRkZGRkZGRkAfT+cGRkZGRkZGRkZGQBkGRkAAAAAAEAAP+cAyAB9AAeAUS7AAEAAQAAAAQruAABELkABAAB9LkAFgAB9LgABdC4ABYQuQAIAAH0uQAJAAH0uQALAAH0uQAOAAH0uAALELgAD9C4AAkQuAAR0LgAChC4ABLQuAAIELgAE9C4AAUQuAAV0LgABBC4ABfQuAADELgAGNC4AAEQuAAZ0LgAARC5ABsAAfS4AAAQuAAd0AC4AABFWLgAAC8buQAAAAY+WbgAAEVYuAAGLxu5AAYABj5ZuAAARVi4AAwvG7kADAAGPlm4AABFWLgAEC8buQAQAAQ+WbgAAEVYuAAYLxu5ABgABD5ZuAAC3LgABhC4AATcuAAD3LgABBC4AAjQuAAJ0LgAAhC4AArQuAAL0LgADtC4AA/QuAAS0LgAE9C4AAkQuAAU0LgAFdC4ABMQuAAW0LgAF9C4ABrQuAAb0LgAABC4ABzcMDERMxEzNTM1MxUzFTMRMxEjFSM1IzUjFSMVIzUjESM1yGRkZGRkZGRkZGRkZGRkAfT+cMjIyMgBkP5wyMjIyMjIASxkAAAAAAEAAP+cAyAB9AAuAja7AB4AAQAfAAQruwAGAAEAAgAEK7gAHhC4AADQuAAeELkAAQAB9LgAHhC5ACgAAfS5ABoAAfS4AAPQuAAaELkABwAB9LgABhC5AAwAAfS4AAjQuAASELgACdC4AAcQuQAKAAH0uAAHELgAC9C4AAYQuAAN0LgABRC4AA7QuAAHELgAD9C4AAwQuAAQ0LgAChC4ABHQuAAKELkAEwAB9LgAChC4ABXQuAASELgAFtC4AAYQuAAX0LgABRC4ABjQuAADELgAGdC4ACgQuAAb0LgAHhC4ACHQuAAeELgAKdC4ACLQuAAoELgAI9C4ABsQuAAk0LgAAhC4ACXQuAABELgAJtC4ABsQuAAn0LgAABC4ACrQuAAfELgAK9C4AB4QuAAt0LgAKRC4AC7QALgAAEVYuAAALxu5AAAABj5ZuAAARVi4AAgvG7kACAAGPlm4AABFWLgAFi8buQAWAAQ+WbgAAEVYuAAeLxu5AB4ABD5ZuAAARVi4ABEvG7kAEQACPlm4AAAQuAAC3LgAA9C4AATcuAADELgABtC4AAfQuAAK0LgAC9C4AAQQuAAM0LgAERC4AA7cuAAS0LgAE9C4ABrQuAAP0LgAFhC4ABDcuAAU0LgAFdC4ABjQuAAZ0LgAGhC4ABvQuAAZELgAHNC4AB3QuAAg0LgAIdC4ABsQuAAi0LgAI9C4ABoQuAAl3LgABBC4ACbQuAALELgAKNC4ACnQuAAEELgAKtC4ACkQuAAs0LgALdAwMRMzFTMVMzUzNTMVIxUjFTMVMzUzFSMVIzUjNSMVIxUjNTM1MzUzNSM1IxUjNTM1ZMhkZGRkZGRkZGRkyGTIZGRkZGRkZGRkAfRkZGRkZGTIZGRkZGRkZGRkZGRkZGRkZAABAAD/OAK8AfQAGgDwuwABAAEAAAAEK7sADAABABQABCu4AAEQuQAQAAH0uQAEAAH0uAAUELgABdC4AAwQuQAIAAH0uAAUELgACdC4AAgQuAAN0LgAEBC4ABfQuAAP0LgACBC4ABHQuAABELgAFdC4AAAQuAAZ0LgADBC4ABzcALgAAEVYuAAALxu5AAAABj5ZuAAARVi4AAovG7kACgAGPlm4AABFWLgAFC8buQAUAAI+WboADQAOAAMruAAUELgABNy4AAPcuAAG0LgAChC4AAjcuAANELgAENC4AAQQuAAS0LgAE9C4ABbQuAAX0LgACBC4ABjQuAAZ0DAxETMRMxUzNTM1IzUzESMVITUhNSMVITUjESM1yGTIZGTIZP4MAfRk/tRkZAH0/tRkZMhk/ahkZMhkZAEsZAAAAQBk/5wCvAH0AB4BYbsAEQABABAABCu4ABEQuAAA0LgAERC5ABQAAfS5AAgAAfS5AAYAAfS5AAQAAfS5AAIAAfS4ABQQuAAJ0LgABBC4AAvQuAADELgADNC4AAIQuAAN0LgACRC4ABPQuAAIELgAFdC4AAcQuAAW0LgABhC4ABfQuAAFELgAGNC4ABEQuAAZ0LgAEhC4ABrQuAAQELgAG9C4ABEQuAAd0LgAEhC4AB7QALgAAEVYuAAALxu5AAAABj5ZuAAARVi4AA4vG7kADgAEPlm6AAMABAADK7gAABC4AALcuAAEELgABty4AA4QuAAI3LgAB9y4AA4QuAAK3LgACBC4AAzQuAAN0LgAChC4ABDQuAAR0LgADRC4ABLQuAAT0LgABxC4ABTQuAAGELgAFdC4AAQQuAAW0LgABRC4ABfQuAACELgAGNC4ABnQuAAEELgAGtC4AAUQuAAb0LgAGRC4ABzQuAAd0DAxEyEVIxUjFSMVIxUhNTMVITUzNTM1MzUzNSEVIzUzNcgB9GRkZGQBLGT9qGRkZGT+1GRkAfRkZGRkZGTIZGRkZGRkZGQAAAEAZP+cArwCWAAUAIC7AAcAAQAOAAQruAAHELkAAAAB9LgABxC4AAPQuAAAELgABdC4AAAQuAAL0LgADhC4ABHQuAAAELgAE9AAuAAARVi4AAovG7kACgAEPlm6AAEAAgADK7oABQAGAAMruAAKELgACNy4AAYQuAAO0LgABRC4ABDQuAABELgAFNAwMQEhFSMVIxUzFTMVITUjNSM1MzUzNQGQASzIZGTI/tRkyMhkAlhkyGTIZMhkZGTIAAAAAAEBLP+cAZACWAAEACq7AAEAAQAAAAQruAAAELgAA9AAuAAAL7gAAEVYuAACLxu5AAIABD5ZMDEBMxEjEQEsZGQCWP1EArwAAAEAZP+cArwCWAAUAHS7AAkAAQANAAQruAAJELgAAdC4AA0QuQAIAAH0uAAD0LgACRC4AA/QuAANELgAEdAAuAAARVi4AAovG7kACgAEPlm6AAEAEgADK7oABQAGAAMruAAKELgADNy4AAYQuAAO0LgABRC4ABDQuAABELgAFNAwMRMhFTMVMxUjFSMVITUzNTM1IzUjNWQBLGTIyGT+1MhkZMgCWMhkZGTIZMhkyGQAAQAAAZACvAJYABAAy7gAES+4AAMvuAARELgADdC4AA0vuQAMAAH0uAAA0LgAAxC5AAYAAfS4AAMQuAAI0LgADBC4AA/QuAAGELgAEtwAuAAARVi4AAIvG7kAAgAGPlm4AABFWLgABi8buQAGAAY+WbgAAEVYuAAKLxu5AAoABj5ZuAAARVi4AA4vG7kADgAGPlm4AAIQuAAB3LgABNC4AAIQuAAH0LgABhC4AAjcuAAJ0LgAAhC4AAvQuAAJELgADNC4AA3QuAACELgAD9C4AAEQuAAQ0DAxEyEVMzUzFSMVITUjFSM1MzVkASzIZGT+1MhkZAJYZGRkZGRkZGQAAAEAAP84ArwCWAAkAbi7ABgAAQAZAAQruwAMAAEAHQAEK7gADBC5AAgAAfS4AADQuAAIELkAAQAB9LkAAwAB9LgAARC4AAXQuAACELgABtC4AAAQuAAH0LgAARC4AAnQuAACELgACtC4AAgQuAAN0LgAABC4AA7QuAABELgAD9C4AAIQuAAQ0LgAAxC4ABHQuAABELgAE9C4AAIQuAAU0LgADBC4ABXQuAAMELgAIdC4ABbQuAAYELgAG9C4ABgQuAAf0LgACBC4ACPQALgAAEVYuAACLxu5AAIABj5ZuAAARVi4AAYvG7kABgAGPlm4AABFWLgAIi8buQAiAAY+WbgAAEVYuAAOLxu5AA4ABD5ZuAAARVi4ABIvG7kAEgAEPlm4AABFWLgAFi8buQAWAAQ+WbgAAEVYuAAaLxu5ABoABD5ZugAPABQAAyu6AAkACgADK7gAAhC4AAHcuAACELgABNy4AAIQuAAH0LgAFhC4AAzcuAAN0LgAENC4ABHQuAAPELgAF9C4ABQQuAAY0LgADxC4ABvQuAARELgAHNC4AB3QuAAKELgAHtC4AAkQuAAg0LgAAhC4ACPQuAABELgAJNAwMQEzFTMVIzUjFTMVIRUzFTM1MxUjFSE1IxUjNTM1MzUjNTM1MzUBkMhkZMjI/tRkyGRk/tTIZGRkZMhkAlhkZGTIZMhkZGRkZGRkZMhkyGQAAAAABAAA/zgDIAJYABQAHwA0ADkCwLsADgABAA8ABCu7AAIAAQAVAAQruAAOELkADAAB9LgAANC4AAIQuQADAAH0uQAFAAH0uAADELgAB9C4AAQQuAAI0LgAAhC4AAnQuAAMELgAGtC4ABfQuAAL0LgADhC4ABHQuAANELgAEtC4AAwQuAAT0LgAFxC4ABTQuAAMELgAFtC4ABYvuAAOELgAGNC4ABgvuAANELgAGdC4ABcQuAAb0LgADBC5AB0AAfS4ABUQuAAe0LgAAhC4ACDQuAAVELgAIdC4AB0QuAAj0LgADBC5ACUAAfS4ABUQuAAn0LgAAhC4ACnQuAAVELgAK9C4AB0QuAAt0LgAAhC4AC/QuAADELgAMdC4AAQQuAAy0LgAAhC4ADPQuAAdELgANdC4AAwQuAA20LgAFxC4ADfQuAAdELgAONC4ADgvALgAAEVYuAACLxu5AAIABj5ZuAAARVi4ABIvG7kAEgAGPlm4AABFWLgAFS8buQAVAAY+WbgAAEVYuAAILxu5AAgABD5ZuAAARVi4AAwvG7kADAAEPlm4AABFWLgALi8buQAuAAQ+WbgAAEVYuAAHLxu5AAcAAj5ZugAJAAoAAyu4AAIQuAAB3LgAAhC4AATcuAAQ0LgAEdC4ABfQuAAF0LgACBC4AAbcuAAJELgADdC4AAYQuAAO0LgAD9C4AAIQuAAT0LgAARC4ABTQuAACELgAFtC4ABcQuAAY0LgABxC4ABncuAAXELgAG9y4ABrcuAAYELgAHdC4AB7QuAACELgAH9C4AB4QuAAg0LgAIdC4ABsQuAAi0LgAGRC4ACbQuAAn0LgAKtC4ACvQuAA10LgAJNy4ACjQuAAPELgALNC4AC3QuAAJELgAL9C4AC0QuAAw0LgAMdC4ABsQuAAy0LgAIRC4ADTQuAA1ELgANtC4ADEQuAA30LgAONC4ADYQuAA50DAxEyEVMxUzESMVIxUhNSM1IxEzNTM1BSEXIwMzNTM1MzUXIxUjFTMVMzUzFSMVIxUhNTMRIzUBIxUzN8gBkGRkZGT+cGRkZGQBLP7TAWMBZGTIZGTIZGRkZMgBLGRk/tRkYwECWGRk/nBkZGRkAZBkZGRk/tTIZGRkZGRkZGRkZGQBLGT+1GRkAAACAMj/nAGQAlgACAAPAKK7AAQAAQAFAAQruAAEELgAANC4AAQQuQABAAH0uAAEELgAB9C4AAUQuAAJ0LgAARC4AArQuAAEELgADNC4AAAQuAAN0LgABRC4AA7QALgAAC+4AABFWLgABi8buQAGAAY+WbgAAEVYuAANLxu5AA0ABD5ZuAAARVi4AAsvG7kACwACPlm4AAYQuAAE3LgADRC4AAncuAALELgACty4AA/QMDEBMxEjNSM1MzUDMxUjFSM1ASxkZGRkZMhkZAJY/nDIZGT+DGRkyAAAAAAAAAAAAAAAgAFUAkwDyATYBRgFrgZiBrgHAAdaB3IHlAg2CR4JWgpECxoLuAycDbQOMg9gEGgQqBEiEcAR6BKGE1oUqBVaFjAW9BeyGCIYgBlgGeQaHhqYG4Ib6BzGHZgegB8qIEwhSCIqIsAjNCPEJG4loiZgJyQnWCf6KCoozCjkKcoqhisyK/osui04LggumC7OL0QwDDA6MNYxYDIyMxY0EDTsNdg2bDcSN9o4pjn4OpY7cDvQO/Q8TDzMPdg/hj/yAAAAFwEaAAEAAAAAAAAAHAAAAAEAAAAAAAEACwAcAAEAAAAAAAIABwAnAAEAAAAAAAMAJgAuAAEAAAAAAAQAEwBUAAEAAAAAAAUADQBnAAEAAAAAAAYAEgB0AAEAAAAAAAgADACGAAEAAAAAAAkADACSAAEAAAAAAAsAFACeAAEAAAAAAAwAEwCyAAEAAAAAABIAEwDFAAMAAQQJAAAAOADYAAMAAQQJAAEAFgEQAAMAAQQJAAIADgEmAAMAAQQJAAMATAE0AAMAAQQJAAQAJgGAAAMAAQQJAAUAGgGmAAMAAQQJAAYAJAHAAAMAAQQJAAgAGAHkAAMAAQQJAAkAGAH8AAMAAQQJAAsAKAIUAAMAAQQJAAwAJgI8Q29weXJpZ2h0IDIwMTkgRGFtaWVuIEd1YXJkLlNjcmliZSBFaXJlUmVndWxhckRhbWllbkd1YXJkOiBTY3JpYmUgRWlyZSBSZWd1bGFyOiAyMDE5U2NyaWJlIEVpcmUgUmVndWxhclZlcnNpb24gMS4wMDBTY3JpYmVFaXJlLVJlZ3VsYXJEYW1pZW4gR3VhcmREYW1pZW4gR3VhcmRodHRwczovL2Vudnl0ZWNoLmNvbWh0dHBzOi8vZGFtaWVuZy5jb21TY3JpYmUgRWlyZSBSZWd1bGFyAEMAbwBwAHkAcgBpAGcAaAB0ACAAMgAwADEAOQAgAEQAYQBtAGkAZQBuACAARwB1AGEAcgBkAC4AUwBjAHIAaQBiAGUAIABFAGkAcgBlAFIAZQBnAHUAbABhAHIARABhAG0AaQBlAG4ARwB1AGEAcgBkADoAIABTAGMAcgBpAGIAZQAgAEUAaQByAGUAIABSAGUAZwB1AGwAYQByADoAIAAyADAAMQA5AFMAYwByAGkAYgBlACAARQBpAHIAZQAgAFIAZQBnAHUAbABhAHIAVgBlAHIAcwBpAG8AbgAgADEALgAwADAAMABTAGMAcgBpAGIAZQBFAGkAcgBlAC0AUgBlAGcAdQBsAGEAcgBEAGEAbQBpAGUAbgAgAEcAdQBhAHIAZABEAGEAbQBpAGUAbgAgAEcAdQBhAHIAZABoAHQAdABwAHMAOgAvAC8AZQBuAHYAeQB0AGUAYwBoAC4AYwBvAG0AaAB0AHQAcABzADoALwAvAGQAYQBtAGkAZQBuAGcALgBjAG8AbQACAAAAAAAA/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.30.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.30.5. Google Fonts
Support for Google fonts will be added soon.
3.31. 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.32. 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.33. Reporting Bugs
If you have a bug to report regarding adventuron, please report here (github account required).
3.34. 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.34.1. clear
We can clear down a collection using the standard 'clear' command.
: clear "my_list_1";
3.34.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 { values = [ 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.34.3. count
Counts the number of elements in a collection.
Note
|
Count can be used to count other lists or sets of things in Adventuron also, not just user-defined collections. |
: if (count "my_list" ) > 0) { : print "There is more than one item in the list"; }
3.34.4. collection_intersect
start_at = my_location locations { my_location : location "You are in a room." ; } collections { my_list_1 : list values = [ dog, cat, poodle ] ; my_list_2 : list values = [ 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 } : iterate "my_list_3" { : print (item()); } : press_any_key ; }
3.34.5. iterate
start_at = my_location locations { my_location : location "You are in a room." ; } collections { my_list : list { values = [ 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. : iterate "my_list" { : print (item()); } : press_any_key ; }
3.34.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" item -> ("one") } : collection_push { collection = "my_list" item -> ("two") } : collection_push { collection = "my_list" item -> ("three") } : collection_push { collection = "my_list" item -> ("four") } : collection_push { collection = "my_list" item -> ("five") } : collection_modify { collection = "my_list" index -> (0) item -> ("ONE") } : collection_modify { collection = "my_list" index -> (2) item -> ("THREE") } : iterate "my_list" { : print (item()); } : press_any_key ; }
3.34.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" item -> ("one") } : collection_push { collection = "my_list" item -> ("two") } : collection_push { collection = "my_list" item -> ("three") } : collection_push { collection = "my_list" item -> ("four") } : collection_push { collection = "my_list" item -> ("five") } : iterate "my_list" { : print (item()); } : press_any_key ; }
3.34.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" item -> ("one") } : collection_push { collection = "my_list" item -> ("two") } : collection_push { collection = "my_list" item -> ("three") } : collection_push { collection = "my_list" item -> ("four") } : collection_push { collection = "my_list" item -> ("five") } : 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.34.9. collection_remove
Removing items by index:
start_at = my_location locations { my_location : location "You are in a room." ; } collections { my_list : list { values = [ 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 ; }
Removing Specific Values:
start_at = my_location locations { my_location : location "You are in a room."; } collections { list_1 : list { items = [ a,b,c,d ] } } on_startup { : collection_remove collection ="list_1" item ="c"; : print ( construct_string { from ="list_1" } ); : press_any_key ; }
3.34.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" ; : iterate "my_list" { : print (item()); } : press_any_key ; }
3.34.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 } : iterate "my_list_3" { : print (item()); } : clear "my_list_1"; : press_any_key ; }
3.34.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 } : iterate "my_list_3" { : print (item()); } : press_any_key ; }
3.34.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.35. 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. prompt_prefix = What Now? prompt = >> question_prompt_char = ? 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.36. 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", "graphics" |
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.37. Links / Contact Info
Documentation + Videos
Games
-
List of games made with Adventuron (non exhaustive).
Chatroom
-
If you want instant support, please use the Adventuron Discord Server.
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.
-
Adventuron Cavejam 2019 - Remix The Cave of Magic.
-
Adventuron Halloween Jam - Make a Spooky Game.
-
Treasure Hunt Jam - Make a text only 'treasure hunt' style game with limited word use.
-
The Next Adventure Jam - Make a game with graphics using a bright vibrant palette.
-
An Adventuron Christmas Jam - Make a game with the theme of "Christmas". Ran Nov 17th to Dec 21st, 2020.
-
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
-
The Text Adventure Literacy Project by Chris Ainsley.
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
-
Interview With Chris Ainsley, Creator of Adventuron Classroom
-
The Classic Adventurer Magazine by Mark Hardisty (Adventuron interview in issue 5).
-
(Audio) Adventure Games Podcast (Adventuron Interview).
-
(Audio) Retro Hour Podcast Episode 238 (Text Adventure History / Adventuron).
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 :
-
http://multipaint.kameli.net (useful for ZX Spectrum, C64, retro compliant images).
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.
-
Email: info@adventuron.io
-
Twitter - @LearnAdventuron.
3.38. Cookbook (Advanced Users Only)
Click here to see a collection of code snippets.
3.39. Migration Guide
3.39.1. Migrating from Beta 68j to Beta 72
-
Convert {( )} syntax to ( ) syntax.
e.g.
// Beta 68j : print {( "Hello World " + vara )} // Beta 72 : print ( "Hello World " + vara );
-
'collection_clear' becomes 'clear'.
// Beta 68j : collection_clear "my_list"; // Beta 72 : clear "my_list";
-
'conspicuous' becomes 'listed'
// Beta 68j rope : object "a rope" at = "my_location" conspicuous = "false" ; // Beta 72 rope : object "a rope" at = "my_location" listed = "false" ;
-
'experimental_scan' and 'collection_iterate' become 'iterate'
// Beta 68j : collection_iterate "my_list" { : print {( item() )} } // Beta 72 : iterate "my_list" { : print ( item() ) ; } // Beta 68j : experimental_scan "current_location" { : print ( item() ) ; } // Beta 72 -- note that old scan categories start with underscore now, see 'iterate' // section for more iteration categories : iterate "_current_location" { : print ( item() ) ; }
-
Remove experimental_is_theme_
// Beta 68j : if (experimental_is_theme_displaying_border()) { } // Beta 72 : if (sysvar_bool "sysvar_displaying_border") { }
-
'prior_prompt' becomes 'prompt_prefix'
system_properties { // Beta 68j prior_prompt = What now? // Beta 72 prompt_prefix = What now? }
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. |
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):
-
Hide (or disable) the prompt.
-
Describe the location
-
Run the on_describe {} block
-
Run the on_tick {} block.
-
Update some system settings.
-
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 - 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
-
List of games made with Adventuron (non exhaustive).
Chatroom
-
If you want instant support, please use the Adventuron Discord Server.
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.
-
Adventuron Cavejam 2019 - Remix The Cave of Magic.
-
Adventuron Halloween Jam - Make a Spooky Game.
-
Treasure Hunt Jam - Make a text only 'treasure hunt' style game with limited word use.
-
The Next Adventure Jam - Make a game with graphics using a bright vibrant palette.
-
An Adventuron Christmas Jam - Make a game with the theme of "Christmas". Ran Nov 17th to Dec 21st, 2020.
-
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
-
The Text Adventure Literacy Project by Chris Ainsley.
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
-
Interview With Chris Ainsley, Creator of Adventuron Classroom
-
The Classic Adventurer Magazine by Mark Hardisty (Adventuron interview in issue 5).
-
(Audio) Adventure Games Podcast (Adventuron Interview).
-
(Audio) Retro Hour Podcast Episode 238 (Text Adventure History / Adventuron).
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 :
-
http://multipaint.kameli.net (useful for ZX Spectrum, C64, retro compliant images).
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.
-
Email: info@adventuron.io
-
Twitter - @LearnAdventuron.