1. Introduction

classr

Adventuron Classroom a fun way to learn to code for kids aged 8 - 12, working with a trusted adult.

Please watch the introduction video in fullscreen mode to learn more …​

1.1. Adventuron

introduction

Adventuron Classroom is the basic version of Adventuron.

Classroom first introduces "adventure" games then demonstrates how to build such a game.

Games made with Classroom are playable on PCs, tablets, mobile phones, and more.

1.2. Lesson Structure

birwood 1

The plan for this course is as follows:

  1. Learn How To Play A Text Adventure Game. (approximately 30 minutes).

  2. How To Use The Keyboard. (approximately 30-45 minutes, skippable).

  3. How To Code A Game. (approximately 3 - 4 hours, progress is saved).

  4. Make Your Own Game. (after the course is finished).

1.3. About Text Adventures

vamp

A text adventure game is a type of game in which the player types (or speaks) commands to the computer and the computer tells you the result of your command.

Text adventures can be pure text, or they might have graphics too to show the player where they are in the fantasy world.

1.4. About Excalibur

In this tutorial, we will learn how to code a text adventure with graphics.

The adventure game we will use as the focus of the coding portion of the lessons is "Excalibur: Sword of Kings".

Excalibur: Sword of Kings, was written in 1987, by Ian Smith & Shaun McClure.

excalzx lady
Figure 1. Excalibur (1987)

Excalibur, Sword of Kings is copyright of Adventuron Software Limited, all rights reserved.

2. Tutorial

2.1. The Game Design

demon knight

There are five things to think about when creating a simple text adventure game.

2.1.1. 1 - Story

Most adventure games revolve around a goal, and some reason for trying to achieve the goal.

The story may be very complicated, almost like a book, or it could be very simple, such as in Excalibur.

2.1.2. 2 - Locations

Locations are places that the player can be inside the game.

Each location has its own sentences to describe itself, and in Excalibur, every location has a picture (graphic).

2.1.3. 3 - Map

The map of a game that describes how the locations are connected together.

2.1.4. 4 - Objects

A game usually has a series of things in it (or objects). A thing can be an object like an apple, or a thing might even be a person. Adventuron calls all these things "objects".

The player can take objects, drop object, and use objects. The game remembers what the player has, and where every object is, even if the player doesn’t have it yet.

2.1.5. 5 - Puzzles

The puzzles of a game describe things that must be solved to make progress in a game.

Usually a part of the game is blocked until a puzzle is solved, then after the player is allowed in the new part of the game, new puzzles are revealed.

2.2. Story

castle smaller

The story of Excalibur: Sword of Kings, is that Arthur has been taken prisoner by the evil sorceress Crania and it’s up to you, a knight of the round table, to find Excalibur, defeat the sorceress, and rescue King Arthur.

2.3. Locations

winch room

There are 4 different areas in Excalibur.

  1. The Road Area.

  2. The Forest of Birwood.

  3. Camelot Castle.

  4. The Salt Mines.

Each area has several locations.

Locations can be indoors (like a room), or outdoors, like in a forest.

Excalibur also shows the player a simple picture (like the one at the top of this section) when describing the location to the player.

We will learn how to add graphics in this course, but not how to draw them.

You can double click in the documentation panel to make the documentation full screen, you can double click again to minimise back to just showing in the left hand column.

Here is a list of all the locations (and the graphics we will add to the game later):

(Locations with two images are places where the contents of the location can change due to solving a puzzle)

Location Graphic Description

hut

hut

You are in a ramshackled hut. Golden sunlight filters through an open doorway to the north.

road 1

road 1

You are standing on a grass bordered track. A hut lies to the south.

road 2

road 2

You are where the road twists eastwards. Small hills around the road are crowned with vibrant red Hawthornes.

road 3

road 3

You are on a rutted gritty track that is flanked by lush pasture. A small clump of trees can be seen on a hill in the distance.

road 4

road 4

You are on a dusty path skirting the edge of Birwood. The faint whisper of foliage can be heard from afar.

lamp seller on road

lamp seller on road after buy lamp

You are where the path branches to the east and continues south towards a chasm.

chasm

chasm

You are stood on the edge of a huge chasm. A tightrope spans the gap, but it looks dangerous.

edge of birwood

birwood

You are on the edge of Birwood. A rope spans a chasm northwards.

deep inside birwood

birwood

You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.

birwood bush

birwood bush

You are stood on the mossy floor below the canopy of leaves which lets a wan light filter through.

demon knight road

demon knight road demon knight cleared road

You are in a dip in the road by dark Birwood. Ravens stark cries can be heard from above.

foot of tree

foot of tree foot of tree with ladder

You are at the foot of a large stone tree that is bare of any branches. The road ends here.

top of tree

top of tree

You are in a stone room set in a large petrified tree. Thick dust carpets the floor.

castle approach_1

castle approach 1

You are now a fair distance from Birwood. The denizens of the countryside make the only sound here. You can see castle Camelot on the eastern horizon.

castle approach 2

castle approach 2 castle door open

You are outside a now foreboding looking Camelot. Its once proud standards now whipped and torn by the winds. A great stone door is the only way in.

castle porch

castle porch

You are in the porch of Camelot. Long dark shadows are cast here, playing tricks with your eyes.

banquet hall

banquet hall

You are in an abandoned banquet hall. Furniture lays broken on the floor.

drafty room

drafty trapdoor close smashed trapdoor

You are in a drafty room. Wind blows through gaps in the mortar creating howling noises.

ornate antechamber

ornate antechamber

You are in an ornate antechamber that is mantled in thin ice, that even covers the paintings.

portcullis

portcullis downportcullis up

You are in a small dingy room which has an iron portcullis set into the northern wall.

salt mine 1

salt mine

You are in an old salt mine. Stygian tunnels lead off to the west and south.

salt mine 2

salt mine

You are in the west part of the mine/ It looks like it’s been over worked and abandoned.

salt mine 3

salt mine

You are at the end of the mine. You can hear the drip of water.

worm room

worm roomsalt mine

You are in the south part of the mine. There been recent movement in the rocks near your feet.

cold room

cold room cold room clear

You are in a bitterly cold room. Everything is coated in a thick layer of ice. Dense icicles show a weird tapestry of frost on the ceiling.

winch room

winch room

You are in the winch room. A huge turning mechanism stands in the corner.

armoury

armoury

You are in the armoury. Cobwebs hang like drapes. Empty weapon racks line the walls.

most splendid room

most splendid room most splendid room clear

You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.

arthur

arthur

You are in a sparse and lonely room. A chill wind enters through the high window.

game over screen

game over

NOTE :: This is not a room, just a graphic.

ending screen

ending screen

NOTE :: This is not a room, just a graphic.

2.4. Map

portcullis

A map is a drawing that shows locations in the game, and how they are connected together.

There are four main directions (called compass directions):

compass 1

A map can be drawn as one big drawing, or may be split up into different pieces.

The map of Excalibur is in two parts:

2.5. Part 1 (Outside The Castle)

map 1

2.6. Part 2 (Inside The Castle)

map 2

2.7. Reading The Maps

A map is a visual way of seeing connections, but we can also turn these connections into words.

Here is how to read the map, using the compass directions as our guide:

  • We can say that road 1 is NORTH of the hut.

  • We can say the the hut is SOUTH of road 1.

  • We can say that demon knight is EAST of lamp seller.

  • We can say that lamp seller is WEST of the demon knight.

2.8. Up and Down

Up and down on maps tend to be treated the same way as north or south, but up and down always needs to be labelled.

2.9. Puzzles

castle approach 2

2.9.1. Puzzles

Excalibur is a short game with just 13 puzzles, most easy to solve. The fun of the adventure is exploring, seeing new graphics, and working out how to solve puzzles.

Not all the answers are obvious. Each object will give a clue if the player types "examine xxxxx" where xxxxx is the name of something.

This adventure is simple for the purpose of the tutorial, and usually (puzzle type) text adventure games have many more puzzles than this one.

It is strongly recommended that you play the game before you read onwards, as spoilers for all the puzzles will follow. The link below has a built in tutorial to help you understand how to play the game.

Click Here to play Excalibur (will open in new window).

Puzzle Description

Climbing The Tree

The player will encounter a tree that has no branches and cannot be climbed.

The player needs to collect the ladder from the start location, and type lean ladder or stand ladder at the base of the tree, and then the player can navigate "up" to reach the stone room inside the top of the tree.

At the top of the tree, is the short sword.

Crossing The Chasm

The player encounters a gorge. The gorge has a tightrope, but it looks dangerous. If the player types "cross gorge" then they will fall and the game will end.


To solve the puzzle the player must break ladder to make a pole, and then once the player is holding the pole, type cross chasm, and the game will inform the player that they use the pole to balance, and they can make their way across the gorge and into the forest.

If the player breaks the ladder before climbing the tree, then the game is not winnable.

Treasure In The Forest

In the forest, the player must examine (or search) two items in the forest. e xamine logs will find an axe, and examine bush will find the stone key.

Crossing The Chasm Again

Making sure they are still holding the pole (from the broken ladder), the player must type cross chasm again to return to the road network.

Getting Past the Demon Knight

The player must type attack knight (or similar), when holding the short sword in order to defeat the knight in battle.


The knight was blocking the road to camelot, so if the player didn’t solve the tree puzzle, and the knight puzzle, then the player cannot reach the entrance of Camelot.

Opening The Gate

At the front gate of camelot, whilst holding the stone key, the player must type unlock door, then open door. This will allow the player to enter camelot.

Buying The Lamp

Inside the castle there is a coin, and the coin must be picked up, and the player must go back outside the castle to buy lamp from the old woman that is selling lamps.

The Trapdoor

Inside the castle, there is an old trapdoor.

Whilst holding the axe, the player should type smash trapdoor or break trapdoor and the trapdoor will be replaced with a broken trapdoor message, and the player should be able to type "down" to enter the salt mines (beneath the castle).

The Rockworm

Inside the salt mines, there is a creature called a rockworm, which is blocking the way further into the mines. If the player tries to go past the room, the player will be attacked and the game will end.


To remove the rockworm, light lamp. Once past the rockworm, go further into the mines and take the salt. Some string is also in the mines, but it serves no purpose.

Getting Past The Ice Creature

In another part of the castle, there is an ice creature, blocking a doorway. throw salt at ice creature to melt it.

Once past the rock creature, get oil, and get excalibur (the legendary sword) from the armoury room.

Opening The Portcullis

There is one part of the castle that is blocked now, it is a room with a closed portcullis (gate). We should now be holding the oil and excalibur. Inside the winch room, there is a winch but it is rusty.


Type oil winch, then type turn winch, doing so will raise the portcullis (open the gate).

The Sorceress

In the room on the other side of the portcullis we see the sorceress Crania, and she has cast a spell at the player.


If the player is holding excalibur, they should type reflect spell or deflect spell and it will bounce the spell using excalibur and make the sorceress vanish.

King Arthur

Now we have access to one more room of the castle, and in this room, King Arthur is prisoner, and is asleep. Type wake arthur, and the game is won.

2.10. Objects

drafty room

2.11. Objects & Scenery

The game features a variety of objects and scenery, some of which have a use, some of which do not. The player must figure out how to interact with objects in the game.

Any items of interest in the game is referred to as an "object", even people. Usually, players can pick up objects, but some "objects" are marked as immovable, and cannot be collected.

2.11.1. Objects (Things we can pick up or use)

Identifier Description Found At Notes

ladder

a ladder

hut

Used to climb tree (by leaning it), then must be broken to create a pole with which to cross the chasm.

red_fish

a red fish

road_3

Not Useful

short_sword

a short sword

top_of_tree

Used to defeat the Demon Knight.

coin

a coin

ornate_antechamber

Used to purchase lamp from old lady.

string

some string

salt_mine_2

Not Useful

salt

some salt

salt_mine_3

Used to melt ice creature.

oil

can of oil

cold_room

Used to oil the winch, so it can be turned to open the portcullis.

excalibur

Excalibur!

armoury

Used to reflect incoming spell from Crania.

long_pole

a long pole

-

Created by breaking ladder. Required to cross chasm.

rungs

some rungs

-

Created by breaking ladder. Not Useful.

stone_key

a stone key

-

Created by examining bush. Used to open door of camelot castle.

axe

a wood cutters' axe

-

Created by examining logs. Used to smash trapdoor, so we can enter the salt mines.

lamp

a lamp

-

Created by buying lamp (with coin) from old lady. Used to frighten away the rockworm (by lighting lamp).

Scenery (Things we can’t pick up)
Object Name Description Initial Location Notes

old_woman

an old woman selling lamps

lamp_seller_on_road

Disappears after buying lamp with coin.

logs

a pile of logs

deep_inside_birwood

Must be examined to find the woodcutters' axe.

bush

a bush

birwood_bush

Must be examined to find the stone key.

demon_knight

a Demon Knight guarding the east road

demon_knight_road

Blocks the road to camelot. Must be attacked once holding the short sword. Disappears after attacked.

trapdoor

an old trapdoor

drafty_room

Blocks the entrace to the salt mines. Smashed with axe. After smashing, trapdoor is removed and replaced with smashed trapdoor.

smashed_trapdoor

a smashed trapdoor

-

Smashed trapdoor is created when the non-smashed trapdoor is smashed when carrying the woodcutters' axe.

rockworm

a Rockworm, guarding the south tunnel

worm_room

Blocks the path further into the salt mines. Must be scared away by lighting lamp.

ice_creature

an Ice Creature, guarding the north exit

cold_room

Blocks the entrance to the winch room and armoury, must be melted by throwing ice at it. When melted, ice creature is removed from the game.

winch

a winch

winch_room

Must be oiled, then turned to open the portcullis in the portcullis room.

spell

a spell flying at you from Crania

most_splendid_room

Must be deflected or reflected using excalibur. Once spell is reflected or deflected, then Crania (and spell) are removed from the game.

asleep_arthur

King Arthur (asleep)

arthur (arthur is the room identifier)

Arthur must be woken to win the game.

3. Using The Keyboard

3.1. Coding And The Keyboard

Feel free to skip this chapter for now if you are familiar with the keyboard, or just wish to start the coding section.

You can skip the chapter by clicking the up arrow above this text, and then just scroll down to the next chapter in the lesson list.

keyboard

Adventuron is a code based system and requires that game-makers are able to use a keyboard and mouse / touchpad.

If it’s your first time to type a large document on a keyboard, don’t worry - practise makes perfect

3.2. Moving The Cursor

We will now practise using the keyboard.

Step 1 - Select "Keyboard Practise" from the menu at the bottom right of the middle panel (the editor window). Make sure there is a tick next to the "Keyboard Practise" menu option.

Step 2 - Click inside the text editor window you the left mouse button.

006b

Step 3 - After selected the keyboard practise mode, type in the following text:

006c

If you have never used a keyboard before this might be hard at first, so ask an adult for help in finding the right buttons to press if you get lost.

3.3. Selecting Text

3.4. Selecting text with the cursor keys, holding the SHIFT key

Holding the SHIFT button whist tapping a cursor will "select" text (light it up).

The SHIFT key is the key to the left of the "Z" key on the keyboard.

cursor select

3.5. Selecting text, by holding left mouse button then moving mouse

We can also select text by moving the mouse to the start of an area, holding the left mouse button, moving it until the text is selected then letting go.

mouse select

3.6. Deleting Text

3.7. Deleting Text

backspace

The backspace button is usually above the ENTER button and next to the + and - buttons. The image above shows the key on a typical keyboard.

This may not match your keyboard layout exactly.

If we press the BACKSPACE button when text is selected, all the text we selected will disappear.

select and backspace

3.8. Select All, Cut,Copy & Paste

3.9. The Control / Command Button

The Control button is usually the bottom left key on Linux, Windows and Chromebook keyboards. Some keyboards may have this button in a slightly different place, so please look at your own keyboard to find where it is.

keyboard

3.10. Information For Apple Computer Users

This course will refer to the special button as the Control button, but on Apple branded home computers, the COMMAND button should be used instead of the CONTROL button for all shortcuts that use the CONTROL button.

3.11. Select All

Hold the CONTROL button and then tap the A button to select all text in the editor.

select all

3.12. Copy Paste

Select some text (using cursor keys + shift or mouse drag), then hold the CONTROL button and then tap the C button to make an in-memory copy of the selected text (copy). Then press CONTROL and V to place the copy of the text that was copied where the cursor is.

copy paste

3.13. Cut Paste

Select some text (using cursor keys + shift or mouse drag), then hold the CONTROL button and then tap the X button to make an in-memory copy of the selected text, and also to delete the selection from the document (cut).

Then press CONTROL and V to place the copy of the deleted text that was copied where the cursor is. Cut and paste is extremely useful for moving text around quickly.

cut paste

3.14. Undo

Hold the CONTROL button and then tap the Z button to undo the last action you performed, this can work more than once. This is very handy if you press something wrong, or type something wrong. Remember, it’s very normal to get things wrong, in fact, that’s the reason that undo is there.

undo

3.15. Saving

3.16. Saving

There are two ways to save in Adventuron.

  1. You can press CONTROL + S on the keyboard together.

  2. Or you can click the play icon (picture) on the top bar. It looks like a triangle pointing right.

play icon
Figure 2. Save game then start game.

If you can’t remember all of these it’s OK. You will reminded when and how you can save.

3.17. Privacy Modes & Save Files

Adventuron stores your files in the browser. If you close the browser tab, it will remember the file you were working on.

If you use Adventuron Classroom in 'incognito' or private browsing mode, then your work will be lost when you close the Window as nothing is currently stored on the Adventuron website server.

3.18. Other Keys

Feel free to skip this section if you wish, but more useful keyboard commands are included here.

3.19. Page Up & Page Down

We can use the PAGE UP and PAGE DOWN buttons to move the cursor up and down the screen, very quickly. The mouse wheel can also be used to page up and page down.

3.19.1. (Page Up/Down on Chromebooks )

On some Chromebooks, page up and page down buttons do not exist. You can press CONTROL + SHIFT + CURSOR UP / DOWN buttons to move through the text one page at a time.

3.20. Redo (Control + Y)

Hold the CONTROL button and the Y button to redo something you already undid. There is no image for this description, as it’s difficult to demonstrate visually. Try it out thout straight after an undo.

3.21. Finding Text (Control + F)

Sometimes you might want to find some text in Adventuron. To do this, press CONTROL + F together, and then type the letters of the word you are looking for.

3.22. Underscore (_)

A very important key is the underscore character:

_

The underscore character is used a lot in Adventuron. To type it, you need to press the button to the right of the '0' key on the keyboard, whilst pressing SHIFT.

3.23. Colon (:)

Another very important key is the colon character:

:

The colon character is used a lot in adventuron. To type it, you need to press the button to the right of the 'L' key on the keyboard, whilst pressing SHIFT.

3.24. Double Quote (")

Another very important key is the double quote character:

"

The double quote character is used a lot in adventuron. To type it, you need look at your keyboard for where it is, and press it whilst pressing SHIFT. (this key in a different place depening on your keyboard type).

There are more advanced things you can do with the keyboard, and they are all very fun, but that’s enough for now.

3.25. Typing special characters (British Keyboard)

Keyboards are different in different parts of the world, so this guide is only for people with British keyboards.

Here are the characters that require the shift button on a British keyboard.

Special character How to type

!

Hold Shift & Press 1

"

Hold Shift & Press 2

£

Hold Shift & Press 3

$

Hold Shift & Press 4

%

Hold Shift & Press 5

^

Hold Shift & Press 6

&

Hold Shift & Press 7

*

Hold Shift & Press 8

(

Hold Shift & Press 9

)

Hold Shift & Press 0

_ (underscore)

Hold Shift & Press -

+

Hold Shift & Press =

~

Hold Shift & Press #

:

Hold Shift & Press ;

{

Hold Shift & Press [

}

Hold Shift & Press ]

<

Hold Shift & Press ,

>

Hold Shift & Press .

?

Hold Shift & Press /

4. Starting To Code

4.1. Getting Started With Autocompletion

Before we can start to code, we need to clear the editor window of all text and switch off keyboard practise mode (if it is enabled).

To do this, click the "Menu" button, and select "Start Coding (Clear All Text)" option.

See the animation below:

new 004b

4.2. Creating The First Location

Now let’s type-in the first location in Excalibur.

Each location requires an ID part and a DESCRIPTION part.

In Adventuron the ID is the part of a line of code BEFORE the : letter. The DESCRIPTION is surrounded by the double-quote " characters.

this_is_the_id : location "This is the description" ;

IDs cannot contain spaces but can contain underscores.

We will change the first location to have an ID of hut, type in the description of the first location, and set the start location of the game to the id of the hut location.

002

4.3. Testing The Game

To test the game, either press CONTROL + S, or click the "save" button at the top of the window.

play icon

It doesn’t do much yet, but Adventuron is at least describing our first location.

003

Code so far …​

########################################
#  Adventuron                          #
########################################

start_at      = hut

########################################
#  Locations                           #
########################################

locations {

   hut    : location "You are in an old hut. Sunlight shines in from a doorway to the north." ;

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [

   ]

}

########################################
#  Objects                             #
########################################

objects {

}

4.4. Connecting Locations Together

4.5. Compass Directions

new compass

4.6. Connection Our 3 Locations Together

In the tutorial game, the hut has an exit north to road_1, and road_1 has an exit north to road_2. We can put this in a table to make it nice and clear.

map a
  1. A box that is above another box is NORTH of that box.

  2. A box that is below another box is SOUTH of that box.

  3. A box that is left of another box is WEST of that box.

  4. A box that is right of another box is EAST of that box.

We connect locations together using the connections table.

From Location Direction To Location

Hut

North

Road 1

Road 1

North

Road 2

Adventuron automatically knows that if road 1 is north of the hut, that the hut is south of road 1, so you don’t need to create connections in each direction.

4050 1

Placing your cursor on a blank line in the middle the connections block, and press CONTROL + SPACE.

The first item to be suggested will be a location identifier. This is the from location.

4050 2

Select "hut" as the from location, by using the cursor (arrow) keys on the keyboard, then press the ENTER button. You can move up or down the selected options with the CURSOR KEYS, or you can use the mouse to click the option you want.

After you select hut, Adventuron will write "hut," (hut followed by comma).

The middle section header colour will be red and read "Attention required on line xx" (xx is a number), because connections require 3 items per line.

Until we add all three items on a line, Adventuron will not be very happy. It likes everything to be very tidy.

Next, press CONTROL + SPACE again. This is now the direction column, again use the cursor (arrow) keys to select NORTH, then press the ENTER button.

4050 3

The line should now read "hut, north, " and your cursor (the flashy part) should be at the end of the line.

4050 4

The window should be reporting there is a validation problem. This is because it is waiting for the 3rd entry on the line. The third entry should be the "road_1".

Press "r" then press CONTROL + SPACE, and we will be presented with an option for road_1 and road_2.

4050 5

Select road_1, then press enter.

4050 6

Typing the first few letters of something you are looking for before pressing CONTROL + SPACE will only show options containing the letters you typed. Typing the first few letters of things you know about can really speed up AUTOCOMPLETION.

4.7. And Again

Now we go to a new line, and repeat the process but for "road_1, north, road_2".

006

Now …​ Click the PLAY button …​.

play icon

Now use the right hand side of the screen to explore these three locations. Adventuron will display the connections between our locations.

007

South is the opposite direction as north, so we can type "n" (short for north) to move up the map, and "s" (short for south) to move down the map.

If we try to go in a direction without a connection, Adventuron will tell inform us that we cannot go that way.

We can also click on the directions with a mouse click to go in that direction.

Here is the code so far

########################################
#  Adventuron                          #
########################################

start_at      = hut

########################################
#  Locations                           #
########################################

locations {

   hut    : location "You are in an old hut. Sunlight shines in from a doorway to the north." ;
   road_1 : location "You are standing on a track. The hut is south." ;
   road_2 : location "You are where the road turns eastwards. You see small hills in the distance." ;

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,    north, road_1,
      road_1, north, road_2,
   ]

}

########################################
#  Objects                              #
########################################

objects {

}

4.8. Adding an object

lamp

In Adventuron, objects are a type of things that exists in the game world.

The first object in the game, in the first location (the hut) in fact, is the ladder.

Adventuron supports different types of objects, but the ladder is just a normal type of object (can be picked up and put down), so we create it as an object.

To create the ladder object, we move the cursor (using the mouse or the cursor keys) to an empty line inside the objects {} code block.

4100 1

We then press CONTROL + SPACE, and just like creating a new location, we type the name of the object id (or nickname), then we press the TAB button (usually left of the letter Q) to move to the area between the " letters, then type the description of the object.

008

Articles

The part between the '"' characters, is usually prefixed by the "article" which is a word like "the" or "some" or "a" or "an".

If you don’t know what an article is, or which one to use, ask a teacher or a trusted grown up.

If you don’t know what to do, just write the name of the object by itself.

Placing The Ladder In The Hut

Now we have defined what a ladder is, but we need to place the ladder in the hut.

We want to put the ladder in the hut, so we need to find a bit of space in the objects line. The place where you find space is usually before the ";" character.

Move your cursor just before the ";" character, and press CONTROL + SPACE:

4100 2

Once there, now type "sta", this will narrow down the set of options to options that contain "sta".

After selecting "start_at" from the list, now we have to choose the start location for the ladder.

4100 3

When your cursor is between the "" characters, press CONTROL + SPACE again !

4100 4

Now we can choose which location in which we wish to create the ladder.

4100 5

Select "hut" (using the cursor keys then pressing ENTER, or clicking with your mouse pointer). Adventuron will type hut automatically.

Here is an animation showing this process:

009

Now let’s press the PLAY ICON and play the game for a little while …​.

play icon
010

4.8.1. Great Job!

If you have got this far, congratulations.

If you feel tired, or get stuck, then take a break, or ask a trusted grown up for help.

4.8.2. Code So Far

########################################
#  Adventuron                          #
########################################

start_at      = hut

########################################
#  Locations                           #
########################################

locations {

   hut    : location "You are in an old hut. Sunlight shines in from a doorway to the north." ;
   road_1 : location "You are standing on a track. The hut is south." ;
   road_2 : location "You are where the road turns eastwards. You see small hills in the distance." ;

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,    north, road_1,
      road_1, north, road_2,
   ]

}

########################################
#  Objects                             #
########################################

objects {
   ladder : object "a ladder" start_at = "hut" ;
}

4.9. Adding all the locations

castle smaller

We will now type in all the remaining locations of Excalibur into the game.

It’s much easier if you do this in a pair, with one person reading the ids and descriptions, and the other person typing.

Remember, you always need to start on an EMPTY LINE then press CONTROL + SPACE and Adventuron will give you a new location template. After that, type the name of the identifier, then press the TAB button (left of the Q button), then type the description of the location.

The underscore '_' looks like a minus symbol, but lower. To type it you have to hold the SHIFT button and press the minus '-' button.

You can copy and paste this text if you wish, but this is good typing practise if you have the time to type all these locations yourself.

(If the following text is too cramped, remember you can double click the documentation to go into full screen mode, then double click to go back)

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

4.10. Code So Far

########################################
#  Adventuron                          #
########################################

start_at      = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,    north, road_1,
      road_1, north, road_2,
   ]

}

########################################
#  Objects                             #
########################################

objects {
   ladder : object "a ladder" start_at = "hut" ;
}

4.11. Adding all the navigation options

It is now time to add all the navigation options, and for now, we will ignore the areas of the map that are blocked (the parts with the dotted line).

Map - Part 1

map 1
Figure 3. Click to see larger image

Map - Part 2

map 2
Figure 4. Click to see larger image

This table (which was prepared from the map earlier in the tutorial) shows how all the locations are connected.

from direction to

hut

leads north to

road_1

road_1

leads north to

road_2

road_2

leads east to

road_3

road_3

leads east to

road_4

road_4

leads north to

foot_of_tree

road_4

leads south to

lamp_seller_on_road

lamp_seller_on_road

leads east to

demon_knight_road

lamp_seller_on_road

leads south to

chasm

foot_of_tree

leads up to

top_of_tree

chasm leads

leads south to

edge_of_birwood

edge_of_birwood

leads south to

deep_inside_birwood

deep_inside_birwood

leads west to

birwood_bush

demon_knight_road

leads east to

castle_approach_1

castle_approach_1

leads east to

castle_approach_2

castle_approach_2

leads east to

castle_porch

castle_porch

leads east to

banquet_hall

banquet_hall

leads north to

portcullis

banquet_hall

leads south to

drafty_room

portcullis

leads north to

most_splendid_room

most_splendid_room

leads west to

arthur

drafty_room

leads east to

ornate_antechamber

drafty_room

leads down to

salt_mine_1

ornate_antechamber

leads east to

cold_room

cold_room

leads north to

winch_room

winch_room

leads east to

armoury

salt_mine_1

leads west to

salt_mine_2

salt_mine_1

leads south to

worm_room

worm_room

leads south to

salt_mine_3

Now, we have to enter this information into the connections block of code.

Now, you must repeat the lesson from earlier for each entry in this table. See the animation at the bottom of this section to show how this works, but you have to use CONTROL + SPACE - a lot.

It might help if you do this in a pair, and one person reads out each line, as the other person creates a new line in the navigation table. After you type each line, check it to make sure you have not made any mistakes.

The video below is sped up, but the it shows how you should be able to edit the connections easily, using CONTROL + SPACE.

011 new

After entering this information into Adventuron, you now have a map you can completely explore.

Here is the source-code you should have entered so far …​.

########################################
#  Adventuron                          #
########################################

start_at      = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {
   ladder : object "a ladder" start_at = "hut" ;
}

4.12. Adding all the objects

We will now create all the remaining objects and scenery, and set the start location of each item using start_at.

As a reminder, this is how we describe an object at a location.

ladder : object "a ladder" start_at="hut" ;

The full list of objects is repeated here, for convenience:

4.12.1. Objects (Things we can pick up or use)

Identifier Description Found At

ladder

a ladder

hut

red_fish

a red fish

road_3

short_sword

a short sword

top_of_tree

coin

a coin

ornate_antechamber

string

some string

salt_mine_2

salt

some salt

salt_mine_3

oil

can of oil

cold_room

excalibur

Excalibur!

armoury

long_pole

a long pole

-

rungs

some rungs

-

stone_key

a stone key

-

axe

a wood cutters' axe

-

lamp

a lamp

-

Scenery (Objects or People we can’t pick up)
Object Name Description Initial Location

old_woman

an old woman selling lamps

lamp_seller_on_road

logs

a pile of logs

deep_inside_birwood

bush

a bush

birwood_bush

demon_knight

a Demon Knight guarding the east road

demon_knight_road

trapdoor

an old trapdoor

drafty_room

smashed_trapdoor

a smashed trapdoor

-

rockworm

a Rockworm, guarding the south tunnel

worm_room

ice_creature

an Ice Creature, guarding the north exit

cold_room

winch

a winch

winch_room

spell

a spell flying at you from Crania

most_splendid_room

Remember that we create an object by pressing CONTROL + SPACE on an empty line in the objects {} code block, select 'object', then type in the identifier, then press the TAB button to type in the description.

To create a new line, press ENTER at the end of the line (after the ';').

Non moveable things are known as 'scenery' and scenery is something that is shown by the game, but cannot be put in your pocket.

It’s important that you tell the computer if something is an object (you can take it), or scenery (you can not take it).

The completed code block should look like this:

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"       start_at="hut" ;
   red_fish         : object  "a red fish"     start_at="road_3" ;
   short_sword      : object  "a short sword"  start_at="top_of_tree" ;
   coin             : object  "a coin"         start_at="ornate_antechamber" ;
   string           : object  "some string"    start_at="salt_mine_2" ;
   salt             : object  "some salt"      start_at="salt_mine_3" ;
   oil              : object  "can of oil"     start_at="cold_room" ;
   excalibur        : object  "Excalibur!"     start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"               start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                           start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                   start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"    start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                          start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"    start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit" start_at="cold_room" ;
   winch            : scenery "a winch"                                  start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"        start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                     start_at="arthur" ;

}

4.12.2. If you make a mistake

If you make a mistake, you can copy and paste from this document into your own code. If you have somehow done something wrong, and want to catch-up, you can copy and paste from the code at the bottom of this section.

4.12.3. Locations, Connections & Objects

We now have the basic structure of the game defined.

We have the location descriptions, connections between locations, and objects that the game contains.

Even though we have not yet created the puzzles, we should now be able to explore the world, and all the objects / scenery in the world, without the game stopping us from going anywhere.

012

4.13. Code So Far

########################################
#  Adventuron                          #
########################################

start_at      = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                              start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

5. Adding Logic

5.1. Responding to commands

5.2. What Are Commands?

Text adventure games respond to some kind of command (usually text), then usually show some text, or do something in response to the text..

If the player types something the game doesn’t know about, the game try its best to give the player some feedback.

If a reply is not programmed, then Adventuron will use one of its standard replies.

do not understand

There are different ways of writing command handlers, but the way we will use in the tutorial is the "manual" method.

This method involves, manually looking at the verb (the doing word) and the noun (the thing, person, object, or scenery).

The text we wish to respond to is "EXAMINE LADDER".

So, what happens if we type examine ladder.

If we are not in the same location as the ladder …​

ladder not here

If we are in the same location as the ladder …​

ladder nothing special

The response we want when examine the ladder (when it is held or in the same location) is "A LONG POLE WITH RUNGS ATTACHED."

5.3. Why examine messages are important

Why do we want this response?

Well, the response is there to give the player a clue about how the ladder might be used. Later on, there is a tightrope across a chasm.

Normally a pole is used by people balancing on a tightrope, so this message gives a clue to the player that the ladder could be converted into a pole, somehow.

5.4. Creating the on_command {} block

To write our handler, we need a new section creating in the document. We need a blank line of text, OUTSIDE of "connections", "locations" and "objects" blocks.

The location can be anywhere you like (outside of the other code blocks), but we will place it UNDERNEATH the objects block.

To create the "on_command {}" block, press CONTROL + SPACE, next start typing the first few letters of on_command (such as "on"), when you see the "on_command" item, select it using the "enter" button on the keyboard.

013

The "on_command {}" block is used to process commands that the player submitted (could be via keyboard or joypad or hyperlink or voice) …​ and respond to those user entered command with a reaction.

If nothing is matched, the Adventuron will either do something with the command itself (if it knows what to do), or tell the player that it doesn’t something about what they typed.

5.5. Creating a ": match" command

Now we need to match "examine ladder", so lets go to an empty line inside on_command {} and press …​ CONTROL + SPACE. There are a couple of options here, so let’s select "match", and then press enter.

After pressing enter, we should see the following block of code appear. The "get lamp" text is already highlighted by the editor, this means if we start typing, it will automatically wipe over the text.

The "get lamp" text is just there to demonstrate how to use match items, and will appear as a default every time you create a new match using this technique. You don’t need to delete it, you just start typing and it will disappear.

014

Now lets save our text by pressing CONTROL + S, and press the PLAY icon to try out the adventure.

Still, when typing "EXAMINE LADDER", nothing seems to happen.

That’s because we didn’t tell Adventuron what to do if ladder is matched, so Adventuron didn’t do anything, and therefore just gave its normal response.

5.6. Creating a ": print" command

Now, inside the ": match {}" command, on a blank line, press CONTROL + SPACE. A big list of commands are available here, but we won’t look at these right now.

Start typing the letters "pri" (the first 3 letters of print), and now we will be able to pick the command we are interested in, which is "print".

The text we want to display is "A LONG POLE WITH RUNGS ATTACHED.", so after selecting the "print" command, type "A LONG POLE WITH RUNGS ATTACHED." in the area between the quotes (").

015

In the original Excalibur: Sword of Kings game, all messages are in capital letters, but this is optional, and if you prefer not to use capital letters, that is fine.

Now, lets save the document with CONTROL + S, and run the game with the play icon. Actually, it’s not necessary to press the PLAY icon, as CONTROL + S will reset the game every time.

Now when we type "EXAMINE LADDER" we see the response "A LONG POLE WITH RUNGS ATTACHED." appear. Success !

016

But, there is a problem ! Can you guess what it is?

The problem is that if you type "EXAMINE LADDER" anywhere, even if you are in a different location, you still get the same response.

The response to the command should only be made when the ladder is present - and to do that we need to make the ": print {}" command CONDITIONAL.

The code so far …​.

########################################
#  Adventuron                          #
########################################

start_at      = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  On Command                          #
########################################

on_command {

   : match "examine ladder"  {

      : print "A LONG POLE WITH RUNGS ATTACHED." ;

   }

}

5.7. The ": if" command

The ": if" command lets us do something but only if it’s the right time to do it.

Checking to see if something is the right time is called a conditional logic.

We use conditions every day when we speak to each other. We might say something like, "if the weather is good, let’s go to the park". The right time to go to the park is when the weather is good.

On Saturday, I go to the cinema, is also kind of a condition too. It can be rephrased "if it’s saturday, I go to the cinema."

We tell computers the right time to do something using the word "if".

We wish to only display "A LONG POLE WITH RUNGS ATTACHED." when we examine the ladder if we are in the same location or if we are holding the ladder.

The if command is in 3 parts:

  • : if → This is an if command

  • () → Is it a good time to do this?

  • {} → This is what we should do, only if it’s the right time to do it.

To make our "if" command, we make a line ABOVE the print command, then press CONTROL + SPACE, then type "if" then select the if with the CURSOR KEYS, then press ENTER.

017

We can see in the video above how to make an if statement using the autocomplete (CONTROL + SPACE) method.

if statement 1

5.8. Cutting And Pasting The Print Statement

This is also a good time to show how to cut and paste.

Go to the end of the match code block (using a mouse or the cursor keys), and then once at the end of the line, hold the SHIFT button on the keyboard (ask a grown up or friend if you can’t find the button), and then keep tapping the cursor key left and up until the whole of the match code block is selected (starting from the ":" character next to match).

If you select too much, use the right and down cursor keys to go back.

Once you select the print line, let go of the shift key, and the cursor keys, then press CONTROL + X, on the keyboard. This will cut the text. Cutting text is like deleting text temporarily, but the computer remembers the deleted text so it can move it somewhere else.

Now move the cursor to the empty line inside main part of the if statement and press CONTROL + V. This will paste the cut text into the new space.

018

You can see from the video about that we add new spaces to the start of the "match" block when it is inside of the "if" block. This makes the code easier to see the start and end of blocks.

Cutting and pasting is extremely useful, and it really benefits you to practise cutting and pasting a lot of text. If you have a mouse, you can also select the text by dragging the mouse across the text you want to cut.

If you want to copy text, rather than move text, use CONTROL + C, instead of CONTROL + X at the beginning…​.

If you have cut and paste correctly, the header bar should not be red, and we should save the document (CONTROL + S), and move forward.

We now have an if statement with the thing to do if it’s a good time part (the print command), but we still don’t know when it is the right time to perform the print command…​

5.9. How to check if it is the right time to do something!

Usually when we want to do something, we need to ask permission first. Asking permission usually has two answers, "yes", and "no". Computers understand "yes" and "no" very well.

So, when is the right time to be able to examine the ladder? Well, you can’t examine (look) at a ladder if it’s not in the same location can you? So, it either has to be in the same location, or if you are holding it. That’s the right time that you can examine (look) at a ladder.

Adventuron has lots of different recipes for getting a yes or a no answer. One of these recipes is called the "is_present" recipe.

"present" has two meanings. The first meaning is the type of thing you might get on your birthday.

The second mean is if something is with you. You could say, "my friend is here', or "my friend is present", and they both mean the same thing.

We can use "is_present" to check to see if the ladder is in the same location or if the person playing the game is holding the ladder.

The best way to understand it is to show how we type this in …​

019

Adventuron will only perform the middle part (the part between the {} bracey brackets) only if the ladder is in the same location, or we are holding the ladder.

Now we can see that we can only look at the ladder if it is in the same location as us. If we go north from the hut, and try to examine the ladder, we see the usual message that is shown when adventuron doesn’t know what to do.

Press CONTROL + S to save your progress, and try out examining the ladder when you are in the hut, and when you are not in the hut.

Remember that navigating requires you to know the directions of the compass. North is up on the map, south is down.

020

5.9.1. The code so far …​.

It’s useful at this point to show where we are at. This is the listing that we should have at this point in time, if we have followed all the instructions. Please check you are up to date.

########################################
#  Adventuron                          #
########################################

start_at      = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Things                              #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  On Command                          #
########################################

on_command {

   : if ( is_present "ladder" ) {
      : match "examine ladder"  {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }

}

5.10. Adding all the other EXAMINE actions

5.11. Examine

In text adventure games, objects are able to be examined.

To examine a sword we would type:

examine sword

It’s a way of delivering clues to the player, and sometimes to discover something hidden.

Here are the some messages that we wish to display when examining certain objects.

Table 1. Examine Handlers (Part 1 of 2)
match condition message

examine ladder

is_present "ladder"

A LONG POLE WITH RUNGS ATTACHED.

examine woman

is_present "old_woman"

SHE LOOKS AT YOU WITH AN INTENSE GLARE.

examine lamp

is_present "lamp"

IT’S OLD AND TARNISHED.

examine fish

is_present "red_fish"

IT STINKS!

examine sword

is_present "short_sword"

INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK!' ~~ MERLIN.

So, let’s now enter these new items.

The following code should be added to the bottom of the on_command{} section:

: match "examine woman"  {
  : if (is_present "old_woman") {
     : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
  }
}
: match "examine lamp"  {
  : if (is_present "lamp") {
     : print "IT'S OLD AND TARNISHED." ;
  }
}
: match "examine fish"  {
  : if (is_present "red_fish") {
     : print "IT STINKS!" ;
  }
}
: match "examine sword"  {
  : if (is_present "short_sword") {
     : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
  }
}

We will also modify the existing ladder handler to place the command matcher on the outside.

021

So far the only thing that we have done in response to a player entering some text (such as examine ladder or examine lamp), is to display some text to the player.

Sometimes we want to do something else.

Table 2. Examine Handlers (Part 2 of 2)
match condition message other actions

examine bush

is_present "bush"

YOU FIND SOMETHING!

Create the stone_key , wait for the user to press something, then redescribe the scene. * NOTE: This is slightly different behaviour to the original game.

examine logs

is_present "logs"

YOU FIND AN AXE!

Create the axe in the current location, wait for the user to press something, then redescribe the scene. * NOTE: This is slightly different behaviour to the original game.

Both the logs and the bush create a new object in the scene that the player is in when they are examined.

They also redescribe (refresh) the description of the scene so that the player can see the created objects. Hiding objects within a scene is quite normal in this type of adventure.

To be able to program this, we require 3 new commands, in addition to the ': print' command, which we have already used.

We also require 1 new condition.

Table 3. Commands So Far
Command Description

: print

Displays some text to the player

: create

Creates an object in the current scene (NEW)

: press_any_key

Tells the game to wait until the player either presses a key on the keyboard, or clicks the mouse, or touches the touchscreen. (NEW)

: redescribe

Tells the game to clear the screen, then to redescribe the current scene, including the contents of the scene. (NEW)

Table 4. Conditions So Far
Command Description

: is_present

Is an object carried or in the same scene as the player?

: has_not_created

Has the object not yet been created? (NEW)

5.11.1. AND statements (&&)

To create the logic for the last two examine messages, we also require an and statement.

An AND statement what we use to put together statements that must ALL BE TRUE in order to execute the part between the { } statements.

We use AND statements in English all the time to describe some requirements. Things like "if the weather is good and I have time this weekend, I will go to the park."

"We will go to the park only if the weather is good, AND we have time."

In Adventuron, an and is written using the && letters. Let’s see how this is used below by building our logic for "examine logs" and "examine bushes".

022

In the animation shown above, the bush code block is created, and after checking the "is_present" condition, the && operator is used to connect the two expressions that must be true.

The next condition that is added is has_not_created "stone_key".

   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }

The purpose behind this condition is to make sure that we won’t KEEP generating keys every time the bush is examined.

Without this, every time we examine the bush, the message is displayed, and the key is regenerated.

Next in the animation, we create the message to display when the bush is examined (for the first time), then we add the "create" command to create the key (in the scene that the player is in), then we add the "press_any_key" command, and finally, the "redescribe" command.

We copy this block of code using copy and paste (as described earlier), and then modify the differences we need the logs.

We swap the stone_key for the axe, and the logs for the bush, and we have a different message to print, but the structure of the block is the same, so that’s why we copied and pasted.

It’s important not to type more than you need to type, so learning to copy and paste is a time saver.

There is actually a more elegant (easier) way to give objects examine messages and to check for existence of something, but we are sticking to the basic method in this tutorial.

Let’s Play

So, let’s play the game again to see what happens when we examine the bush and the logs.

023

The code so far …​.

########################################
#  Adventuron                          #
########################################

start_at      = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Things                              #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }
}

5.12. Adding Pictures (graphics)

5.12.1. Introducing Files

Do you remember at the beginning of this guide, that we saw pictures of the original version of Excalibur?

It had lots of bright colourful pictures.

excalzx hut
Figure 5. Excalibur (1987)
excalzx lady
Figure 6. Excalibur (1987)

These pictures are called graphics, and you can use graphics to make your adventure more fun and colourful.

Adventuron lets you add (also known as import) fun blocky graphics from files.

A file is a named thing on your computer, that you can access inside a folder. Files can contain all sorts of things, like words, or web pages, or music, or videos, or …​ graphics.

There are lots of different types of graphic files, but the type that Adventuron likes best is PNG.

A PNG file is a type of file that can hold old-style blocky graphics very nicely, but it can also store other types of picture too.

The most common type of graphic file type is JPEG, but this type of file can sometimes make blocky graphics blurry, so let’s use PNG instead.

5.12.2. How do you make a PNG file?

An upcoming version of Adventuron will also feature a basic graphics editor.

But, for the time being, on Windows, you might use Microsoft Paint, and when you save the file, make sure to select PNG.

paint

On OSX, there are many applications that will produce PNG files. Ask a parent or teacher to recommend one.

5.12.3. Zip Import

Adventuron can also import (add) many files at the same time, if they are inside another type of file called a ZIP file.

A zip file is available containing all the Excalibur graphics.

This file is made available for the purpose of following this tutorial only, and must not be redistributed.

These graphics should ONLY be used for following this tutorial and MUST NOT be used in any personal adventures you make yourself. Better to make your own graphics.

5.12.4. So, how do we import graphics?

Well, see the little button at the bottom of the editor window with "Menu", click that, and then select the "Import" option.

After clicking that, find the zip file you downloaded (it should be in the downloads folder on your computer), and then click "Open".

024

Getting the graphics from the zip "file" into the Adventuron is called importing. It can also be sometimes referred to as loading.

The graphics we just imported (or loaded) share the same identifiers as the scenes we have already entered.

Adventuron will automatically associate the graphics with the scenes, if they share the same identifiers, so now all the initial scene graphics are set up already.

When the import takes place, Adventuron converts the graphics into text. It’s not readable to human beings but the computer knows how to read this strange text.

assets base64

If it looks impossible to read, then don’t worry, it’s impossible to read for everyone.

This type of text is called base64 text, and it’s not important for humans to be able to read it - just understand that it makes sense to the computer.

All that’s important is the identifier part, and that the computer knows how to read it.

Later versions of Adventuron will hide this information.

Now that we importing the graphics, we should be able to take a walk around the game world, but this time, with graphics.

025

The code so far

########################################
#  Adventuron                          #
########################################

start_at      = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }
}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

6. Adding Puzzles

6.1. Blocking The Top Of The Tree

foot of tree

At this point in the tutorial, the player has complete freedom to go everywhere, and there are no puzzles.

It is common in this type of game, for areas of the map to be blocked.

Blocking means restricting access to a location or an area of the map (until a puzzle is solved or action is performed).

The first block we will create is blocking access to the top of the tree.

Currently, there is no barrier to going from the bottom of the tree to the top of the tree.

The first puzzle in the game is climbing the stone tree. There are no branches on the tree, so it cannot be climbed.

Even though we have created an entry in the connections section, describing that the bottom of the tree leads up to the top of the tree, after creating the BLOCK, typing up should not allow the player to go UP to the location "top of tree" unless the ladder is rested against the tree.

6.2. Boolean Variables

But before we get to blocks, we need to create a boolean variable.

A boolean variable is a container for a yes or no answer.

Imagine it like an envelope, and inside the envelope there can only be written "yes" or "no".

In most computer languages, YES is the same as TRUE, and NO is the same as FALSE.

  • YES = TRUE

  • NO = FALSE

So, now, we will create an envelope that contains the answer to the question:

is the ladder standing against the tree?

  • yes or no (true or false)

The ladder starts in the hut, so the answer to the question at the start of the game is no (or false).

We will store this fact inside the boolean variable 'is_ladder_standing'. We could call the variable 'is_the_ladder_standing_against_the_tree' but keeping variable names as short as possible makes it faster to code.

Variables are convenient because it lets the game author keep track of when the player has done things in the game.

Never be tempted to make variable names TOO SHORT, because you need to understand what they mean.

We can create the boolean variable like this by pressing CONTROL + SPACE, on a blank line when not in another section (just above on_command {} is good), then typing the name

new 001

Type it yourself, or copy and paste it from here:

booleans {
   is_ladder_standing : boolean "false";
}

6.3. Standing the ladder against the tree

Next we want to be able to change the VALUE of the boolean variable.

Remember, 'is_ladder_standing', now contains a false (no) answer, but if the player goes to the tree, holding the ladder, and type LEAN LADDER or STAND LADDER or REST LADDER or DROP LADDER then we should put a true (or yes) value in this variable (or envelope).

on_command {}
: match "stand ladder;lean ladder;rest ladder;drop ladder"  {
  : if (is_carried "ladder" && is_at "foot_of_tree") {
     : drop ;
     : set_true "is_ladder_standing" ;
     : set_graphic graphic = "foot_of_tree_2"  target = "foot_of_tree" ;
     : redescribe;
  }
}

The code show above does the following.

  1. It checks that the player typed stand ladder or lean ladder or rest ladder or drop ladder. If the player didn’t type one of these things, then we don’t execute any further step.

  2. Next it checks that the player is carrying the ladder, and that the player is currently at the foot of the tree location. If the players isn’t carrying the ladder or isn’t at the foot of the tree, then we don’t execute any further step.

  3. It drops the object currently being reference (in this case ladder).

  4. It puts a true (or yes) value into the is_ladder_standing variable.

  5. It changes the graphic for the current scene to the 2nd version (a version showing the ladder).

  6. It redescribes the current location (forcing the graphic and text to be refreshed).

6.4. Taking the ladder from the tree

on_command {}
: match "get ladder"  {
  : if (is_at "foot_of_tree" && is_beside "ladder") {
     : get ;
     : set_false "is_ladder_standing" ;
     : set_graphic graphic = "foot_of_tree" target  = "foot_of_tree" ;
     : redescribe ;
  }
}

The code show above does the following.

  1. It checks that the player typed "get ladder". If the player didn’t type it, then we don’t execute any further step.

  2. Next it checks that the player is beside (but not carrying) the ladder, and that the player is currently at the foot of the tree location. If the players isn’t beside the ladder or isn’t at the foot of the tree, then we don’t execute any further step.

  3. It gets the object currently being reference (in this case ladder).

  4. It puts a false (or yes) value into the is_ladder_standing variable.

  5. It changes the graphic for the current scene to the 1st version (a version not showing the stood ladder).

  6. It redescribes the current location (forcing the graphic and text to be refreshed).

6.5. Progress Report

Now we have code that will change the location graphic and change the VALUE of the 'is_ladder_standing' boolean variable when the ladder is stood against the tree, and when it is taken from the tree location.

new 002

Although we have code now to record if the ladder is standing or not, it doesn’t prevent us from going UP the tree when the ladder is not stood against the tree. Also, the UP direction is still listed even when the ladder is not standing against the tree.

For real immersion, we want to remove the UP direction from the exit lists if the ladder is not standing against the tree.

We can achieve both of these goals (remove up exit, and block access up) by using a barrier.

6.6. Introducing Barriers

A barrier (in Adventuron) is something that stops you from going somewhere and is contained in a section called barriers {}.

There are many types of barrier, but the one we will use for the tree puzzle is a block.

A block prevents acess to a location via regular direction commands (north, south, east, west, up, down, …​).

As standard, if the block is active then the block will also remove the direction from list of available directions. This lets the player know that the direction is not available. Sometimes we do want to list the location of a blocked exit anyway, and we will explore this option later.

A regular block requires the following:

  • A location identifier to block

  • A message to display (or a subroutine to execute).

  • An activation condition.

The activation condition which tells the block when it should be active, or inactive.

In this case, we will look at the is_ladder_standing variable.

barriers{}
tree : block {
  location       = top_of_tree
  message        = YOU CAN'T FIND YOUR GRIP
  block_when_not = is_ladder_standing
}

The code shown above tells Adventuron to block the top_of_tree location, but only when is_ladder_standing contains a false (no) value/answer.

Adventuron takes care of removing the listing of an exit when a block is encountered, so if the ladder is not stood at the bottom of the tree, the "UP" exit will not be shown.

If the player types UP by themselves, they see the message "YOU CAN’T FIND YOUR GRIP" but they do not travel to the top of the tree.

6.6.1. Testing the block

If we click the PLAY icon at the top of the screen, and play the game now. We can navigate to the bottom of the tree (N, N, E, E, N), and we can now see that UP is not listed as an exit.

If we type UP, we are show the message "YOU CAN’T FIND YOUR GRIP".

We have successfully BLOCKED access to the top of the tree.

029

6.7. The code so far …​..

########################################
#  Adventuron                          #
########################################

start_at       = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false";
}

########################################
#  Blocks                              #
########################################

barriers {
   tree : block {
      location       = top_of_tree
      message        = YOU CAN'T FIND YOUR GRIP
      block_when_not = is_ladder_standing
   }
}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

6.8. Fighting the Knight

demon knight road

We are going to now code the first danger of the game.

The Demon Knight stands in the path on the way to Camelot. Currently, we can just walk past the knight, because we haven’t added any logic.

If we try to attack the knight without a weapon, then the knight will defeat us in battle, and the game will end.

If we try to walk past the knight, then the knight will strike us, and the game will end.

The way to defeat the knight is to attack the knight whilst carrying the short sword (which was obtained from the room at the top of the tree, which itself required the ladder puzzle to be solved).

So our logic is:

  1. If in same location as knight, and issuing the 'east' command, then describe defeat, and end game.

  2. If in the same location as the knight, and typing 'attack knight', or 'fight knight', and not holding short sword, then describe defeat, and end game.

  3. If in the same location as the knight, and typing 'attack knight', or 'fight knight', and holding short sword, then describe victory, and remove the knight from the game.

This puzzle will use a different kind of block.

A subroutine block is a block that executes a subroutine instead of moving to the blocked location.

Our First Subroutine Block (Added in barriers{} section)
knight : block {
  location          = castle_approach_1
  gosub             = lose_fight
  block_when_exists = demon_knight
  show_blocked_exit = true
}

The 'show_blocked_exit' option is something that can be added to a block to tell adventuron to show the blocked exit in the exits list.

In this puzzle, we want to show the exit 'east' even though moving in that direction will end the game.

As standard, if there is an active block, then the exit will not be listed until the block is removed or made inactive.

6.8.1. Subroutines

A subroutine is section of code that can be referenced from some other part of the code.

The advantage of using subroutines is that sometimes the same functionality needs to be used multiple times, and it makes it easy to write code that does one thing, in one place, rather than copying and pasting it in multiple places.

The code inside a subroutine can be referenced in various parts of Adventuron, and once the code is finished executing, it returns to the place in the code from where it was referenced (unless the subroutine ends the game).

We will place the battle logic in three subroutines.

Subroutine Id Description When Referenced

lose_fight

The subroutine will print the message "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU…​." then it will execute the "end_game" subroutine.

If we try to move into the blocked location beyond the knight or if we attempt to attack the knight without the short sword, then the lose_fight subroutine is executed.

win_fight

This subroutine prints the message "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. BEFORE YOUR EYES THE KNIGHT TURNS TO DUST ALONG WITH YOUR SWORD!", then the short sword is removed from the game, the knight is removed from the game, the graphic for the location with the knight is changed to remove the knight, and the block of the castle_approach_1 location is removed.

This subroutine is executed if we fight the knight whilst holding the short sword.

end_game

Waits for the user to press a button, then clears the current screen, then shows the "game_over" graphic, then prints the message, "Your quest is over …​…​…​.", then prints the number of turns, and signals to Adventuron to end the game (game over).

The subroutine is executed when the game is lost. It is referenced from the "lose_fight" subroutine, but it will also be referenced by other parts of the game later on.

Subroutines
########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2" target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over" ;
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }
}

To initiate fighting the knight, then the command "fight knight" or "attack knight" or "challenge knight" should be typed.

on_command {} code
: match "fight knight;attack knight;challenge knight"  {
  : if (is_present "demon_knight") {
     : if (is_carried "short_sword") {
        : gosub "win_fight" ;
     }
     : else {
        : gosub "lose_fight" ;
     }
  }
}

6.8.2. Else Statements

In the previous block, we see the used of an 'else' statement. An else statement is a block or code that will only be executed if and 'if' statement that appears above it, has a condition that is not 'true'.

An else statement can only be used after an 'if' statement or an 'else_if' statement (described later).

6.8.3. The code so far

########################################
#  Adventuron                          #
########################################

start_at       = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false";
}

########################################
#  Blocks                              #
########################################

barriers {
   tree : block {
      location          = top_of_tree
      message           = YOU CAN'T FIND YOUR GRIP
      block_when_not    = is_ladder_standing
   }

   knight : block {
      location          = castle_approach_1
      gosub             = lose_fight
      block_when_exists = demon_knight
      show_blocked_exit = true
   }
}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

    : match "fight knight;attack knight;challenge knight"  {
      : if (is_present "demon_knight") {
         : if (is_carried "short_sword") {
            : gosub "win_fight" ;
         }
         : else {
            : gosub "lose_fight" ;
         }
      }
    }


}


########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2"  target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over" ;
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

6.9. Crossing the chasm

chasm

The ladder has a second use.

To cross the chasm you need to be holding a pole to help you balance, then type CROSS CHASM whilst holding the pole.

Both sides of the chasm require typing CROSS CHASM to take you to the opposite side, and the holding of the pole that assists your balance.

The pole is an object that is created if the player types BREAK LADDER, SMASH LADDER or DISASSEMBLE LADDER whilst holding the ladder.

The clue to solve this puzzle is the use of the word "tightrope" in the "edge of a huge chasm" location.

Tightrope walkers usually hold a pole to help their balance.

Examining the ladder describes the ladder as "A LONG POLE WITH RUNGS ATTACHED.". Interesting !

Breaking, smashing or dismantling the ladder will create the objects "some rungs" and "a long pole". It will also remove the ladder from the game.

The ladder can be broken at any time, including BEFORE climbing the tree. Breaking the ladder this way puts the game into an unwinnable state, as the ladder cannot be reconstructed.

The player will probably become aware of this if they solve the chasm puzzle before the tree puzzle, but if they don’t it may be frustrating.

QUIZ - Can you think of a way to fix the unwinnability problem here ?

6.9.1. Breaking The Ladder

The logic for breaking the ladder is fairly straightforward.

The following code should be added to the bottom of the on_command{} section:

: match "break ladder;smash ladder;disassemble ladder"  {
   : if (is_carried "ladder") {
      : print   "OK."       ;
      : destroy "ladder"    ;
      : create  "long_pole" ;
      : create  "rungs"     ;
      : press_any_key       ;
      : redescribe          ;
   }
}

Here is an animation on how it should look to create this block:

new 003

We will be using less animations going forward as you should be getting used to how to use CONTROL + SPACE, TAB, the CURSOR KEYS, and other keyboard shortcuts.

6.9.2. Commenting Out Code

Moving on, we need to code in the chasm crossing logic. Currently the navigation table allows free movements from the chasm location to the edge_of_birwood.

We will use yet another form of blocking now which is simply removing the navigation item entirely.

To do this, we can "comment out" the line in the navigation table which connects the chasm location to the edge_of_birwood location.

To comment something out, we can type the // character at the start of the line (or lines) we wish to ignore. We could also delete the line, but in this case, we will comment out the line.

Commented out code is completely ignored by Adventuron.

It can be useful to temporarily disable and enable blocks of code.

035

6.9.3. The GOTO Command

We now wish to write the code that will allow the player to travel between the chasm location and the edge_of_birwood location when CROSS CHASM is typed and entered in either of those locations (whilst holding the pole).

Some logic can be added for falling if the player types "CROSS CHASM" without holding the pole.

: match "cross chasm; balance _; walk _"  {
  : if (is_at "chasm" && is_carried "long_pole") {
     : print "THE POLE HELPS YOU BALANCE...." ;
     : press_any_key ;
     : goto "edge_of_birwood" ;
     : redescribe ;
  }
  : if (is_at "chasm" && !is_carried "long_pole") {
     : print "YOU LOSE YOUR BALANCE....." ;
     : gosub "end_game" ;
  }
  : if (is_at "edge_of_birwood" && is_carried "long_pole") {
     : print "THE POLE HELPS YOU BALANCE...." ;
     : press_any_key ;
     : goto "chasm" ;
     : redescribe ;
  }
  : if (is_at "edge_of_birwood" && !is_carried "long_pole") {
     : print "YOU LOSE YOUR BALANCE....." ;
     : gosub "end_game" ;
  }
}

The "!" character in from of is_carried "long_pole" means NOT, and of course the && characters read as AND.

6.9.4. Code so far …​..

########################################
#  Adventuron                          #
########################################

start_at       = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      //chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false";
}

########################################
#  Blocks                              #
########################################

barriers {
   tree : block {
      location          = top_of_tree
      message           = YOU CAN'T FIND YOUR GRIP
      block_when_not    = is_ladder_standing
   }

   knight : block {
      location          = castle_approach_1
      gosub             = lose_fight
      block_when_exists = demon_knight
      show_blocked_exit = true
   }
}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

    : match "fight knight;attack knight;challenge knight"  {
      : if (is_present "demon_knight") {
         : if (is_carried "short_sword") {
            : gosub "win_fight" ;
         }
         : else {
            : gosub "lose_fight" ;
         }
      }
    }

    : match "break ladder;smash ladder;disassemble ladder"  {
       : if (is_carried "ladder") {
          : print   "OK."       ;
          : destroy "ladder"    ;
          : create  "long_pole" ;
          : create  "rungs"     ;
          : press_any_key       ;
          : redescribe          ;
       }
    }

    : match "cross chasm; balance _; walk _"  {
      : if (is_at "chasm" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "edge_of_birwood" ;
         : redescribe ;
      }
      : if (is_at "chasm" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
      : if (is_at "edge_of_birwood" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "chasm" ;
         : redescribe ;
      }
      : if (is_at "edge_of_birwood" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
    }
}


########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2"  target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over";
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

6.10. Opening The Castle Door

castle approach 2

The next puzzle is opening the castle stone door. The door is either open or closed, locked or unlocked.

The door requires the stone key to unlock the door. The stone key was found in the bush in Birwood forest.

A door is a kind of barrier, and can be created in the barriers section (at the top of the document).

We create a door this way, and it will take care of all the opening / closing / and blocking logic for us.

barriers{}
castle_door : door {
  key   = stone_key
  from  = castle_approach_2
  to    = castle_porch
  on_unlock {
     : print "YOU UNLOCK IT WITH THE KEY, WHICH JAMS IN THE LOCK." ;
     : destroy "stone_key" ;
  }
  on_open {
     : set_graphic graphic = "castle_approach_2a" target = "castle_approach_2" ;
     : redescribe ;
  }
  on_close {
     : set_graphic graphic = "castle_approach_2"  target = "castle_approach_2" ;
     : redescribe ;
  }
}

The on_unlock {} section is executed when the door is unlocked. In our section, we wish to destroy the key (remove it from being carried by the player) after the door is locked.

The on_open {} section is executed when the door is opened. In our case, we wish to change the graphic to a version of the graphic with an open door, then redescribe (repaint) the current location.

The on_close {} section is executed when the door is closed. In our case, we wish to change the graphic to a version of the graphic with a closed door, then redescribe (repaint) the current location.

An animation of creating this block is shown here:

new 005

6.10.1. Code so far

########################################
#  Adventuron                          #
########################################

start_at       = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      //chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false";
}

########################################
#  Blocks                              #
########################################

barriers {

   castle_door : door {
     key   = stone_key
     from  = castle_approach_2
     to    = castle_porch
     on_unlock {
        : print "YOU UNLOCK IT WITH THE KEY, WHICH JAMS IN THE LOCK." ;
        : destroy "stone_key" ;
     }
     on_open {
        : set_graphic graphic = "castle_approach_2a" target = "castle_approach_2" ;
        : redescribe ;
     }
     on_close {
        : set_graphic graphic = "castle_approach_2"  target = "castle_approach_2" ;
        : redescribe ;
     }
   }

   tree : block {
      location          = top_of_tree
      message           = YOU CAN'T FIND YOUR GRIP
      block_when_not    = is_ladder_standing
   }

   knight : block {
      location          = castle_approach_1
      gosub             = lose_fight
      block_when_exists = demon_knight
      show_blocked_exit = true
   }

}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

    : match "fight knight;attack knight;challenge knight"  {
      : if (is_present "demon_knight") {
         : if (is_carried "short_sword") {
            : gosub "win_fight" ;
         }
         : else {
            : gosub "lose_fight" ;
         }
      }
    }

    : match "break ladder;smash ladder;disassemble ladder"  {
       : if (is_carried "ladder") {
          : print   "OK."       ;
          : destroy "ladder"    ;
          : create  "long_pole" ;
          : create  "rungs"     ;
          : press_any_key       ;
          : redescribe          ;
       }
    }

    : match "cross chasm; balance _; walk _"  {
      : if (is_at "chasm" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "edge_of_birwood" ;
         : redescribe ;
      }
      : if (is_at "chasm" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
      : if (is_at "edge_of_birwood" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "chasm" ;
         : redescribe ;
      }
      : if (is_at "edge_of_birwood" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
    }
}


########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2"  target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over" ;
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

6.11. Buying the Lamp

lamp seller on road

Buying the lamp is a very simple piece of logic, and is an 'item swap' puzzle. You take an item to a place, type something, and it is replaced with something else.

In this case, the "old woman selling lamps" has a lamp to "sell". When the player gains access to the castle, they will find a coin.

If the player takes the coin, then goes to the same location as the woman, and types BUY LAMP or GIVE COIN, then the game will print "THE OLD LADY TAKES YOUR COIN, GIVES YOU A BRASS LAMP, THEN DISAPPEARS INTO THIN AIR.".

The following code should be added at the end (but inside) the on_command {} section of code.

on_command {}
: match "give coin; buy lamp"  {
  : if (is_present "old_woman") {
     : if (is_carried "coin") {
        : print "THE OLD LADY TAKES YOUR COIN, GIVES YOU A BRASS LAMP, THEN DISAPPEARS INTO THIN AIR." ;
        : destroy "coin" ;
        : destroy "old_woman" ;
        : create "lamp" target="inventory" ;
        : set_graphic graphic = "lamp_seller_on_road_2"  target = "lamp_seller_on_road" ;
        : press_any_key ;
        : redescribe ;
     }
     : else {
        : match "buy lamp"  {
           : print "'CROSS MY PALM WITH SILVER!'" ;
        }
     }
  }
}

6.11.1. Code so far:

########################################
#  Adventuron                          #
########################################

start_at       = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      //chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}


########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false";
}

########################################
#  Barriers                            #
########################################

barriers {

   castle_door : door {
     key   = stone_key
     from  = castle_approach_2
     to    = castle_porch
     on_unlock {
        : print "YOU UNLOCK IT WITH THE KEY, WHICH JAMS IN THE LOCK." ;
        : destroy "stone_key" ;
     }
     on_open {
        : set_graphic graphic = "castle_approach_2a" target = "castle_approach_2" ;
        : redescribe ;
     }
     on_close {
        : set_graphic graphic = "castle_approach_2"  target = "castle_approach_2" ;
        : redescribe ;
     }
   }

   tree : block {
      location             = top_of_tree
      message           = YOU CAN'T FIND YOUR GRIP
      block_when_not    = is_ladder_standing
   }

   knight : block {
      location             = castle_approach_1
      gosub             = lose_fight
      block_when_exists = demon_knight
      show_blocked_exit = true
   }

}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

    : match "fight knight;attack knight;challenge knight"  {
      : if (is_present "demon_knight") {
         : if (is_carried "short_sword") {
            : gosub "win_fight" ;
         }
         : else {
            : gosub "lose_fight" ;
         }
      }
    }

    : match "break ladder;smash ladder;disassemble ladder"  {
       : if (is_carried "ladder") {
          : print   "OK."       ;
          : destroy "ladder"    ;
          : create  "long_pole" ;
          : create  "rungs"     ;
          : press_any_key       ;
          : redescribe          ;
       }
    }

    : match "cross chasm; balance _; walk _"  {
      : if (is_at "chasm" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "edge_of_birwood" ;
         : redescribe ;
      }
      : if (is_at "chasm" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
      : if (is_at "edge_of_birwood" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "chasm" ;
         : redescribe ;
      }
      : if (is_at "edge_of_birwood" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
    }

   : match "give coin; buy lamp"  {
     : if (is_present "old_woman") {
        : if (is_carried "coin") {
           : print "THE OLD LADY TAKES YOUR COIN, GIVES YOU A BRASS LAMP, THEN DISAPPEARS INTO THIN AIR." ;
           : destroy "coin" ;
           : destroy "old_woman" ;
           : create "lamp" target="inventory" ;
           : set_graphic graphic = "lamp_seller_on_road_2"  target = "lamp_seller_on_road" ;
           : press_any_key ;
           : redescribe ;
        }
        : else {
           : match "buy lamp"  {
              : print "'CROSS MY PALM WITH SILVER!'" ;
           }
        }
     }
   }
}


########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2"  target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over" ;
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

6.12. Breaking The Trapdoor

drafty trapdoor close

Inside the castle is a trapdoor, which is locked, and cannot be opened or unlocked.

The solution is to smash the trapdoor.

The axe is required to smash the trapdoor, and this can be found by examining the logs inside Birwood Forest.

When the player types SMASH TRAPDOOR or CHOP TRAPDOOR or BREAK TRAPDOOR we also need to swap the scenery object of "trapdoor" with the new object "smashed trapdoor" and update the graphic in the 'drafty_room' to show the smashed trapdoor.

We add a block for the 'salt_mine_1' location (the location underneath the room with the trapdoor).

The block is only active when the original (non swapped) 'trapdoor' object exists, so when we swap the trapdoor objects for the smashed trapdoor object, the block is switched off, and the DOWN exit is shown.

barriers {}
trapdoor : block {
   location            = salt_mine_1
   message             = THE TRAPDOOR IS JAMMED SHUT!
   block_when_exists   = trapdoor
}
on_command{}
: match "smash trapdoor;chop trapdoor;break trapdoor"  {
  : if (is_present "trapdoor") {
     : if (is_carried "axe") {
        : print "USING THE AXE, YOU SMASH THE TRAPDOOR!" ;
        : destroy "trapdoor" ;
        : create "smashed_trapdoor" ;
		: destroy "axe" ;
        : set_graphic target = "drafty_room" graphic = "drafty_room_2" ;
        : pause "1600" ;
        : redescribe ;
     }
     : else {
        : print "A FRUITLESS EXERCISE!" ;
        : done ;
     }
  }
}

6.12.1. Block identifiers

You might be asking what is the purpose of the part of the block definition before the ':' character.

my_block_id : block {/* .... */}
this_can_be_anything : block {/* .... */}

Well, it’s just an identifier for the block, and used internally.

The identified should be unique, but it doesn’t correspond to anything else. It is 'arbitrary'.

Arbitrary is a word that means that 'it could be anything'. All adventuron requires is an id here, but it helps if you name it something useful, so you can remember what the block is doing.

6.12.2. The Pause Command

This section introduces the ': pause' command.

The ': pause' command is used to introduce a delay (or pause) in executing your code.

Usage
   : pause "1600" ;

The number in the quotes represents milliseconds of time to wait. One second is the same as 1,000 milliseconds of time, so the line shown above commands Adventuron to wait for 1.6 seconds.

The reason for this might be to give the player a change to read something before moving on, or for dramatic effect.

Make sure that if using a pause before a clear screen or redescribe command, that you give the player a second chance to understand what just happened.

In this case, we give two visual indicators that the trapdoor is smashed. We change the on screen graphic, and we change the on screen text (to show a smashed trapdoor).

It is a good idea NOT to place any critical story information behind a pause followed by an instant clearing of the screen (or redescribe). It will be frustrating for the player.

6.12.3. Code so far

########################################
#  Adventuron                          #
########################################

start_at       = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      //chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false";
}

########################################
#  Barriers                            #
########################################

barriers {

   castle_door : door {
     key   = stone_key
     from  = castle_approach_2
     to    = castle_porch
     on_unlock {
        : print "YOU UNLOCK IT WITH THE KEY, WHICH JAMS IN THE LOCK." ;
        : destroy "stone_key" ;
     }
     on_open {
        : set_graphic graphic = "castle_approach_2a" target = "castle_approach_2" ;
        : redescribe ;
     }
     on_close {
        : set_graphic graphic = "castle_approach_2"  target = "castle_approach_2" ;
        : redescribe ;
     }
   }

   tree : block {
      location            = top_of_tree
      message             = YOU CAN'T FIND YOUR GRIP
      block_when_not      = is_ladder_standing
   }

   knight : block {
      location            = castle_approach_1
      gosub               = lose_fight
      block_when_exists   = demon_knight
      show_blocked_exit   = true
   }

   trapdoor : block {
      location            = salt_mine_1
      message             = THE TRAPDOOR IS JAMMED SHUT!
      block_when_exists   = trapdoor
   }

}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

    : match "fight knight;attack knight;challenge knight"  {
      : if (is_present "demon_knight") {
         : if (is_carried "short_sword") {
            : gosub "win_fight" ;
         }
         : else {
            : gosub "lose_fight" ;
         }
      }
    }

    : match "break ladder;smash ladder;disassemble ladder"  {
       : if (is_carried "ladder") {
          : print   "OK."       ;
          : destroy "ladder"    ;
          : create  "long_pole" ;
          : create  "rungs"     ;
          : press_any_key       ;
          : redescribe          ;
       }
    }

    : match "cross chasm; balance _; walk _"  {
      : if (is_at "chasm" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "edge_of_birwood" ;
         : redescribe ;
      }
      : if (is_at "chasm" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
      : if (is_at "edge_of_birwood" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "chasm" ;
         : redescribe ;
      }
      : if (is_at "edge_of_birwood" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
    }

   : match "give coin; buy lamp"  {
     : if (is_present "old_woman") {
        : if (is_carried "coin") {
           : print "THE OLD LADY TAKES YOUR COIN, GIVES YOU A BRASS LAMP, THEN DISAPPEARS INTO THIN AIR." ;
           : destroy "coin" ;
           : destroy "old_woman" ;
           : create "lamp" target="inventory" ;
           : set_graphic graphic = "lamp_seller_on_road_2"  target = "lamp_seller_on_road" ;
           : press_any_key ;
           : redescribe ;
        }
        : else {
           : match "buy lamp"  {
              : print "'CROSS MY PALM WITH SILVER!'" ;
           }
        }
     }
   }


   : match "smash trapdoor;chop trapdoor;break trapdoor"  {
     : if (is_present "trapdoor") {
        : if (is_carried "axe") {
           : print "USING THE AXE, YOU SMASH THE TRAPDOOR!" ;
           : destroy "trapdoor" ;
           : create "smashed_trapdoor" ;
   		   : destroy "axe" ;
           : set_graphic target = "drafty_room" graphic = "drafty_room_2" ;
           : pause "1600" ;
           : redescribe ;
        }
        : else {
           : print "A FRUITLESS EXERCISE!" ;
           : done ;
        }
     }
   }

}


########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2"  target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over" ;
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

6.13. Defeating The RockWorm

worm room

The Rockworm puzzle is the most complex puzzle to code, so please take your time to read and study this section.

The Rockworm lives in the salt mine under the castle and is blocking the way forward.

The solution to this puzzle is simply to persuade it to leave.

Rockworms are sensitive to light, so lighting the lamp is all that is required to scare the worm away.

The worm is blocking further access to the salt mines, and salt is required to tackle the Ice Creature problem.

6.13.1. Design Problems

We should discuss some design problems with this puzzle. In the 1980s, 'sudden death' puzzles were very common, and 'learn-by-death' puzzles were also common. This is one of those puzzles.

Rather than change the original logic, we will implement the mechanics here, as the game is short, and a death will only cost the player a few minutes of time.

The game also has save slots, so if the player feels like something is dangerous they can save the game.

6.13.2. Outcomes

There are 3 different outcomes to this puzzle.

1. Solution

The solution to getting past the rockworm is the light the lamp (which was purchased from the old woman) in the same room as the worm. The worm will make a noise, and get out of the way (the worm doesn’t like light).

2. Sudden Death 1

The first way is to linger in the worm’s location for too long. The game will warn the player before the worm will make its fatal move, then on the next move, if the player has not moved away, the player will 'die'.

3. Sudden Death 2

The second is to try to move beyond the worm. This is a variant of the knight logic (where moving past the demon knight would end the game).

Note
The original logic of the game had a restriction that it was only possible to light the lamp once, and if you did it at the wrong time, the game was unwinnable. This version of the game removes that unwinnable state.
The Worm Attacks !

First, we can put the worm attack code into a subroutine, so we can reference it from multiple places in our code. This is because the worm can attack in multiple ways (if we stay too long, or if we try to move past the worm).

subroutines {}
worm_attack : subroutine {
  : print "THE ROCKWORM RISES UP AND TAKES YOU IN ITS GLEAMING MANDIBLES." ;
  : gosub "end_game" ;
}

Now we create the block (a subroutine block) in the barriers{} section.

This will make sure that if the player attempts to move past the worm, they will see the message "THE ROCKWORM RISES UP AND TAKES YOU IN ITS GLEAMING MANDIBLES.", and then the game will end.

barriers {}
worm : block {
    location            = salt_mine_3
    gosub               = worm_attack
    block_when_exists   = rockworm
    show_blocked_exit   = true
}
Timed Events

Adventuron supports timed events. A timed even is something that will happen after a certain amount of turns of the game (entering commands).

To perform a timed event, we need to put some if statements in the on_tick {} block of code. The on_tick{} section of code is executed after the player has submitted a command.

This can be after the screen is redrawn (such as changing location), or it could be after any command is executed (such as GET LAMP or EXAMINE BUSH).

In Excalibur, we want the worm to attack if the player stays in the same location as the worm for 4 turns. We also want to issue a warning to the player after 3 turns that the worm is getting ready to attack.

The code to achieve this is as follows.

on_tick {
   : if (is_present "rockworm" ) {
      : if (linger() == 3) {
         : print "THE ROCKWORM STARTS MOVING TOWARDS YOU" ;
      }
      : if (linger() == 4) {
         : gosub "worm_attack" ;
      }
   }
}

The on_tick {} block is executed after the player enters a command.

The next part is an if () {} statement that checks to see if the rockworm is present in the same scene / location of the game. The inner if statements will only be executed if we are sharing a scene with the rockworm.

The first INNER IF STATEMENT tests to see if we have been 3 turns in the current location. If we have then it prints "THE ROCKWORM STARTS MOVING TOWARDS YOU".

The second INNER IF STATEMENT tests to see if we have been 4 turns in the current location. If we have, then it prints "THE ROCKWORM RISES UP AND TAKES YOU IN ITS GLEAMING MANDIBLES.", and it executs the end_game subroutine. (Game over).

The linger() function

You may be wondering what is linger(), and how it works. linger is an expression item that resolves to a number. It returns the number of turns since we arrived in a location (or scene). Just after we change location, it will RETURN a ZERO value. ZERO is the number 0.

Numbers can be turned into a yes or no answer by comparing them against other numbers.

Integer Operator Sample Description

==

linger() == 3

Return TRUE 3 turns after arriving in the current scene, return FALSE otherwise.

==

linger() == 4

Return TRUE 4 turns after arriving in the current scene, return FALSE otherwise.

Boolean Variables

A boolean variable is a way of storing if something is a yes answer (true) or a no answer (false).

In Excalibur, we create the 'is_light_lit' boolean variable, which is initially set to have a 'false' value. A 'false' value is the same as a 'no' value. So, this section of code tells the game, that at the start of the game, we should remember that we light is not lit.

We can change the VALUE of a VARIABLE during the game, and we can ask questions about the current content of a variable from anywhere inside our game code. So, later on in the code, we can store a TRUE value inside 'is_light_lit'…​. But that comes later.

booleans {
   is_light_lit : boolean "false" ;
}

The boolean variable is created at root level (not inside any other block of code).

Lighting The Lamp

While the player is holding the unlit lamp (the game checks the value of the 'is_light_lit' variable), if the player types LIGHT LAMP the following actions are performed:

  • We set the 'is_light_lit' boolean variable to a value of TRUE (we use this to inform the player that the light has gone out if they change location).

If the player lights the lamp in the presence of the Rockworm, the following happens:

  • We print the message "THE ROCKWORM’S SENSITIVE EYES ARE SURPRISED BY THE STRONG LIGHT AND IT RETREATS DOWN ITS BURROW …​."

  • We remove the Rockworm from the game.

  • We remove the block from 'salt_mine_3' location.

  • We change the graphic of 'worm_room' location to the replacement picture 'worm_room_2' (room without the worm).

  • We wait for the user to press any key.

  • Redescribe the current location (redraw the graphic and clear previous commands from the screen).

If the light is lit without the worm present, then:

  • Print the message "IT EMITS A BRIGHT LIGHT."

on_command{}
: match "light lamp; switch lamp; turn lamp"  {
  : if (is_present "lamp" && is_light_lit == false) {
    : set_true "is_light_lit" ;
    : if (is_present "rockworm") {
       : print "THE ROCKWORM'S SENSITIVE EYES ARE SURPRISED BY THE STRONG LIGHT AND IT RETREATS DOWN ITS BURROW ...." ;
       : destroy "rockworm" ;
       : set_graphic target = "worm_room" graphic = "worm_room_2" ;
       : press_any_key ;
       : redescribe ;
    }
    : else {
       : print "IT EMITS A BRIGHT LIGHT." ;
       : done ;
    }
  }
}
on_describe{}

The on_describe{} code block is executed when a scene is described, either by moving to a new location, or by typing (or clicking/touching/saying) "look".

It is usually used to add additional information to a scene or to trigger some event (triggering an event means performing some code that tells the player new information or changes the game).

We will use this block to make sure that we report that the light (from the lamp) goes out when we change location. The purpose of this is so that the player must always type LIGHT LAMP to solve the Rockworm puzzle.

If the player could just light the lamp and carry it around indefinately, then they may solve the Rockworm puzzle accidentally.

Putting this in the on_redescribe {} means that whatever location is travelled to after lighting the lamp, the light is described as going out, so the player knows that lighting the lamp will still do something if they do it again.

on_describe {
  : if (is_light_lit) {
     : print "THE LIGHT'S GONE OUT." ;
     : set_false "is_light_lit" ;
  }
}

6.13.3. Code so far …​.

########################################
#  Adventuron                          #
########################################

start_at       = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      //chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Object                              #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false" ;
   is_light_lit       : boolean "false" ;
}

########################################
#  Barriers                            #
########################################

barriers {

   castle_door : door {
     key   = stone_key
     from  = castle_approach_2
     to    = castle_porch
     on_unlock {
        : print "YOU UNLOCK IT WITH THE KEY, WHICH JAMS IN THE LOCK." ;
        : destroy "stone_key" ;
     }
     on_open {
        : set_graphic graphic = "castle_approach_2a" target = "castle_approach_2" ;
        : redescribe ;
     }
     on_close {
        : set_graphic graphic = "castle_approach_2"  target = "castle_approach_2" ;
        : redescribe ;
     }
   }

   tree : block {
      location            = top_of_tree
      message             = YOU CAN'T FIND YOUR GRIP
      block_when_not      = is_ladder_standing
   }

   knight : block {
      location            = castle_approach_1
      gosub               = lose_fight
      block_when_exists   = demon_knight
      show_blocked_exit   = true
   }

   trapdoor : block {
      location            = salt_mine_1
      message             = THE TRAPDOOR IS JAMMED SHUT!
      block_when_exists   = trapdoor
   }

   worm : block {
      location            = salt_mine_3
      gosub               = worm_attack
      block_when_exists   = rockworm
      show_blocked_exit   = true
   }

}

########################################
#  On Describe                         #
########################################

on_describe {
   : if (is_light_lit) {
      : print "THE LIGHT'S GONE OUT." ;
      : set_false "is_light_lit" ;
   }
}

########################################
#  On Describe                         #
########################################

on_tick {
   : if (is_present "rockworm" ) {
      : if (linger() == 3) {
         : print "THE ROCKWORM STARTS MOVING TOWARDS YOU" ;
      }
      : if (linger() == 4) {
         : gosub "worm_attack" ;
      }
   }
}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

    : match "fight knight;attack knight;challenge knight"  {
      : if (is_present "demon_knight") {
         : if (is_carried "short_sword") {
            : gosub "win_fight" ;
         }
         : else {
            : gosub "lose_fight" ;
         }
      }
    }

    : match "break ladder;smash ladder;disassemble ladder"  {
       : if (is_carried "ladder") {
          : print   "OK."       ;
          : destroy "ladder"    ;
          : create  "long_pole" ;
          : create  "rungs"     ;
          : press_any_key       ;
          : redescribe          ;
       }
    }

    : match "cross chasm; balance _; walk _"  {
      : if (is_at "chasm" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "edge_of_birwood" ;
         : redescribe ;
      }
      : if (is_at "chasm" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
      : if (is_at "edge_of_birwood" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "chasm" ;
         : redescribe ;
      }
      : if (is_at "edge_of_birwood" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
    }

   : match "give coin; buy lamp"  {
     : if (is_present "old_woman") {
        : if (is_carried "coin") {
           : print "THE OLD LADY TAKES YOUR COIN, GIVES YOU A BRASS LAMP, THEN DISAPPEARS INTO THIN AIR." ;
           : destroy "coin" ;
           : destroy "old_woman" ;
           : create "lamp" target="inventory" ;
           : set_graphic graphic = "lamp_seller_on_road_2"  target = "lamp_seller_on_road" ;
           : press_any_key ;
           : redescribe ;
        }
        : else {
           : match "buy lamp"  {
              : print "'CROSS MY PALM WITH SILVER!'" ;
           }
        }
     }
   }


   : match "smash trapdoor;chop trapdoor;break trapdoor"  {
     : if (is_present "trapdoor") {
        : if (is_carried "axe") {
           : print "USING THE AXE, YOU SMASH THE TRAPDOOR!" ;
           : destroy "trapdoor" ;
           : create "smashed_trapdoor" ;
   		   : destroy "axe" ;
           : set_graphic target = "drafty_room" graphic = "drafty_room_2" ;
           : pause "1600" ;
           : redescribe ;
        }
        : else {
           : print "A FRUITLESS EXERCISE!" ;
           : done ;
        }
     }
   }

   : match "light lamp; switch lamp; turn lamp"  {
     : if (is_present "lamp" && is_light_lit == false) {
       : set_true "is_light_lit" ;
       : if (is_present "rockworm") {
          : print "THE ROCKWORM'S SENSITIVE EYES ARE SURPRISED BY THE STRONG LIGHT AND IT RETREATS DOWN ITS BURROW ...." ;
          : destroy "rockworm" ;
          : set_graphic target = "worm_room" graphic = "worm_room_2" ;
          : press_any_key ;
          : redescribe ;
       }
       : else {
          : print "IT EMITS A BRIGHT LIGHT." ;
          : done ;
       }
     }
   }

}


########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2"  target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over";
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }

   worm_attack : subroutine {
     : print "THE ROCKWORM RISES UP AND TAKES YOU IN ITS GLEAMING MANDIBLES." ;
     : gosub "end_game" ;
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

6.14. Defeating The Ice Creature

cold room

Defeating the ice creature is extremely simple, if a little cruel.

You must throw salt at the Ice Creature, and then it dissolves into nothingness.

What did the Ice Creature ever do to anyone apart from block the path to the winch? Why was the Ice creature guarding the winch? Did it expect that this would be its final job? Who will take care of the icicles now?

Anyway, this again is a simple blocking arrangement, then graphic swap (to a version of the graphic without the creature) upon typing the words THROW SALT when in the same room as the ice creature, and holding the salt.

First, let’s add the block, and the description of the block.

This block itsel is not a 'sudden death' block. It just tells the player 'THE ICE CREATURE WILL NOT ALLOW IT …​'.

barriers {}
ice_creature : block {
   location            = winch_room
   message             = THE ICE CREATURE WILL NOT ALLOW IT ...
   block_when_exists   = ice_creature
   show_blocked_exit   = true
}

Now we add the on_command{} match command to respond to "throw salt". Perhaps you can figure out what to type now without reading the next part?

on_command {}
: match "throw salt"  {
   : if (is_present "ice_creature") {
      : if (is_carried "salt") {
         : print "THE CREATURE BEGINS TO MELT RAPIDLY..." ;
         : destroy "ice_creature" ;
   	     : destroy "salt" ;
         : set_graphic target = "cold_room" graphic = "cold_room_2" ;
         : press_any_key ;
         : redescribe ;
      }
      : else {
         : print "YOU DON'T HAVE ANY." ;
      }
   }
   : else {
      : print "NOT RIGHT NOW." ;
   }
}

The Ice Creature is another "sudden death" type monster if you stay in the room more than one turn.

We implement the "sudden death" here.

on_tick {}
: if (is_present "ice_creature") {
  : if (linger() == 1) {
     : print "THE ICE CREATURE TAKES YOU IN A FREEZING GRIP" ;
     : gosub "end_game" ;
  }
}

6.14.1. Code so far …​.

########################################
#  Adventuron                          #
########################################

start_at       = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      //chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false" ;
   is_light_lit       : boolean "false" ;
}

########################################
#  Blocks                              #
########################################

barriers {

   castle_door : door {
     key   = stone_key
     from  = castle_approach_2
     to    = castle_porch
     on_unlock {
        : print "YOU UNLOCK IT WITH THE KEY, WHICH JAMS IN THE LOCK." ;
        : destroy "stone_key" ;
     }
     on_open {
        : set_graphic graphic = "castle_approach_2a" target = "castle_approach_2" ;
        : redescribe ;
     }
     on_close {
        : set_graphic graphic = "castle_approach_2"  target = "castle_approach_2" ;
        : redescribe ;
     }
   }

   tree : block {
      location            = top_of_tree
      message             = YOU CAN'T FIND YOUR GRIP
      block_when_not      = is_ladder_standing
   }

   knight : block {
      location            = castle_approach_1
      gosub               = lose_fight
      block_when_exists   = demon_knight
      show_blocked_exit   = true
   }

   trapdoor : block {
      location            = salt_mine_1
      message             = THE TRAPDOOR IS JAMMED SHUT!
      block_when_exists   = trapdoor
   }

   worm : block {
      location            = salt_mine_3
      gosub               = worm_attack
      block_when_exists   = rockworm
      show_blocked_exit   = true
   }

   ice_creature : block {
      location            = winch_room
      message             = THE ICE CREATURE WILL NOT ALLOW IT ...
      block_when_exists   = ice_creature
      show_blocked_exit   = true
   }

}

########################################
#  On Describe                         #
########################################

on_describe {
   : if (is_light_lit) {
      : print "THE LIGHT'S GONE OUT." ;
      : set_false "is_light_lit" ;
   }
}

########################################
#  On Describe                         #
########################################

on_tick {
   : if (is_present "rockworm" ) {
      : if (linger() == 3) {
         : print "THE ROCKWORM STARTS MOVING TOWARDS YOU" ;
      }
      : if (linger() == 4) {
         : gosub "worm_attack" ;
      }
   }
   : if (is_present "ice_creature") {
     : if (linger() == 1) {
        : print "THE ICE CREATURE TAKES YOU IN A FREEZING GRIP" ;
        : gosub "end_game" ;
     }
   }
}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

    : match "fight knight;attack knight;challenge knight"  {
      : if (is_present "demon_knight") {
         : if (is_carried "short_sword") {
            : gosub "win_fight" ;
         }
         : else {
            : gosub "lose_fight" ;
         }
      }
    }

    : match "break ladder;smash ladder;disassemble ladder"  {
       : if (is_carried "ladder") {
          : print   "OK."       ;
          : destroy "ladder"    ;
          : create  "long_pole" ;
          : create  "rungs"     ;
          : press_any_key       ;
          : redescribe          ;
       }
    }

    : match "cross chasm; balance _; walk _"  {
      : if (is_at "chasm" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "edge_of_birwood" ;
         : redescribe ;
      }
      : if (is_at "chasm" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
      : if (is_at "edge_of_birwood" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "chasm" ;
         : redescribe ;
      }
      : if (is_at "edge_of_birwood" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
    }

   : match "give coin; buy lamp"  {
     : if (is_present "old_woman") {
        : if (is_carried "coin") {
           : print "THE OLD LADY TAKES YOUR COIN, GIVES YOU A BRASS LAMP, THEN DISAPPEARS INTO THIN AIR." ;
           : destroy "coin" ;
           : destroy "old_woman" ;
           : create "lamp" target="inventory" ;
           : set_graphic graphic = "lamp_seller_on_road_2"  target = "lamp_seller_on_road" ;
           : press_any_key ;
           : redescribe ;
        }
        : else {
           : match "buy lamp"  {
              : print "'CROSS MY PALM WITH SILVER!'" ;
           }
        }
     }
   }


   : match "smash trapdoor;chop trapdoor;break trapdoor"  {
     : if (is_present "trapdoor") {
        : if (is_carried "axe") {
           : print "USING THE AXE, YOU SMASH THE TRAPDOOR!" ;
           : destroy "trapdoor" ;
           : create "smashed_trapdoor" ;
   		   : destroy "axe" ;
           : set_graphic target = "drafty_room" graphic = "drafty_room_2" ;
           : pause "1600" ;
           : redescribe ;
        }
        : else {
           : print "A FRUITLESS EXERCISE!" ;
           : done ;
        }
     }
   }

   : match "light lamp; switch lamp; turn lamp"  {
     : if (is_present "lamp" && is_light_lit == false) {
       : set_true "is_light_lit" ;
       : if (is_present "rockworm") {
          : print "THE ROCKWORM'S SENSITIVE EYES ARE SURPRISED BY THE STRONG LIGHT AND IT RETREATS DOWN ITS BURROW ...." ;
          : destroy "rockworm" ;
          : set_graphic target = "worm_room" graphic = "worm_room_2" ;
          : press_any_key ;
          : redescribe ;
       }
       : else {
          : print "IT EMITS A BRIGHT LIGHT." ;
       }
     }
   }

   : match "throw salt"  {
      : if (is_present "ice_creature") {
         : if (is_carried "salt") {
            : print "THE CREATURE BEGINS TO MELT RAPIDLY..." ;
            : destroy "ice_creature" ;
      	    : destroy "salt" ;
            : set_graphic target = "cold_room" graphic = "cold_room_2" ;
            : press_any_key ;
            : redescribe ;
         }
         : else {
            : print "YOU DON'T HAVE ANY." ;
         }
      }
      : else {
         : print "NOT RIGHT NOW." ;
      }
   }

}


########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2"  target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over";
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }

   worm_attack : subroutine {
     : print "THE ROCKWORM RISES UP AND TAKES YOU IN ITS GLEAMING MANDIBLES." ;
     : gosub "end_game" ;
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

6.15. Raising The Portcullis

winch room

The Winch Room contains the winch that will raise (open) the portcullis leading to Crania and Arthur.

The portcullis (a kind of gate/door that goes up and down). The portcullis is in a different room to the winch.

There are two 'puzzles' here.

The first 'puzzle' is that the winch is jammed and needs some oil.

Lucky for the player that there is a can of oil in the room where the ice creature met its salty demise.

How very convenient !

The second part of the puzzle is simply to turn the winch.

Turning the winch will remove the block on the most splendid room and change the graphic in the portcullis room to show an open door instead of a closed portcullis.

Isn’t programming neat?

Firstly, we will use two boolean variables.

At the start of the game we have not oiled or turned the winch, so they are both set to a value of false initially.

booleans {}
has_oiled_winch  : boolean "false" ;
has_turned_winch : boolean "false" ;

Next, let’s make a block for the most splendid room (which is north of the portcullis room). The block is a simple block that displays the message "YOU CAN’T GO THAT WAY.".

This block uses the 'block_when_not' condition, which means, block when a boolean variable contains a 'false' value.

It’s easy to understand if we read it like we see it (even though it is slightly strange english:

  • block when not has turned winch.

barriers {}
portcullis : block {
   location               = most_splendid_room
   message                = YOU CAN'T GO THAT WAY.
   block_when_not         = has_turned_winch
}

Finally, let’s wire up the command handler for OIL WINCH and TURN WINCH:

on_command {}
: match "oil winch"  {
   : if (is_present "winch") {
      : if (is_carried "oil") {
         : print "OK." ;
         : set_true "has_oiled_winch" ;
         : set_graphic target = "portcullis" graphic = "portcullis_2" ;
         : destroy "oil" ;
      }
      : else {
         : print "YOU HAVE NO OIL!" ;
      }
   }
   : else {
      : print "IT ISN'T HERE" ;
   }
}

: match "turn winch"  {
   : if (is_present "winch") {
      : if (has_oiled_winch) {
         : print "OK." ;
         : set_true "has_turned_winch" ;
      }
      : else {
         : print "IT'S STUCK!" ;
      }
   }
   : else {
      : print "IT ISN'T HERE" ;
   }
}

6.15.1. Using Boolean Variables within an 'if' condition

This block of code uses multiple if then else blocks of code, and it also shows the use of a boolean variable inside an if statement.

We can perform an conditional action based on if a boolean variable (or boolean expression) contains a true (or yes) answer, or a false (or no) answer.

6.15.2. How To Name Boolean Variables

It is usual in Adventuron is to name boolean variables starting with is_ or has_ because it makes it easier to understand what that the variable represents a true/false or yes/no answer.

Imagine that the has_oiled_winch boolean variable was called oiled_winch. It would be difficult to know if the identifier represented a fact (such as something is true or false), or an object.

The way we choose to name something is called a naming convention. These are are very common in programming, and it really makes things a lot easier if you follow a pattern - even if the pattern is unique to yourself.

6.15.3. Code so far …​.

########################################
#  Adventuron                          #
########################################

start_at       = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      //chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false" ;
   is_light_lit       : boolean "false" ;
   has_oiled_winch    : boolean "false" ;
   has_turned_winch   : boolean "false" ;
}

########################################
#  Blocks                              #
########################################

barriers {

   castle_door : door {
     key   = stone_key
     from  = castle_approach_2
     to    = castle_porch
     on_unlock {
        : print "YOU UNLOCK IT WITH THE KEY, WHICH JAMS IN THE LOCK." ;
        : destroy "stone_key" ;
     }
     on_open {
        : set_graphic graphic = "castle_approach_2a" target = "castle_approach_2" ;
        : redescribe ;
     }
     on_close {
        : set_graphic graphic = "castle_approach_2"  target = "castle_approach_2" ;
        : redescribe ;
     }
   }

   tree : block {
      location            = top_of_tree
      message             = YOU CAN'T FIND YOUR GRIP
      block_when_not      = is_ladder_standing
   }

   knight : block {
      location            = castle_approach_1
      gosub               = lose_fight
      block_when_exists   = demon_knight
      show_blocked_exit   = true
   }

   trapdoor : block {
      location            = salt_mine_1
      message             = THE TRAPDOOR IS JAMMED SHUT!
      block_when_exists   = trapdoor
   }

   worm : block {
      location            = salt_mine_3
      gosub               = worm_attack
      block_when_exists   = rockworm
      show_blocked_exit   = true
   }

   ice_creature : block {
      location            = winch_room
      message             = THE ICE CREATURE WILL NOT ALLOW IT ...
      block_when_exists   = ice_creature
      show_blocked_exit   = true
   }

   portcullis : block {
      location               = most_splendid_room
      message                = YOU CAN'T GO THAT WAY.
      block_when_not         = has_turned_winch
   }

}

########################################
#  On Describe                         #
########################################

on_describe {
   : if (is_light_lit) {
      : print "THE LIGHT'S GONE OUT." ;
      : set_false "is_light_lit" ;
   }
}

########################################
#  On Describe                         #
########################################

on_tick {
   : if (is_present "rockworm" ) {
      : if (linger() == 3) {
         : print "THE ROCKWORM STARTS MOVING TOWARDS YOU" ;
      }
      : if (linger() == 4) {
         : gosub "worm_attack" ;
      }
   }
   : if (is_present "ice_creature") {
     : if (linger() == 1) {
        : print "THE ICE CREATURE TAKES YOU IN A FREEZING GRIP" ;
        : gosub "end_game" ;
     }
   }
}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

    : match "fight knight;attack knight;challenge knight"  {
      : if (is_present "demon_knight") {
         : if (is_carried "short_sword") {
            : gosub "win_fight" ;
         }
         : else {
            : gosub "lose_fight" ;
         }
      }
    }

    : match "break ladder;smash ladder;disassemble ladder"  {
       : if (is_carried "ladder") {
          : print   "OK."       ;
          : destroy "ladder"    ;
          : create  "long_pole" ;
          : create  "rungs"     ;
          : press_any_key       ;
          : redescribe          ;
       }
    }

    : match "cross chasm; balance _; walk _"  {
      : if (is_at "chasm" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "edge_of_birwood" ;
         : redescribe ;
      }
      : if (is_at "chasm" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
      : if (is_at "edge_of_birwood" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "chasm" ;
         : redescribe ;
      }
      : if (is_at "edge_of_birwood" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
    }

   : match "give coin; buy lamp"  {
     : if (is_present "old_woman") {
        : if (is_carried "coin") {
           : print "THE OLD LADY TAKES YOUR COIN, GIVES YOU A BRASS LAMP, THEN DISAPPEARS INTO THIN AIR." ;
           : destroy "coin" ;
           : destroy "old_woman" ;
           : create "lamp" target="inventory" ;
           : set_graphic graphic = "lamp_seller_on_road_2"  target = "lamp_seller_on_road" ;
           : press_any_key ;
           : redescribe ;
        }
        : else {
           : match "buy lamp"  {
              : print "'CROSS MY PALM WITH SILVER!'" ;
           }
        }
     }
   }


   : match "smash trapdoor;chop trapdoor;break trapdoor"  {
     : if (is_present "trapdoor") {
        : if (is_carried "axe") {
           : print "USING THE AXE, YOU SMASH THE TRAPDOOR!" ;
           : destroy "trapdoor" ;
           : create "smashed_trapdoor" ;
   		   : destroy "axe" ;
           : set_graphic target = "drafty_room" graphic = "drafty_room_2" ;
           : pause "1600" ;
           : redescribe ;
        }
        : else {
           : print "A FRUITLESS EXERCISE!" ;
           : done ;
        }
     }
   }

   : match "light lamp; switch lamp; turn lamp"  {
     : if (is_present "lamp" && is_light_lit == false) {
       : set_true "is_light_lit" ;
       : if (is_present "rockworm") {
          : print "THE ROCKWORM'S SENSITIVE EYES ARE SURPRISED BY THE STRONG LIGHT AND IT RETREATS DOWN ITS BURROW ...." ;
          : destroy "rockworm" ;
          : set_graphic target = "worm_room" graphic = "worm_room_2" ;
          : press_any_key ;
          : redescribe ;
       }
       : else {
          : print "IT EMITS A BRIGHT LIGHT." ;
       }
     }
   }

   : match "throw salt"  {
      : if (is_present "ice_creature") {
         : if (is_carried "salt") {
            : print "THE CREATURE BEGINS TO MELT RAPIDLY..." ;
            : destroy "ice_creature" ;
      	    : destroy "salt" ;
            : set_graphic target = "cold_room" graphic = "cold_room_2" ;
            : press_any_key ;
            : redescribe ;
         }
         : else {
            : print "YOU DON'T HAVE ANY." ;
         }
      }
      : else {
         : print "NOT RIGHT NOW." ;
      }
   }

   : match "oil winch"  {
      : if (is_present "winch") {
         : if (is_carried "oil") {
            : print "OK." ;
            : set_true "has_oiled_winch" ;
            : set_graphic target = "portcullis" graphic = "portcullis_2" ;
            : destroy "oil" ;
         }
         : else {
            : print "YOU HAVE NO OIL!" ;
         }
      }
      : else {
         : print "IT ISN'T HERE" ;
      }
   }

   : match "turn winch"  {
      : if (is_present "winch") {
         : if (has_oiled_winch) {
            : print "OK." ;
            : set_true "has_turned_winch" ;
         }
         : else {
            : print "IT'S STUCK!" ;
         }
      }
      : else {
         : print "IT ISN'T HERE" ;
      }
   }

}


########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2"  target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over" ;
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }

   worm_attack : subroutine {
     : print "THE ROCKWORM RISES UP AND TAKES YOU IN ITS GLEAMING MANDIBLES." ;
     : gosub "end_game" ;
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

6.16. Reflecting The Spell

most splendid room

Now that the portcullis is up, we have access to the MOST SPLENDID ROOM, which is a yellow version of a regular room - but this one has CRANIA, THE EVIL SORCERESS in it, and she’s throwing a spell your way.

We deal with the spell by typing REFLECT SPELL or DEFLECT SPELL whilst holding the sword, EXCALIBUR, which was in the armoury next to the winch room.

If you type those magic words, then the spell will be reflected back at CRANIA, and the room is then clear.

This is very easy to write the code for, it’s basically the same logic as the Ice Creature.

  1. Create the location block

  2. Create the command Handler

  3. Create the sudden-death timer

barriers {}
crania : block {
   location            = arthur
   message             = YOU CAN'T GET PAST
   block_when_exists   = spell
}
on_command{}
: match "reflect spell; deflect spell; use excalibur"  {
   : if (is_present "spell") {
      : if (is_carried "excalibur") {
         : print "EXCALIBUR REFLECTS THE SPELL! THE SORCERESS, PROMISING REVENGE, VANISHES!" ;
         : destroy "spell" ;
         : set_graphic  target = "most_splendid_room" graphic = "most_splendid_room_2";
         : press_any_key ;
         : redescribe ;
      }
      : else {
         : print "YOU WAVE YOUR HANDS BUT IT'S NO GOOD..." ;
      }
   }
   : else {
      : print "YOU CAN'T." ;
   }
}
on_tick{}
: if (is_present "spell") {
   : if (linger() == 1) {
      : print "THE SPELL HITS YOU HEAD ON, PETRIFYING YOU INSTANTLY." ;
      : gosub "end_game" ;
   }
}
########################################
#  Adventuron                          #
########################################

start_at       = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      //chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false" ;
   is_light_lit       : boolean "false" ;
   has_oiled_winch    : boolean "false" ;
   has_turned_winch   : boolean "false" ;
}

########################################
#  Blocks                              #
########################################

barriers {

   castle_door : door {
     key   = stone_key
     from  = castle_approach_2
     to    = castle_porch
     on_unlock {
        : print "YOU UNLOCK IT WITH THE KEY, WHICH JAMS IN THE LOCK." ;
        : destroy "stone_key" ;
     }
     on_open {
        : set_graphic graphic = "castle_approach_2a" target = "castle_approach_2" ;
        : redescribe ;
     }
     on_close {
        : set_graphic graphic = "castle_approach_2"  target = "castle_approach_2" ;
        : redescribe ;
     }
   }

   tree : block {
      location            = top_of_tree
      message             = YOU CAN'T FIND YOUR GRIP
      block_when_not      = is_ladder_standing
   }

   knight : block {
      location            = castle_approach_1
      gosub               = lose_fight
      block_when_exists   = demon_knight
      show_blocked_exit   = true
   }

   trapdoor : block {
      location            = salt_mine_1
      message             = THE TRAPDOOR IS JAMMED SHUT!
      block_when_exists   = trapdoor
   }

   worm : block {
      location            = salt_mine_3
      gosub               = worm_attack
      block_when_exists   = rockworm
      show_blocked_exit   = true
   }

   ice_creature : block {
      location            = winch_room
      message             = THE ICE CREATURE WILL NOT ALLOW IT ...
      block_when_exists   = ice_creature
      show_blocked_exit   = true
   }

   portcullis : block {
      location            = most_splendid_room
      message             = YOU CAN'T GO THAT WAY.
      block_when_not      = has_turned_winch
   }

   crania : block {
      location            = arthur
      message             = YOU CAN'T GET PAST
      block_when_exists   = spell
   }

}

########################################
#  On Describe                         #
########################################

on_describe {
   : if (is_light_lit) {
      : print "THE LIGHT'S GONE OUT." ;
      : set_false "is_light_lit" ;
   }
}

########################################
#  On Describe                         #
########################################

on_tick {
   : if (is_present "rockworm" ) {
      : if (linger() == 3) {
         : print "THE ROCKWORM STARTS MOVING TOWARDS YOU" ;
      }
      : if (linger() == 4) {
         : gosub "worm_attack" ;
      }
   }
   : if (is_present "ice_creature") {
     : if (linger() == 1) {
        : print "THE ICE CREATURE TAKES YOU IN A FREEZING GRIP" ;
        : gosub "end_game" ;
     }
   }
   : if (is_present "spell") {
      : if (linger() == 1) {
         : print "THE SPELL HITS YOU HEAD ON, PETRIFYING YOU INSTANTLY." ;
         : gosub "end_game" ;
      }
   }
}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

    : match "fight knight;attack knight;challenge knight"  {
      : if (is_present "demon_knight") {
         : if (is_carried "short_sword") {
            : gosub "win_fight" ;
         }
         : else {
            : gosub "lose_fight" ;
         }
      }
    }

    : match "break ladder;smash ladder;disassemble ladder"  {
       : if (is_carried "ladder") {
          : print   "OK."       ;
          : destroy "ladder"    ;
          : create  "long_pole" ;
          : create  "rungs"     ;
          : press_any_key       ;
          : redescribe          ;
       }
    }

    : match "cross chasm; balance _; walk _"  {
      : if (is_at "chasm" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "edge_of_birwood" ;
         : redescribe ;
      }
      : if (is_at "chasm" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
      : if (is_at "edge_of_birwood" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "chasm" ;
         : redescribe ;
      }
      : if (is_at "edge_of_birwood" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
    }

   : match "give coin; buy lamp"  {
     : if (is_present "old_woman") {
        : if (is_carried "coin") {
           : print "THE OLD LADY TAKES YOUR COIN, GIVES YOU A BRASS LAMP, THEN DISAPPEARS INTO THIN AIR." ;
           : destroy "coin" ;
           : destroy "old_woman" ;
           : create "lamp" target="inventory" ;
           : set_graphic graphic = "lamp_seller_on_road_2"  target = "lamp_seller_on_road" ;
           : press_any_key ;
           : redescribe ;
        }
        : else {
           : match "buy lamp"  {
              : print "'CROSS MY PALM WITH SILVER!'" ;
           }
        }
     }
   }


   : match "smash trapdoor;chop trapdoor;break trapdoor"  {
     : if (is_present "trapdoor") {
        : if (is_carried "axe") {
           : print "USING THE AXE, YOU SMASH THE TRAPDOOR!" ;
           : destroy "trapdoor" ;
           : create "smashed_trapdoor" ;
   		   : destroy "axe" ;
           : set_graphic target = "drafty_room" graphic = "drafty_room_2" ;
           : pause "1600" ;
           : redescribe ;
        }
        : else {
           : print "A FRUITLESS EXERCISE!" ;
           : done ;
        }
     }
   }

   : match "light lamp; switch lamp; turn lamp"  {
     : if (is_present "lamp" && is_light_lit == false) {
       : set_true "is_light_lit" ;
       : if (is_present "rockworm") {
          : print "THE ROCKWORM'S SENSITIVE EYES ARE SURPRISED BY THE STRONG LIGHT AND IT RETREATS DOWN ITS BURROW ...." ;
          : destroy "rockworm" ;
          : set_graphic target = "worm_room" graphic = "worm_room_2" ;
          : press_any_key ;
          : redescribe ;
       }
       : else {
          : print "IT EMITS A BRIGHT LIGHT." ;
       }
     }
   }

   : match "throw salt"  {
      : if (is_present "ice_creature") {
         : if (is_carried "salt") {
            : print "THE CREATURE BEGINS TO MELT RAPIDLY..." ;
            : destroy "ice_creature" ;
      	    : destroy "salt" ;
            : set_graphic target = "cold_room" graphic = "cold_room_2" ;
            : press_any_key ;
            : redescribe ;
         }
         : else {
            : print "YOU DON'T HAVE ANY." ;
         }
      }
      : else {
         : print "NOT RIGHT NOW." ;
      }
   }

   : match "oil winch"  {
      : if (is_present "winch") {
         : if (is_carried "oil") {
            : print "OK." ;
            : set_true "has_oiled_winch" ;
            : set_graphic target = "portcullis" graphic = "portcullis_2" ;
            : destroy "oil" ;
         }
         : else {
            : print "YOU HAVE NO OIL!" ;
         }
      }
      : else {
         : print "IT ISN'T HERE" ;
      }
   }

   : match "turn winch"  {
      : if (is_present "winch") {
         : if (has_oiled_winch) {
            : print "OK." ;
            : set_true "has_turned_winch" ;
         }
         : else {
            : print "IT'S STUCK!" ;
         }
      }
      : else {
         : print "IT ISN'T HERE" ;
      }
   }

   : match "reflect spell; deflect spell; use excalibur"  {
      : if (is_present "spell") {
         : if (is_carried "excalibur") {
            : print "EXCALIBUR REFLECTS THE SPELL! THE SORCERESS, PROMISING REVENGE, VANISHES!" ;
            : destroy "spell" ;
            : set_graphic  target = "most_splendid_room" graphic = "most_splendid_room_2";
            : press_any_key ;
            : redescribe ;
         }
         : else {
            : print "YOU WAVE YOUR HANDS BUT IT'S NO GOOD..." ;
         }
      }
      : else {
         : print "YOU CAN'T." ;
      }
   }

}


########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2"  target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over" ;
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }

   worm_attack : subroutine {
     : print "THE ROCKWORM RISES UP AND TAKES YOU IN ITS GLEAMING MANDIBLES." ;
     : gosub "end_game" ;
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

6.17. Waking Arthur

arthur

6.17.1. Wake Up !

Waking Arthur is a very simple puzzle. Arthur is asleep, the obvious action is to try to wake him. Typing WAKE ARTHUR or WAKE KING should show the ending screen of the game (good ending), then end the game.

on_command{}
: match "wake arthur; wake king"  {
  : if (is_present "asleep_arthur") {
     : clear_screen;
     : print_graphic "ending_screen";
     : end_game ;
  }
}

6.17.2. Ending Screen

The ending screen is a graphic (in PNG format).

If you are building your own game, you can construct a textual message, or make your own ending graphic.

ending screen

6.17.3. A Completable Game

All puzzles have now been coded, and the game is now fully playable.

There are still some minor tasks to perform to make the experience better for the player, and to package the game, but it’s time to take a rest and enjoy what you have achieved so far.

6.17.4. Code So Far

########################################
#  Adventuron                          #
########################################

start_at       = hut

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      //chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false" ;
   is_light_lit       : boolean "false" ;
   has_oiled_winch    : boolean "false" ;
   has_turned_winch   : boolean "false" ;
}

########################################
#  Blocks                              #
########################################

barriers {

   castle_door : door {
     key   = stone_key
     from  = castle_approach_2
     to    = castle_porch
     on_unlock {
        : print "YOU UNLOCK IT WITH THE KEY, WHICH JAMS IN THE LOCK." ;
        : destroy "stone_key" ;
     }
     on_open {
        : set_graphic graphic = "castle_approach_2a" target = "castle_approach_2" ;
        : redescribe ;
     }
     on_close {
        : set_graphic graphic = "castle_approach_2"  target = "castle_approach_2" ;
        : redescribe ;
     }
   }

   tree : block {
      location            = top_of_tree
      message             = YOU CAN'T FIND YOUR GRIP
      block_when_not      = is_ladder_standing
   }

   knight : block {
      location            = castle_approach_1
      gosub               = lose_fight
      block_when_exists   = demon_knight
      show_blocked_exit   = true
   }

   trapdoor : block {
      location            = salt_mine_1
      message             = THE TRAPDOOR IS JAMMED SHUT!
      block_when_exists   = trapdoor
   }

   worm : block {
      location            = salt_mine_3
      gosub               = worm_attack
      block_when_exists   = rockworm
      show_blocked_exit   = true
   }

   ice_creature : block {
      location            = winch_room
      message             = THE ICE CREATURE WILL NOT ALLOW IT ...
      block_when_exists   = ice_creature
      show_blocked_exit   = true
   }

   portcullis : block {
      location            = most_splendid_room
      message             = YOU CAN'T GO THAT WAY.
      block_when_not      = has_turned_winch
   }

   crania : block {
      location            = arthur
      message             = YOU CAN'T GET PAST
      block_when_exists   = spell
   }

}

########################################
#  On Describe                         #
########################################

on_describe {
   : if (is_light_lit) {
      : print "THE LIGHT'S GONE OUT." ;
      : set_false "is_light_lit" ;
   }
}

########################################
#  On Describe                         #
########################################

on_tick {
   : if (is_present "rockworm" ) {
      : if (linger() == 3) {
         : print "THE ROCKWORM STARTS MOVING TOWARDS YOU" ;
      }
      : if (linger() == 4) {
         : gosub "worm_attack" ;
      }
   }
   : if (is_present "ice_creature") {
     : if (linger() == 1) {
        : print "THE ICE CREATURE TAKES YOU IN A FREEZING GRIP" ;
        : gosub "end_game" ;
     }
   }
   : if (is_present "spell") {
      : if (linger() == 1) {
         : print "THE SPELL HITS YOU HEAD ON, PETRIFYING YOU INSTANTLY." ;
         : gosub "end_game" ;
      }
   }
}

########################################
#  On Command                          #
########################################

on_command {
   : match "examine ladder"  {
      : if ( is_present "ladder" ) {
         : print "A LONG POLE WITH RUNGS ATTACHED." ;
      }
   }
   : match "examine woman"  {
      : if (is_present "old_woman") {
         : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ;
      }
   }
   : match "examine lamp"  {
      : if (is_present "lamp") {
         : print "IT'S OLD AND TARNISHED." ;
      }
   }
   : match "examine fish"  {
      : if (is_present "red_fish") {
         : print "IT STINKS!" ;
      }
   }
   : match "examine sword"  {
      : if (is_present "short_sword") {
         : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ;
      }
   }
   : match "examine bush"  {
      : if (is_present "bush" && has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }
   : match "examine logs"  {
      : if (is_present "logs" && has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

    : match "fight knight;attack knight;challenge knight"  {
      : if (is_present "demon_knight") {
         : if (is_carried "short_sword") {
            : gosub "win_fight" ;
         }
         : else {
            : gosub "lose_fight" ;
         }
      }
    }

    : match "break ladder;smash ladder;disassemble ladder"  {
       : if (is_carried "ladder") {
          : print   "OK."       ;
          : destroy "ladder"    ;
          : create  "long_pole" ;
          : create  "rungs"     ;
          : press_any_key       ;
          : redescribe          ;
       }
    }

    : match "cross chasm; balance _; walk _"  {
      : if (is_at "chasm" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "edge_of_birwood" ;
         : redescribe ;
      }
      : if (is_at "chasm" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
      : if (is_at "edge_of_birwood" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "chasm" ;
         : redescribe ;
      }
      : if (is_at "edge_of_birwood" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
    }

   : match "give coin; buy lamp"  {
     : if (is_present "old_woman") {
        : if (is_carried "coin") {
           : print "THE OLD LADY TAKES YOUR COIN, GIVES YOU A BRASS LAMP, THEN DISAPPEARS INTO THIN AIR." ;
           : destroy "coin" ;
           : destroy "old_woman" ;
           : create "lamp" target="inventory" ;
           : set_graphic graphic = "lamp_seller_on_road_2"  target = "lamp_seller_on_road" ;
           : press_any_key ;
           : redescribe ;
        }
        : else {
           : match "buy lamp"  {
              : print "'CROSS MY PALM WITH SILVER!'" ;
           }
        }
     }
   }


   : match "smash trapdoor;chop trapdoor;break trapdoor"  {
     : if (is_present "trapdoor") {
        : if (is_carried "axe") {
           : print "USING THE AXE, YOU SMASH THE TRAPDOOR!" ;
           : destroy "trapdoor" ;
           : create "smashed_trapdoor" ;
   		   : destroy "axe" ;
           : set_graphic target = "drafty_room" graphic = "drafty_room_2" ;
           : pause "1600" ;
           : redescribe ;
        }
        : else {
           : print "A FRUITLESS EXERCISE!" ;
           : done ;
        }
     }
   }

   : match "light lamp; switch lamp; turn lamp"  {
     : if (is_present "lamp" && is_light_lit == false) {
       : set_true "is_light_lit" ;
       : if (is_present "rockworm") {
          : print "THE ROCKWORM'S SENSITIVE EYES ARE SURPRISED BY THE STRONG LIGHT AND IT RETREATS DOWN ITS BURROW ...." ;
          : destroy "rockworm" ;
          : set_graphic target = "worm_room" graphic = "worm_room_2" ;
          : press_any_key ;
          : redescribe ;
       }
       : else {
          : print "IT EMITS A BRIGHT LIGHT." ;
       }
     }
   }

   : match "throw salt"  {
      : if (is_present "ice_creature") {
         : if (is_carried "salt") {
            : print "THE CREATURE BEGINS TO MELT RAPIDLY..." ;
            : destroy "ice_creature" ;
      	    : destroy "salt" ;
            : set_graphic target = "cold_room" graphic = "cold_room_2" ;
            : press_any_key ;
            : redescribe ;
         }
         : else {
            : print "YOU DON'T HAVE ANY." ;
         }
      }
      : else {
         : print "NOT RIGHT NOW." ;
      }
   }

   : match "oil winch"  {
      : if (is_present "winch") {
         : if (is_carried "oil") {
            : print "OK." ;
            : set_true "has_oiled_winch" ;
            : set_graphic target = "portcullis" graphic = "portcullis_2" ;
            : destroy "oil" ;
         }
         : else {
            : print "YOU HAVE NO OIL!" ;
         }
      }
      : else {
         : print "IT ISN'T HERE" ;
      }
   }

   : match "turn winch"  {
      : if (is_present "winch") {
         : if (has_oiled_winch) {
            : print "OK." ;
            : set_true "has_turned_winch" ;
         }
         : else {
            : print "IT'S STUCK!" ;
         }
      }
      : else {
         : print "IT ISN'T HERE" ;
      }
   }

   : match "reflect spell; deflect spell; use excalibur"  {
      : if (is_present "spell") {
         : if (is_carried "excalibur") {
            : print "EXCALIBUR REFLECTS THE SPELL! THE SORCERESS, PROMISING REVENGE, VANISHES!" ;
            : destroy "spell" ;
            : set_graphic  target = "most_splendid_room" graphic = "most_splendid_room_2";
            : press_any_key ;
            : redescribe ;
         }
         : else {
            : print "YOU WAVE YOUR HANDS BUT IT'S NO GOOD..." ;
         }
      }
      : else {
         : print "YOU CAN'T." ;
      }
   }

   : match "wake arthur; wake king"  {
      : if (is_present "asleep_arthur") {
         : clear_screen;
         : print_graphic "ending_screen";
         : end_game ;
      }
   }

}


########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2"  target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over" ;
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }

   worm_attack : subroutine {
     : print "THE ROCKWORM RISES UP AND TAKES YOU IN ITS GLEAMING MANDIBLES." ;
     : gosub "end_game" ;
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

7. Final Steps

7.1. Adding Polish

7.1.1. Some More Examine Commands

The fish is found early on in the game, and the player might naturally try to eat the fish. This response checks to see if the fish is present (present means in the same scene or held in the players hands). If the fish is present, and if "EAT FISH" is submitted as a comant, then it’s game over. The fish is rotten.

: match "eat fish"  {
   : if (is_present "red_fish") {
      : print "UHGH! THIS FISH IS ROTTEN!\nYOU START TO GET STOMACH PAINS." ;
      : gosub "end_game" ;
   }
}

7.1.2. Adding an intro tune

Adding an intro tune is a matter of calling a subroutine containing beeps with the correct pitches and millisecond timings when the game starts.

This action can be added at the start of the game.

Note : If using sound in your game, the game will automatically ask for consent for sound after the intro screen is shown.

on_startup {
   : gosub "intro_song" ;
}
subroutines {}
intro_song : subroutine {
  : beep millis = "256"  pitch = "0"  ;
  : beep millis = "512"  pitch = "3"  ;
  : beep millis = "256"  pitch = "5"  ;
  : beep millis = "512"  pitch = "7"  ;
  : beep millis = "256"  pitch = "8"  ;
  : beep millis = "256"  pitch = "7"  ;
  : beep millis = "512"  pitch = "5"  ;
  : beep millis = "256"  pitch = "2"  ;
  : beep millis = "512"  pitch = "-2" ;
  : beep millis = "256"  pitch = "0"  ;
  : beep millis = "256"  pitch = "2"  ;
  : beep millis = "256"  pitch = "3"  ;
  : beep millis = "256"  pitch = "2"  ;
  : beep millis = "512"  pitch = "2"  ;
  : beep millis = "256"  pitch = "7"  ;
  : beep millis = "256"  pitch = "8"  ;
  : beep millis = "256"  pitch = "3"  ;
  : beep millis = "256"  pitch = "0"  ;
}

How to write a song is a whole different subject, but pitch = 0 represents middle c, so you can experiment just by doing.

7.2. Setting up the "loading" screen

In the old days, games used to take a long time to load before you could play the game. Whilst they were loading, a graphic was displayed, to make the wait more interesting and build excitement for playing the game.

Adventuron supports an image such as this - an image to be displayed, before the player clicks the screen or touches the keyboard for the first time.

To set up an loading screen, it’s very simple.

We go to a blank line at the "root" level of the source code, then press CONTROL + SPACE, then select "loading_screen".

loading_screen = excalibur_loading

After doing this, pressing the "play" button, will display the loading screen instead of the ADVENTURON logo.

excalibur loading

7.2.1. Advanced Customisation

This section is to be complete pending version 1.0 of Adventuron …​

7.2.2. The 'if_examine' Command

So far we have just used the 'match' command to check for verbs and nouns, but as examine commands are very common, there also exists an 'if_examine' command, which requires the identifier of an object.

How to examine the fish with the 'match' command
: match "examine fish"  {
  : if (is_present "red_fish") {
     : print "IT STINKS!" ;
  }
}
How to examine a ladder with the 'examine' command
: if_examine "red_fish" {
   : print "IT STINKS!" ;
}

The examine command doesn’t require a check for if the object is present, and it doesn’t require a verb. It expects the identifier of an object.

It will automatically know which noun and verb to match from the id of the object.

We can now replace all our examine messages like this:

on_command {

: if_examine "ladder"       { : print "A LONG POLE WITH RUNGS ATTACHED." ; }
: if_examine "old_woman"    { : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ; }
: if_examine "lamp"         { : print "IT'S OLD AND TARNISHED." ; }
: if_examine "red_fish" { : print "IT STINKS!" ; }
: if_examine "short_sword"  { : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ; }
: if_examine "bush" {
   : if (has_not_created "stone_key") {
      : print "YOU FIND SOMETHING!" ;
      : create "stone_key" ;
      : press_any_key ;
      : redescribe ;
   }
}
: if_examine "logs" {
   : if (has_not_created "axe") {
      : print "YOU FIND AN AXE!" ;
      : create "axe" ;
      : press_any_key ;
      : redescribe ;
   }
}

/// Other commands here

}

7.2.3. Code So Far

########################################
#  Adventuron                          #
########################################

start_at       = hut
loading_screen = excalibur_loading

########################################
#  Locations                           #
########################################

locations {

   hut                    : location "You are in an old hut. Sunlight shines in from a doorway to the north.";
   road_1                 : location "You are standing on a track. The hut is south.";
   road_2                 : location "You are where the road turns eastwards. You see small hills in the distance.";
   road_3                 : location "You are on a road surrounded by grass. Trees can be seen on a hill in the distance.";
   road_4                 : location "You are on a dusty path on the edge of Birwood.";
   lamp_seller_on_road    : location "You are at a crossroads.";
   chasm                  : location "You are stood on the edge of a huge chasm (a cliff). A tightrope spans the gap, but it looks dangerous.";
   edge_of_birwood        : location "You are on the edge of Birwood. A rope spans the chasm northwards." ;
   deep_inside_birwood    : location "You are deep inside Birwood. The trees are alive with the buzzing of tiny insects.";
   birwood_bush           : location "You are standing in Birwood. A gap in the trees lets a warm light filter through.";
   demon_knight_road      : location "You are in a dip in the road by dark Birwood. Birds can be heard above.";
   foot_of_tree           : location "You are at the bottom of a large stone tree that is bare of any branches. The road ends here.";
   top_of_tree            : location "You are in a stone room set in a large stone tree.";
   castle_approach_1      : location "You are now a fair distance from Birwood. You can see castle Camelot to the east.";
   castle_approach_2      : location "You are outside Camelot Castle. A great stone door is the only way in.";
   castle_porch           : location "You are in the porch of Camelot.";
   banquet_hall           : location "You are in an abandoned banquet hall (eating area). Furniture lays broken on the floor.";
   drafty_room            : location "You are in a drafty room. Wind blows through gaps in the walls creating howling noises.";
   ornate_antechamber     : location "You are in an antechamber covered in thin ice that even covers the paintings.";
   portcullis             : location "You are in a room which has an iron portcullis set into the northern wall.";
   salt_mine_1            : location "You are in an old salt mine. Tunnels lead to the west and south.";
   salt_mine_2            : location "You are in the west part of the mine. It looks like it's been abandoned.";
   salt_mine_3            : location "You are at the end of the mine. You can hear the drip of water.";
   worm_room              : location "You are in the south part of the mine. There been recent movement in the rocks near your feet.";
   cold_room              : location "You are in a bitterly cold room. Everything is coated in a thick layer of ice.";
   winch_room             : location "You are in the winch room.";
   armoury                : location "You are in the armoury. Empty weapon racks line the walls.";
   most_splendid_room     : location "You are in the most splendid room in the castle. Rugs and paintings adorn the floor and walls.";
   arthur                 : location "You are in a sparse and lonely room. A cold wind enters through a high window.";

}

########################################
#  Connections                         #
########################################

connections {

   from, direction, to = [
      hut,                  north,  road_1,
      road_1,               north,  road_2,
      road_2,               east,   road_3,
      road_3,               east,   road_4,
      road_4,               north,  foot_of_tree,
      road_4,               south,  lamp_seller_on_road,
      lamp_seller_on_road,  east,   demon_knight_road,
      lamp_seller_on_road,  south,  chasm,
      foot_of_tree,         up,     top_of_tree,
      //chasm,                south,  edge_of_birwood,
      edge_of_birwood,      south,  deep_inside_birwood,
      deep_inside_birwood,  west,   birwood_bush,
      demon_knight_road,    east,   castle_approach_1,
      castle_approach_1,    east,   castle_approach_2,
      castle_approach_2,    east,   castle_porch,
      castle_porch,         east,   banquet_hall,
      banquet_hall,         north,  portcullis,
      banquet_hall,         south,  drafty_room,
      portcullis,           north,  most_splendid_room,
      most_splendid_room,   west,   arthur,
      drafty_room,          east,   ornate_antechamber,
      drafty_room,          down,   salt_mine_1,
      ornate_antechamber,   east,   cold_room,
      cold_room,            north,  winch_room,
      winch_room,           east,   armoury,
      salt_mine_1,          west,   salt_mine_2,
      salt_mine_1,          south,  worm_room,
      worm_room,            south,  salt_mine_3,
   ]

}

########################################
#  Objects                             #
########################################

objects {

   # Items we can pick-up (Objects)

   ladder           : object  "a ladder"                                    start_at="hut" ;
   red_fish         : object  "a red fish"                                  start_at="road_3" ;
   short_sword      : object  "a short sword"                               start_at="top_of_tree" ;
   coin             : object  "a coin"                                      start_at="ornate_antechamber" ;
   string           : object  "some string"                                 start_at="salt_mine_2" ;
   salt             : object  "some salt"                                   start_at="salt_mine_3" ;
   oil              : object  "can of oil"                                  start_at="cold_room" ;
   excalibur        : object  "Excalibur!"                                  start_at="armoury" ;
   long_pole        : object  "a long pole" ;
   rungs            : object  "some rungs" ;
   stone_key        : object  "a stone key" ;
   axe              : object  "a wood cutters' axe" ;
   lamp             : object  "a lamp" ;

   # Things or people that we cannot pick up (Scenery)

   old_woman        : scenery "an old woman selling lamps"                  start_at="lamp_seller_on_road" ;
   logs             : scenery "a pile of logs"                              start_at="deep_inside_birwood" ;
   bush             : scenery "a bush"                                      start_at="birwood_bush" ;
   demon_knight     : scenery "a Demon Knight guarding the east road"  start_at="demon_knight_road" ;
   trapdoor         : scenery "an old trapdoor"                             start_at="drafty_room" ;
   smashed_trapdoor : scenery "a smashed trapdoor" ;
   rockworm         : scenery "a Rockworm, guarding the south tunnel"       start_at="worm_room" ;
   ice_creature     : scenery "an Ice creature, guarding the north exit"    start_at="cold_room" ;
   winch            : scenery "a winch"                                     start_at="winch_room" ;
   spell            : scenery "a spell flying at you from Crania"           start_at="most_splendid_room" ;
   asleep_arthur    : scenery "King Arthur (asleep)"                        start_at="arthur" ;

}

########################################
#  Booleans                            #
########################################

booleans {
   is_ladder_standing : boolean "false" ;
   is_light_lit       : boolean "false" ;
   has_oiled_winch    : boolean "false" ;
   has_turned_winch   : boolean "false" ;
}

########################################
#  Blocks                              #
########################################

barriers {

   castle_door : door {
     key   = stone_key
     from  = castle_approach_2
     to    = castle_porch
     on_unlock {
        : print "YOU UNLOCK IT WITH THE KEY, WHICH JAMS IN THE LOCK." ;
        : destroy "stone_key" ;
     }
     on_open {
        : set_graphic graphic = "castle_approach_2a" target = "castle_approach_2" ;
        : redescribe ;
     }
     on_close {
        : set_graphic graphic = "castle_approach_2"  target = "castle_approach_2" ;
        : redescribe ;
     }
   }

   tree : block {
      location            = top_of_tree
      message             = YOU CAN'T FIND YOUR GRIP
      block_when_not      = is_ladder_standing
   }

   knight : block {
      location            = castle_approach_1
      gosub               = lose_fight
      block_when_exists   = demon_knight
      show_blocked_exit   = true
   }

   trapdoor : block {
      location            = salt_mine_1
      message             = THE TRAPDOOR IS JAMMED SHUT!
      block_when_exists   = trapdoor
   }

   worm : block {
      location            = salt_mine_3
      gosub               = worm_attack
      block_when_exists   = rockworm
      show_blocked_exit   = true
   }

   ice_creature : block {
      location            = winch_room
      message             = THE ICE CREATURE WILL NOT ALLOW IT ...
      block_when_exists   = ice_creature
      show_blocked_exit   = true
   }

   portcullis : block {
      location            = most_splendid_room
      message             = YOU CAN'T GO THAT WAY.
      block_when_not      = has_turned_winch
   }

   crania : block {
      location            = arthur
      message             = YOU CAN'T GET PAST
      block_when_exists   = spell
   }

}

########################################
#  On Startup                          #
########################################

on_startup {
   : gosub "intro_song" ;
}

########################################
#  On Describe                         #
########################################

on_describe {
   : if (is_light_lit) {
      : print "THE LIGHT'S GONE OUT." ;
      : set_false "is_light_lit" ;
   }
}

########################################
#  On Describe                         #
########################################

on_tick {
   : if (is_present "rockworm" ) {
      : if (linger() == 3) {
         : print "THE ROCKWORM STARTS MOVING TOWARDS YOU" ;
      }
      : if (linger() == 4) {
         : gosub "worm_attack" ;
      }
   }
   : if (is_present "ice_creature") {
     : if (linger() == 1) {
        : print "THE ICE CREATURE TAKES YOU IN A FREEZING GRIP" ;
        : gosub "end_game" ;
     }
   }
   : if (is_present "spell") {
      : if (linger() == 1) {
         : print "THE SPELL HITS YOU HEAD ON, PETRIFYING YOU INSTANTLY." ;
         : gosub "end_game" ;
      }
   }
}

########################################
#  On Command                          #
########################################

on_command {

   #########################################
   ## Examine Messages
   #########################################


   : if_examine "ladder"       { : print "A LONG POLE WITH RUNGS ATTACHED." ; }
   : if_examine "old_woman"    { : print "SHE LOOKS AT YOU WITH AN INTENSE GLARE." ; }
   : if_examine "lamp"         { : print "IT'S OLD AND TARNISHED." ; }
   : if_examine "red_fish" { : print "IT STINKS!" ; }
   : if_examine "short_sword"  { : print "INSCRIBED UPON IT ARE THE WORDS 'GOOD LUCK' ~~ MERLIN." ; }

   : if_examine "bush" {
      : if (has_not_created "stone_key") {
         : print "YOU FIND SOMETHING!" ;
         : create "stone_key" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : if_examine "logs" {
      : if (has_not_created "axe") {
         : print "YOU FIND AN AXE!" ;
         : create "axe" ;
         : press_any_key ;
         : redescribe ;
      }
   }

   : match "eat fish"  {
      : if (is_present "red_fish") {
         : print "UHGH! THIS FISH IS ROTTEN!\nYOU START TO GET STOMACH PAINS." ;
         : gosub "end_game" ;
      }
   }

   : match "get ladder"  {
      : if (is_at "foot_of_tree" && is_beside "ladder") {
         : get ;
         : set_false "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree"  ;
         : redescribe ;
      }
   }

   : match "stand ladder;lean ladder;rest ladder"  {
      : if (is_carried "ladder" && is_at "foot_of_tree") {
         : drop ;
         : set_true "is_ladder_standing" ;
         : set_graphic target = "foot_of_tree" graphic = "foot_of_tree_2"  ;
         : redescribe;
      }
   }

    : match "fight knight;attack knight;challenge knight"  {
      : if (is_present "demon_knight") {
         : if (is_carried "short_sword") {
            : gosub "win_fight" ;
         }
         : else {
            : gosub "lose_fight" ;
         }
      }
    }

    : match "break ladder;smash ladder;disassemble ladder"  {
       : if (is_carried "ladder") {
          : print   "OK."       ;
          : destroy "ladder"    ;
          : create  "long_pole" ;
          : create  "rungs"     ;
          : press_any_key       ;
          : redescribe          ;
       }
    }

    : match "cross chasm; balance _; walk _"  {
      : if (is_at "chasm" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "edge_of_birwood" ;
         : redescribe ;
      }
      : if (is_at "chasm" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
      : if (is_at "edge_of_birwood" && is_carried "long_pole") {
         : print "THE POLE HELPS YOU BALANCE...." ;
         : press_any_key ;
         : goto "chasm" ;
         : redescribe ;
      }
      : if (is_at "edge_of_birwood" && !is_carried "long_pole") {
         : print "YOU LOSE YOUR BALANCE....." ;
         : gosub "end_game" ;
      }
    }

   : match "give coin; buy lamp"  {
     : if (is_present "old_woman") {
        : if (is_carried "coin") {
           : print "THE OLD LADY TAKES YOUR COIN, GIVES YOU A BRASS LAMP, THEN DISAPPEARS INTO THIN AIR." ;
           : destroy "coin" ;
           : destroy "old_woman" ;
           : create "lamp" target="inventory" ;
           : set_graphic graphic = "lamp_seller_on_road_2"  target = "lamp_seller_on_road" ;
           : press_any_key ;
           : redescribe ;
        }
        : else {
           : match "buy lamp"  {
              : print "'CROSS MY PALM WITH SILVER!'" ;
           }
        }
     }
   }


   : match "smash trapdoor;chop trapdoor;break trapdoor"  {
     : if (is_present "trapdoor") {
        : if (is_carried "axe") {
           : print "USING THE AXE, YOU SMASH THE TRAPDOOR!" ;
           : destroy "trapdoor" ;
           : create "smashed_trapdoor" ;
   		   : destroy "axe" ;
           : set_graphic target = "drafty_room" graphic = "drafty_room_2" ;
           : pause "1600" ;
           : redescribe ;
        }
        : else {
           : print "A FRUITLESS EXERCISE!" ;
           : done ;
        }
     }
   }

   : match "light lamp; switch lamp; turn lamp"  {
     : if (is_present "lamp" && is_light_lit == false) {
       : set_true "is_light_lit" ;
       : if (is_present "rockworm") {
          : print "THE ROCKWORM'S SENSITIVE EYES ARE SURPRISED BY THE STRONG LIGHT AND IT RETREATS DOWN ITS BURROW ...." ;
          : destroy "rockworm" ;
          : set_graphic target = "worm_room" graphic = "worm_room_2" ;
          : press_any_key ;
          : redescribe ;
       }
       : else {
          : print "IT EMITS A BRIGHT LIGHT." ;
       }
     }
   }

   : match "throw salt"  {
      : if (is_present "ice_creature") {
         : if (is_carried "salt") {
            : print "THE CREATURE BEGINS TO MELT RAPIDLY..." ;
            : destroy "ice_creature" ;
      	    : destroy "salt" ;
            : set_graphic target = "cold_room" graphic = "cold_room_2" ;
            : press_any_key ;
            : redescribe ;
         }
         : else {
            : print "YOU DON'T HAVE ANY." ;
         }
      }
      : else {
         : print "NOT RIGHT NOW." ;
      }
   }

   : match "oil winch"  {
      : if (is_present "winch") {
         : if (is_carried "oil") {
            : print "OK." ;
            : set_true "has_oiled_winch" ;
            : set_graphic target = "portcullis" graphic = "portcullis_2" ;
            : destroy "oil" ;
         }
         : else {
            : print "YOU HAVE NO OIL!" ;
         }
      }
      : else {
         : print "IT ISN'T HERE" ;
      }
   }

   : match "turn winch"  {
      : if (is_present "winch") {
         : if (has_oiled_winch) {
            : print "OK." ;
            : set_true "has_turned_winch" ;
         }
         : else {
            : print "IT'S STUCK!" ;
         }
      }
      : else {
         : print "IT ISN'T HERE" ;
      }
   }

   : match "reflect spell; deflect spell; use excalibur"  {
      : if (is_present "spell") {
         : if (is_carried "excalibur") {
            : print "EXCALIBUR REFLECTS THE SPELL! THE SORCERESS, PROMISING REVENGE, VANISHES!" ;
            : destroy "spell" ;
            : set_graphic  target = "most_splendid_room" graphic = "most_splendid_room_2";
            : press_any_key ;
            : redescribe ;
         }
         : else {
            : print "YOU WAVE YOUR HANDS BUT IT'S NO GOOD..." ;
         }
      }
      : else {
         : print "YOU CAN'T." ;
      }
   }

   : match "wake arthur; wake king"  {
      : if (is_present "asleep_arthur") {
         : clear_screen;
         : print_graphic "ending_screen";
         : end_game ;
      }
   }

}


########################################
#  Subroutines                         #
########################################

subroutines {

   // This subroutine is executed if we lose a fight with the knight
   lose_fight : subroutine {
      // Have to explicitly attack the knight, even if you have the sword.
      : print "THE KNIGHT WIELDS HIS SWORD DEFTLY AND ATTACKS YOU...." ;
      : gosub "end_game" ;
   }

   // This subroutine is executed if we win a fight with the knight.
   win_fight : subroutine {
      : print "A GREAT BATTLE ENSUES IN WHICH YOU ARE VICTORIOUS. THE KNIGHT TURNS TO DUST BEFORE YOUR EYES ALONG WITH YOUR SWORD!" ;
      : press_any_key ;
      : destroy "demon_knight" ;
      : destroy "short_sword" ;
      : set_graphic graphic = "demon_knight_road_2"  target = "demon_knight_road" ;
      : redescribe ;
   }

   end_game : subroutine {
      : press_any_key ;
      : clear_screen;
      : print_graphic "game_over" ;
      : print "Your quest is over .........." ;
      : turns ;
      : end_game ;
   }

   worm_attack : subroutine {
     : print "THE ROCKWORM RISES UP AND TAKES YOU IN ITS GLEAMING MANDIBLES." ;
     : gosub "end_game" ;
   }

   intro_song : subroutine {
      : print_graphic "excalibur_loading" ;
      : beep millis = "256"  pitch = "0"  ;
      : beep millis = "512"  pitch = "3"  ;
      : beep millis = "256"  pitch = "5"  ;
      : beep millis = "512"  pitch = "7"  ;
      : beep millis = "256"  pitch = "8"  ;
      : beep millis = "256"  pitch = "7"  ;
      : beep millis = "512"  pitch = "5"  ;
      : beep millis = "256"  pitch = "2"  ;
      : beep millis = "512"  pitch = "-2" ;
      : beep millis = "256"  pitch = "0"  ;
      : beep millis = "256"  pitch = "2"  ;
      : beep millis = "256"  pitch = "3"  ;
      : beep millis = "256"  pitch = "2"  ;
      : beep millis = "512"  pitch = "2"  ;
      : beep millis = "256"  pitch = "7"  ;
      : beep millis = "256"  pitch = "8"  ;
      : beep millis = "256"  pitch = "3"  ;
      : beep millis = "256"  pitch = "0"  ;
   }

}

// Placeholders used for documentation purposes only as graphic data is too large to place in document.
assets {
   graphics {
      armoury               : placeholder ;
      arthur                : placeholder ;
      banquet_hall          : placeholder ;
      birwood_bush          : placeholder ;
      castle_approach_1     : placeholder ;
      castle_approach_2     : placeholder ;
      castle_approach_2a    : placeholder ;
      castle_porch          : placeholder ;
      chasm                 : placeholder ;
      cold_room             : placeholder ;
      cold_room_2           : placeholder ;
      deep_inside_birwood   : placeholder ;
      demon_knight_road     : placeholder ;
      demon_knight_road_2   : placeholder ;
      drafty_room           : placeholder ;
      drafty_room_2         : placeholder ;
      edge_of_birwood       : placeholder ;
      ending_screen         : placeholder ;
      excalibur_loading     : placeholder ;
      foot_of_tree          : placeholder ;
      foot_of_tree_2        : placeholder ;
      game_over             : placeholder ;
      hut                   : placeholder ;
      lamp_seller_on_road   : placeholder ;
      lamp_seller_on_road_2 : placeholder ;
      most_splendid_room    : placeholder ;
      most_splendid_room_2  : placeholder ;
      ornate_antechamber    : placeholder ;
      portcullis            : placeholder ;
      portcullis_2          : placeholder ;
      road_1                : placeholder ;
      road_2                : placeholder ;
      road_3                : placeholder ;
      road_4                : placeholder ;
      salt_mine_1           : placeholder ;
      salt_mine_2           : placeholder ;
      salt_mine_3           : placeholder ;
      top_of_tree           : placeholder ;
      winch_room            : placeholder ;
      worm_room             : placeholder ;
      worm_room_2           : placeholder ;
   }
}

7.3. Packaging The Game As HTML

7.3.1. Packaging as a HTML File

Now we have a game that plays well in the Adventuron editor, it’s time to package the game as a HTML File.

To do this we must fill in the game info section.

game_information {
   game_name             = Excalibur : Sword of Kings
   game_shortname        = Excalibur
   ported_by             = xxxxx
   written_by            = Ian Smith / Shaun McClure
   copyright_message     = (C) Adventuron Software Limited
   year                  = 1987
   game_version          = 1.0.0
   short_synopsis        = Rescue King Arthur In Camelot
}

Now, click the menu button at the bottom right, then click the "Compile" option.

Adventuron will display a message, which you should read, then produce a HTML file containing the game.

When you make something new, you automatically are granted copyright. Copyright gives you the right to choose how to sell something and who is allowed to copy you.

Excalibur is copyright of Adventuron Software Limited for the purpose of using in this tutorial. Producing a HTML version is to demonstrate the feature. You are not permitted to redistribute your HTML copy of Excalibur.

7.3.3. Distributing Your Own Game

Adventuron is not licensed for commercial use, and games created with Classroom embed Adventuron into the generated HTML files.

As long as you make your own adventure that does not break the license terms, you can share HTML versions of your own creations, providing you do not charge a fee for your game.

Your packaged game will be independent of the Adventuron website, and also available to play without an internet connection. It is very important for archival purposes.

7.3.4. Adventuron Engine License (1.0.0 Prerelease)

/* ADVENTURON 1.0.0 Prerelease - NON COMMERCIAL-USE EULA                           */
/* Copyright (C) 2017 - 2019 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.                                                 */

7.4. Congratulations

congratulations

7.4.1. Congratulations

Congratulations, you have completed this tutorial.

You have now constructed an illustrated text adventure using the Adventuron game system.

The concepts used in this tutorial can be used to create all sorts of games.

Be careful about creating game featuring copyright characters. For example, games involving famous comic book characters would not be legal to distribute.

Of course you are free to experiment with anything you like privately, but it’s more fun to make a game that you can share with other people.

7.4.2. Advanced Features Of Adventuron

This tutorial demonstrated how to create a basic text adventure in Adventuron, and in doing so, ignores many of the advanced features.

When you are more comfortable with Adventuron, there are many more features to be discovered, such as container support, advanced parser (use full sentences rather than verb noun), gamebook mode, chiptune support, hyperlinks, export to 8-bit machines, dynamic graphics, loops, maths, attribute support, and much more.

Please stay tuned for additional documentation.

7.4.3. Full set of commands

Adventuron contains many many commands and conditions, but only a few of these are required if you are building a simple adventure game such as Exclalibur.

These are all the commands and conditions that Excalibur uses.

Table 5. Commands
Command Description

: match

Execute some commands if a verb or noun (or both) match a pattern.

: if

Perform some commands only if a condition is satisfied (the condition evaluates to true)

: else

Perform some commands only if the condition in a preceeding if is NOT satisfied. Must follow an :if command.

: else_if

Perform some commands only if a condition is satisfied (the condition evaluates to true). Must follow an :if command.

: print

Displays some text to the player

: create

Creates an object in the game (creates in current scene by default).

: destroy

Destroy an object in the game.

: press_any_key

Tells the game to wait until the player either presses a key on the keyboard, or clicks the mouse, or touches the touchscreen.

: pause

Pauses a number of milliseconds. One second is 1,000 milliseconds, so if you want to wait for 2 seconds, use the : pause "2000"; command.

: done

Stop executing commands and wait for input by the player.

: clear_screen

Clears the current screen. This happens automatically when the player navigates to a different location, but sometimes we may wish to refresh the screen when the player does not move.

: redescribe

Tells the game to clear the screen, then to redescribe the current scene, including the contents of the scene.

: gosub

Execute the commands contained in a nominated subroutine.

: set_true

Sets a boolean variable to contain a TRUE value.

: set_false

Sets a boolean variable to contain a FALSE value.

: set_integer

Sets an integer (an integer is a number) variable to a specified value.

: increment

Adds 1 to the value of the specified integer variable (an integer variable holds a number).

: end_game

Display the end_game text, then wait for the player to press or click something, and then restart the game. Typically you would want to give the player some specific information before using this command (like display a failure screen).

: beep

Play a sound tone at a specified pitch and duration.

: turns

Display the current amount of turns taken in the game.

: inventory

Display the items that the player is carrying.

: set_graphic

Change the graphic that is drawn when the player enters a scene. The game will remember the changed graphic. This is useful for if the location should look different in response to some event that has happened in the game.

: show_graphic

Print a graphic at the current line of the display (inline). This only happens once, and does not change any graphic that will be displayed when the player re-enters a scene.

: set_theme

Change the current theme of the game to the specified new theme. A theme is the way that the game is configured to be drawn or laid out. This is an ADVANCED command.

: block

Blocks access to a location on the map. All entrances to the location from all directions are blocked, and a customizable message will be displayed to the player if they attempt to access the location.

: unblock

Unblocks access to a location. The message is removed, and now the location will be listed as an exit direction in neighbouting locations/scenes.

Table 6. Boolean Expression Items
Condition Description

VARNAME

Is a boolean with id matching VARNAME currently holding a TRUE value?

COND1 || COND2

Is condition1 OR condition2 returning a positive answer?

COND1 && COND2

Is condition1 AND condition2 returning a positive answer?

!COND1

Is condition1 holding a FALSE value?

EXPRESSION1 == EXPRESSION2

Is expression1 returning the same value as expression2?

is_present

Is an object carried or in the same scene as the player?

has_not_created

Has the object not yet been created?

is_at

Is the player at the specific scene?

is_carried

Is the player holding the specified item (in the inventory).

is_beside

Is the specified item in the same location as the player, but not in the player’s inventory?

is_just_entered

Did the player just enter the current location from a different location?

Table 7. Integer Expression Items
Condition Description

linger()

Returns the number of turns since we arrived in the current scene. This resets to zero when the player moves to a new location.

Table 8. Events Handling
Event Type Description

on_startup{}

This code block will be executed before any other block when a game is first started. It will NOT be executed if loading a saved game, but it will be executed on a new game.

on_command{}

The on_command{} block is executed after the player submits a command (via keyboard / mouse / joypad / speech / touch / etc). Typically this section contains one or more : match {} items, which are used to check for a particular verb / noun combination.

on_describe{}

The on_describe{} block is executed when a scene is redescribed (this may not be every turn). This may happen due to a code executed in the on_command {} block, or due to the player moving to a new location.

on_tick{}

The on_tick{} block is executed after the on_command{} block, and if the scene has just been changed, it is executed after the on_describe{} block tooand can be used for actions that occur in the game world, independent of what the player just typed.

8. Quick Start Guide (Version 1.0.0)

It is advised that you don’t read this until you complete the course unless you are very familiar with programming concepts and/or text adventure creation concepts.

If you came here accidentally, click the up arrow icon at the top of this panel to go back to the main menu, .

8.1. Introduction

Adventuron Classroom is a web-hosted text-adventure authoring system, with a goal or replicating the magical feel of old-school text adventures from the 1980s.

8.2. Intended Audience

This quick start guide is aimed at authors with some level of programming experience in some other language, and readers that already know what a text adventure is. The guide may also be useful for those that have completed the classroom course.

Terms like integer / boolean / subroutine are used.

An absolute beginner version of this guide will be published later.

8.3. License

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

8.4. Locations

An Adventuron 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." ;
}

8.4.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";
}

8.4.2. Location Graphics

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).

8.5. Connections

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

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

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

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

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

8.6. Variables

8.6.1. Boolean Variables

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

8.6.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
}

8.6.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
}
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):
: set_string var="nice_location_description" {(
   "I am in location with id " +
   current_location()
)}

8.7. 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 can exists and not exist. 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.

8.7.1. Defining Objects

Object Type Details

object

A normal takeable/droppable object.

scenery

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

Defining An Object That Will Not Exist On Game Start
objects {
   blue_spoon : object "a blue spoon";
}
Defining An Object That Will Be Held By Player On Game Start
objects {
   blue_spoon : object "a blue spoon" start_at="inventory";
}
Defining An Object In A Particular Location
objects {
   blue_spoon : object "a blue spoon" start_at="barn";
}

8.7.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".
NOTE — The description does not have to relate to the noun or the adjective at all - although it SHOULD unless the player will become confused.

8.7.3. 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" start_at="barn";
   blue_spoon_2 : object "a blue spoon" start_at="kitchen";
   blue_spoon_3 : object "a blue spoon" start_at="well";
   blue_spoon_4 : object "a blue spoon" start_at="castle";
   blue_spoon_5 : object "a blue spoon" start_at="dungeon";
}

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

8.8. 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.

8.8.1. Block activation conditions.

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

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

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

8.8.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.
   }
}

8.8.3. Doors (Basic)

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

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

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

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

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

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

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

8.9. Event Handlers

Event handlers are a way of putting logic into the game. The game either reacts actively to a user-submitted command, or passively, to events happening in the world.

The most common event handlers are documented here. There are actually additional event handlers, which will be documented in the advanced guide, but to keep it simple, the most common and useful event handlers are documented here.

8.9.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.

on_startup {
   : print "Welcome to the world of nuts and bolts !!!!";
   : press_any_key ;
}

8.9.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";
      }
   }
}

8.9.3. on_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
   }
}

8.9.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.

on_describe {
   : if (is_at "ice_cavern" && has_created_fire == false) {
      : print "You shiver.";
   }
}

8.9.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_describe {
   : if (is_at "ice_cavern" && has_created_fire == false) {
      : print "You shiver.";
   }
}

8.9.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";
}

8.10. Local Event Handlers

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

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

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

      on_command {
         // Local command handlers here
      }

      on_describe {
         // Local description events here
      }

      on_tick {
         // Local tick events here
      }

   }
}

8.11. Commands

Commands represent actions to perform in a given context. Some actions may be conditional on a boolean expression evaluating to a particular result.

8.11.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 look 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.

: you_cant;

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).

8.11.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.

: stagger "message text" ;

Prints the given message and places 'press_any_key' inbetween each paragraph (but not after the final paragraph printed).

: 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).

: 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.

: press_any_key ;

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

: inventory ;

Shows the objects that the player character is holding.

: save ;

Shows the save game dialog.

: load ;

Shows the load game dialog.

: create "OBJECT_ID" ;

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

: create "OBJECT_ID" target = "LOCATION_ID" ;

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

: create "OBJECT_ID" target = "inventory" ;

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

: destroy "OBJECT_ID" ;

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

: set_true "BOOLEAN_ID" ;

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

: set_false "BOOLEAN_ID" ;

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

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

Adds a value onto the current value of an integer.

: 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.

: end_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.

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

Changes the default graphic for a location to a different graphic.

: print_graphic "GRAPHIC_ID";

Prints the referenced graphic directly to the screen.

: get;

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

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

: drop;

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

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

: get "OBJECT_ID";

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

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

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

: drop "OBJECT_ID";

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

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

: pocket "OBJECT_ID";

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

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

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

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

Pocket failing does not stop execution of subsequent commands.

: wear;

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

: unwear;

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

: wear "OBJECT_ID";

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

: unwear "OBJECT_ID";

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

: 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.

8.11.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.

8.12. Boolean Expressions

8.12.1. 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";
       }
    }
}

8.12.2. 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.

8.12.3. Boolean Functions

Boolean functions can be used inside boolean expressions.

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

Name Description

is_at "LOCATION_ID"

Returns true if the player is at the referenced location.

is_present "OBJECT_ID"

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

is_beside "OBJECT_ID"

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

is_exists "OBJECT_ID"

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

is_carried "OBJECT_ID"

Returns true if the referenced object is carried (in the current players inventory).

is_worn "OBJECT_ID"

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

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.

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_at_initial_location "OBJECT_ID"

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

is_just_entered ()

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

is_first_entered ()

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

is_mobile()

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

is_int(STRING_EXPRESSION)

Returns true if the string expression contains an integer number

chance (n)

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

noun1_is "noun"

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

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).

8.13. Integer Expressions

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

8.13.1. 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).

8.13.2. 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.

8.13.3. Integer Functions

This is a greatly abbreviated set 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.

items_carried()

Returns the number of items carried by the player.

item_limit()

Returns the limit of the number of items that is permitted to be carried by the player.

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).

inventory_item_limit()

Returns the number of items that are carryable.

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.

8.13.4. 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.

8.14. Strings

8.14.1. String Functions

Name Description

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).

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.

previous_location()

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

current_location()

Returns the location the player is currently

8.14.2. Dynamically resolving the value of a string using an expression

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 +
         "."
      )}
   }
}

8.15. Setting Up The Game Information

Setting up the game_information{} section is essential to the health of your Adventuron game. It’s this section that

Replace all upper case fields with your specific information

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:

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                         = 2019
   copyright_message            = YOUR COPYRIGHT MESSAGE
   short_synopsis               = ONE SENTENCE DESCRIPTION OF GAME.
}

8.16. Loading And Saving

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.

As each website domain (base part of a url) has its own storage, it’s impossible for one website to corrupt the save data of a game on a different website.

But …​ 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.

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.

8.16.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.

8.16.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.

8.16.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.

8.16.4. Pan-Game Data

Adventuron saves some data seperate to the 5 save slots. This data stores pan-game data. Things like user preferences are stored in this area.

8.16.5. Gotchas

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.

8.17. Match Patterns

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 {{\n   : match \"yawn -\"  {{ : print \"Yawn 1.\" ; }}\n   : match \"yawn _\"  {{ : print \"Yawn 2.\" ; }}\n   : match \"yawn *\"  {{ : print \"Yawn 3.\" ; }}\n}}";
}
on_command {
   : match "yawn -"  { : print "Yawn 1." ; }
   : match "yawn _"  { : print "Yawn 2." ; }
   : match "yawn *"  { : print "Yawn 3." ; }
}

The results are as follows:

match

8.18. Text Formatting Codes

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.

8.18.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" ;
   }
}

8.18.2. 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).

8.18.3. 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.

8.18.4. 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";

8.18.5. 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>>.";
: print "This part of the text is <bright red<#f00>> using 12-bit RGB code #f00 (r = 15, g = 0, b = 0).";

8.18.6. 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.";

8.18.7. 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.";

8.18.8. 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^";

8.18.9. Escape codes

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

\\ 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``";

8.18.10. 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.

8.18.11. For Geeks Only - Bits / RGB / Hexidecimal

  • 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
000 = black
001 = blue
010 = green
100 = red
110 = yellow
101 = magenta
011 = cyan
111 = white

8.18.12. About hex

Adventuron’s text formatting tags supports a 12 bit simplified palette.

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

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

4 bits representation is a number between 0 and 15 (16 combinations).

For numbers 10 - 15, we use hexidecimal notation:

0 = 0
1 = 1
2 = 2
3 = 3
4 = 4
5 = 5
6 = 6
7 = 7
8 = 8
9 = 9
10 = a
11 = b
12 = c
13 = d
14 = e
15 = f

e.g.

#000 = black (0 red, 0 green, 0 blue → always read in rgb order).
#fff = white (15 red (max), 15 green (max), 15 blue (max))

12 bit colour gives a maximum of 4096 possible colour combinations (16 x 16 x 16 = 4096)

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

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.

8.19. Contact

Adventuron is written by Chris Ainsley, and Copyright of Adventuron Software Limited, All Rights Reserved.

9. Code Snippets (Cookbook)

Warning
Please note this section is NOT for children or beginners. Please make sure you are very familiar with the basic aspects of adventuron before reading onwards.

This section contains various recipes for common types of problems that are encountered.

9.1. 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"  start_at = "village" ;
   pen   : object "a pen"   start_at = "village" ;
   sword : object "a sword" start_at = "village" ;
   rock  : object "a rock"  start_at = "village" ;
}

integers {
   inventory_limit : integer "3" ;
}

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
}

9.2. Vehicles

The following example shows how to create a vehicle (a boat), which can be moved between two location (update the code to allow it to travel to many more locations, possibly using a string to track its location rather than a boolean).

The boat is both an object, and a location. The boat object and the boat location cannot have the same identifier.

If the player enters the boat from the same location as the boat can be in, then the player is sent to the "inside_boat" location. From there rowing will move the location of the boat between two locations (lakeside, and island_beach) - it will create the boat in one of two location, the opposite one of the current location.

This code sample also demostrates a "repair boat" puzzle, but without a pre-requisite. You can repair the boat just by typing "repair boat".

Exiting the boat will take the player to the location containing the boat.

######################################
#  Adventuron                        #
######################################

start_at                 = lakeside

######################################
#  Booleans                          #
######################################

booleans {
   is_boat_fixed       : boolean "false" ;
   is_boat_at_lakeside : boolean "true" ;
}

######################################
#  Locations                         #
######################################

locations {
   lakeside     : location  "You are at the lakeside" ;
   inside_boat  : location  "You are a boat." ;
   island_beach : location  "You are at a beach on an island" ;
}

on_describe {

   : if (is_at "inside_boat") {
      : if (is_boat_fixed == false) {
         : print "There is a hole in the boat." ;
      }
   }
}

######################################
#  On Command                        #
######################################

on_command {

   : match "enter boat;climb boat"  {
      : if (is_at "lakeside" || is_at "island_beach") {
         : goto "inside_boat" ;
         : print "You climb inside the boat" ;
         : press_any_key ;
         : redescribe;

      }
   }

   : match "leave boat;exit _"  {
      : if (is_at "inside_boat") {
         : goto "old_boat" ;
         : print "You climb out of the boat" ;
         : press_any_key ;
         : redescribe;

      }

   }

   : match "repair hole;repair boat"  {
      : if (is_at "inside_boat" && is_boat_fixed == false) {
         : print "You repair the hole in the boat" ;
         : set_true "is_boat_fixed" ;
         : press_any_key ;
         : redescribe;
      }
   }

   : match "row boat"  {
      : if (is_at "inside_boat") {
         : if (is_boat_fixed) {
            : if (is_boat_at_lakeside) {
               : print "You row the boat to the island." ;
               : set_false "is_boat_at_lakeside" ;
               : create "old_boat" target = "island_beach" ;

            }
            : else {
               : print "You row the boat to the lakeside." ;
               : set_true "is_boat_at_lakeside" ;
               : create "old_boat" target = "lakeside" ;
            }
         }
         : else {
            : print "You can't row the boat with the hole in it." ;
         }
      }
   }
}

objects {
   old_boat : object "an old boat" start_at = "lakeside" ;
}

themes {
   my_theme : theme {
      lister_exits {
         is_list_enter                        = false
         is_list_exit                         = false
      }
   }
}

9.3. Custom get / drop messages

To take or drop an object without the system message being printed (if you want to print a custom message for example), then you can use the get command, but the quiet version of the command, as shown below.

The is_carried check can be used to test that the get was successful. A failed get will always print the failure message (your hands are full, you can’t take that, etc, - messages can be configured in the theme).

start_at = village

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

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

on_command {
   : match "get lamp"  {
      : if (is_beside "lamp") {
         : get "lamp" quiet = "true" ;
         : if (is_carried "lamp") {
            : print "You pick up the dusty lamp" ;
            : press_any_key ;
            : redescribe;
         }
      }
   }
}

A simpler method exists too. This message will only be displayed if the object is taken.

start_at = village

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

objects {
   lamp : object "a lamp" start_at = "village" get_message = "You pick up the dusty lamp";
}

9.4. Block Access To A Location

A barrier can be used to block access to a location. A block can be created in the "barriers" section.

In this example, a lamp is required to enter forest_1.

There is an issue here that the player may drop the lamp in forest_1, then leave forest_1, then permanently block the path, but that can be taken place with in other parts of the code.

Blocks can also have different conditions (block_when_carried, block_when, block_when_not, block_when_exists, block_when_not_exists, block_when_worn, block_when_not_worn).

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,
   ]
}

barriers {
   block_forest_path : block {
      location               = forest_1
      block_when_not_carried = lamp
      message                = You need a light source to go into the dark forest.
   }
}
objects {
   lamp : object "a magical glowing lamp" start_at = "village" ;
}

themes {
   my_theme : theme {
      font = clairsys_10
   }
}

9.5. Block Exits From A Location

A location agnostic block is a block that blocks all exits from the current location, no matter what the location is (you can narrow this down with the block condition itself).

By default it has a higher priority than other types of block.

NOTE

This type of block is not compatible with Adventuron 2 PAW / Adventuron 2 DAAD (currently).

start_at                 = stream
locations {
   stream   : location "You are by the side of a lovely stream.\nType <WEAR CLOAK<12>> to enable block, type <REMOVE CLOAK<12>> to disable block.";
   forest   : location "You are in a grand forest." ;
   old_hut  : location "You are in an old hut." ;
}
connections {
   from, direction, to = [
      stream, north, forest,
      forest, east, old_hut,
   ]
}
barriers {
   block_disorientate : block {
      block_when_worn = cloak
      message         = You are so confused, you can't seem to move anywhere.
   }
}
objects {
   cloak : object "the cloak of disorientation" wearable = "true" start_at = "inventory" ;
}
themes {
   my_theme : theme {
      presentation_mode = 2
   }
}

9.6. Goto the location of an object

The goto command will let you travel to a location or the location of an object. If the object is non existent, then the goto command does nothing when called.

start_at = village

locations {
   village : location "You are in the village. Type TELEPORT to go to the location of the lamp." ;
   forest  : location "You are in a forest. Type TELEPORT to go to the location of the lamp." ;
}

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

on_command {
   : match "teleport _"  {
      : print "You goto the location of the lamp" ;
      : goto "lamp" ;
      : press_any_key ;
      : redescribe;
   }
}

objects {
   lamp : object "a lamp" start_at = "forest" ;
}

9.7. 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" start_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;
      }
   }
}

9.8. Dynamic Text

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
      : print {(
         "Your score is " +
         score +
         "."
      )}
   }
}

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" ;
   }
}

Here is another variation, but without the requirement for a string variable to reference

start_at = village

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" ;
   }
}

Here is yet another variation, but in this variation, we only print something if it is a Wednesday, and we use inline text.

start_at = village

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

This final variation, demonstrates embedded {} blocks.

  • The outer {} only includes the text between the backtick (`) characters if the boolean reference resolves to true.

  • the next {} only includes the {wed}., if it is wednesday (true in this example).

  • the most inner {} refers to the variable 'wed', which contains a value of "Wednesday".

  • Backticks can be escaped using `` in this syntax.

start_at = village

locations {
   village  : location "You are in the village. {is_wednesday ? `It is {is_wednesday ? `{wed}.`}.`}\nType LOOK to refresh the dynamic location description." ;
}


strings{
   wed : string "Wednesday";
}
booleans {
   is_wednesday : boolean "true" ;
}
on_tick {
   : if (is_wednesday) {
      : set_false "is_wednesday" ;
   }
   : else {
      : set_true "is_wednesday" ;
   }
}

9.9. Persistant Variables

You can specify the 'survivor' scope on a variable to inform Adventuron to let the variable value survive at the point of an end_game or restart occurring (the default value will be set on first game only and never be reapplied upon restart).

In this snippet, completely unrelated, but we also demonstrate the % operator, which is the modulus (or remainder) operator. game_count % 10 gives us the remainder of an integer division by 10. This number will always be in the ranger of zero to nine.

start_at                 = my_location

locations {
   my_location : location "You are in a room. This is your {gane_count_nice} game." ;
}

integers {
   // The variable will survive a game restart (or game over)
   game_count : integer "0" scope="survivor";
}

on_startup {
   : increment "game_count" ;
}

strings {
   gane_count_nice : string_dynamic {(
       game_count +
         (game_count % 10 == 1 ? "st" :
          game_count % 10 == 2 ? "nd" :
          game_count % 10 == 3 ? "rd" : "th")
   )}
}

9.10. 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 + "."
      )}
   }
}

9.11. Picking Commands One At A Time Without Repetition (aka Cycling)

Sometimes you may wish to add some ambient messages to your game, or perhaps some other logic that occurs in cycles.

The logic of a cycle command is that one command out of the command stored inside the cycle {} block will be executed. When executed, the command will not be executed again until all other commands have been exhausted via repeated runs of the cycle command.

At the start of each round, the iteration order is determined. By default, the order is randomised, but you can set the order using predictable_order = "true|false".

Each cycle command requires a unique key as this will be used to store uniquely serialize the state of the cycle command.

The key can be anything you like but it must be unique in your gamefile per : cycle {} block.

Warning
Please do not use else blocks inside this command as the behaviour if doing this is undefined right now. If statement are fine.

9.11.1. Cycling With Predictable Order

start_at = woods

locations {
   woods : location "You are in the woods.\nType <WAIT<12>> repeatedly to cycle through the print commands." {
      on_tick {
         : cycle key = "woods_events" predictable_order = "true" skip_interval = "0"  {
            : print "You step on some twigs." ;
            : print "You hear the hoot of an owl." ;
            : print "The wind blows through your hair." ;
            : print "In the distance you hear the church bell chime." ;
            : print "You are afraid." ;
         }
      }
   }
}

9.11.2. Cycling With Randomized Order (per round)

By setting predictable_order = "false", Adventuron will jumble the commands so that they happen in a random order each round. Each round the random order will be different, but by default the same command can never be executed twice in a row (if it was randomly at the start of a new round after being at the end of the last round then it will automatically be shuffled by adventuron). This behaviour is can be switched off using allow_back_to_back="true" (false by default).

start_at = woods

locations {
   woods : location "You are in the woods.\nType <WAIT<12>> repeatedly to cycle through the print commands." {
      on_tick {
         : cycle key = "woods_events" predictable_order = "false" skip_interval = "0"  {
            : print "You step on some twigs." ;
            : print "You hear the hoot of an owl." ;
            : print "The wind blows through your hair." ;
            : print "In the distance you hear the church bell chime." ;
            : print "You are afraid." ;
         }
      }
   }
}

9.11.3. Skipping

By using skip="1" (or greater), then the cycle command will only be ignored for 1 or more ticks (depending on the integer provided) after each execution.

start_at = woods

locations {
   woods : location "You are in the woods.\nType <WAIT<12>> repeatedly to cycle through the print commands." {
      on_tick {
         : cycle key = "woods_events" predictable_order = "false" skip_interval = "0" skip="1" {
            : print "You step on some twigs." ;
            : print "You hear the hoot of an owl." ;
            : print "The wind blows through your hair." ;
            : print "In the distance you hear the church bell chime." ;
            : print "You are afraid." ;
         }
      }
   }
}

9.12. Semi Random Messages

If you want to execute one command in a mutually exclusive set at random, use the execute_one_at_random command.

This command will select one command (at random) from its direct descendents to execute and only run that command.

Warning
Please do not use else blocks inside this command as the behaviour if doing this is undefined right now. If statement are fine.
start_at = village

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

on_tick {
   : execute_one_at_random {
      : print "one" ;
      : print "two" ;
      : print "three" ;
      : print "four" ;
   }
}

9.13. Asking For A String Using A Negative Confirmation Question

start_at                 = my_location
locations {
   my_location : location "Hello {name}. You are in a room." ;
}
strings {
   name : string "";
}
on_startup {
   : ask_string
      question                  = "What is your name?"
      confirm_negative_question = "You entered your name as \"{name}\".\nWould you like to change the name?"
      var                       = "name"
   ;
}

9.14. Asking For Yes / No Answer

Adventuron allows for the setting of a boolean based on asking a yes / no question.

The : ask_bool command must be used in conjunction with a boolean.

In this snippet, some text in the game is conditionally displayed using a string_dynamic too, along with
a ? : operation

BOOLEAN ? value_if_true : value_if_false

NOTE : This feature does not work with Adventuron2PAW or Adventuron2DAAD

start_at                 = my_location

locations {
   my_location : location "You are in a bright kitchen.\n{toast_thought}" ;
}

strings {
   toast_thought : string_dynamic {(
      is_liking_toast ?
      "I can't stop thinking about delicious toast." :
      "I can't stop thinking about how disgusting toast is."

   )}
}

booleans {
   is_liking_toast : boolean "false" ;
}

on_startup {
   : ask_bool {
      question   = Do you like toast?
      yes_answer = Yes, I like toast very much
      no_answer  = No, toast is not something that appeals to me at all
      var        = is_liking_toast
   }
}

9.15. Adding A Top-Bar

A STICKY HEADER is a header that sticks to the top of the screen (does not scroll out of view).

Sticky headers in Adventuron currently can only (currently) contain two slots, top left, and top right.

To create a sticky header, define one in your theme.

Within the header_layout section, you can use the 'dynamic_text' item to reference a string (which will contain some piece of text that may change during the game).

You can also refer to the 'header_text' from the header_layout section, which will use the current location header text for the slot.

There is a third option, not show here, where you can specify static_text, which is text that is literal and will not change.

In the sample below, type 'jump' at the prompt to increment the score (up to a max of 20). The header will update. The header never scrolls off screen.

start_at = village

locations {
   village  : location "You are in the village" header = "Village" ;
   forest_1 : location "You are in a forest" header = "Forest" ;
   forest_2 : location "You are in a spooky forest" header = "Spooky Forest" ;
}
connections {
   from, direction, to = [
      village, east, forest_1,
      village, west, forest_2,
   ]
}
strings {
   score_topright : string_dynamic {(
      score + " / 20"
   )}
}

######################################
#  On Command                        #
######################################

on_command {

   : match "jump _"  {
      : if (score < 20) {
         : increment "score" ;
         : print "You do something very impressive" ;
         : press_any_key ;
         : redescribe;
      }
   }
}

integers {
   score : integer "0" ;
}
objects {
   lamp : scenery "a magical glowing lamp" start_at = "village" ;
}
themes {
   my_theme : theme {
      layout = G D X O
      screen {
         experimental_spacer_pre_text = 5
      }
      header_layout {
         : header_text;
         : dynamic_text "score_topright" ;
      }
      colors {
         // 15 == white (#fff)
         header_bar_pen   = 15
         // 9 = Blue (#00f)
         header_bar_paper = 9
      }
      theme_settings {
         header_capitalization = original
      }
   }
}

9.16. Treasure Hunt Mode

Adventuron Supports a basic 'treasure hunt' mode.

To switch on treasure hunt mode, simply supply a treasure_room, and flag one or more object as a treasure.

In the code show below, dropping the lamp in the treasure room will display a message of "You have found all the treasures. You have won!".

The winning message can be customised using a theme, and the automatic win-game logic can be disabled in the game settings, in case, you want to script a better ending, or have a more complex set of conditions for completing the treasure hunt.

start_at      = treasure_room
treasure_room = treasure_room
locations {
   treasure_room : location "The treasure room";
   tomb          : location "A tomb" ;
}
connections {
   from, direction, to = [
      treasure_room, east, tomb,
   ]
}
objects {
   lamp : object "a lamp" start_at = "tomb" treasure = "true" ;
}

9.17. Room Escape Game

Below is a small room escape game written in Adventuron.

start_at = cell

locations {
   cell : location "You are in your cell. You see a door, a bed and bland wallpaper adorns the walls." ;
}

objects {
   wallpaper : object "a strip of wallpaper" ;
   pen       : object "a pen"                ;
   key       : object "a small key"          ;
}

booleans {
   is_key_in_keyhole   : boolean "true"  ;
   is_key_on_paper     : boolean "false" ;
   is_paper_under_door : boolean "false" ;
}

vocabulary {
   : noun / aliases = [wallpaper, paper]
}

on_command {

   : match "search bed; examine bed"  {
      : if (has_not_created "pen") {
         : print "You find something" ;
         : create "pen" ;
         : press_any_key ;
         : redescribe;
      }
   }

   : match "examine wallpaper"  {
      : if (has_not_created "wallpaper") {
         : create "wallpaper" ;
         : print "A piece of the wallpaper falls away" ;
         : press_any_key ;
         : redescribe;
      }
      : else {
         : print "You think you should leave the rest of the wallpaper in place." ;
      }
   }

   : match "examine door"  {
      : print "A solid looking oak door with a keyhole." ;
      : if (is_paper_under_door) {
         : print "The wallpaper is peeking out from under the door." ;
      }
   }

   : match "examine keyhole"  {
      : if (is_key_in_keyhole) {
         : print "There appears to be a key in the keyhole on the other side of the door." ;
      }
      : else {
         : print "The key is no longer in the keyhole.\nYou can't see anything else of interest due to the darkness." ;
      }
   }


   : match "slide wallpaper;insert wallpaper;place wallpaper"  {
      : if (is_carried "wallpaper") {
         : if (noun2_is "door") {
            : if (is_paper_under_door) {
               : print "You can't slide it under the door any more." ;
            }
            : else {
               : print "You slide the wallpaper under the door." ;
               : set_true "is_paper_under_door" ;
               : destroy "wallpaper" ;
            }
         }
         : else {
            : print "Where?" ;
         }
      }
      : else {
         : print "You don't have it." ;
      }
   }

   : match "poke keyhole; poke key; insert pen; put pen"  {
      : if (is_key_in_keyhole) {
         : if (is_carried "pen" && (noun2_is "pen" || noun2_is "keyhole" )) {
            : set_false "is_key_in_keyhole" ;
            : if (is_paper_under_door) {
               : print "The key falls onto the paper." ;
               : set_true "is_key_on_paper" ;
            }
            : else {
               : print "The key falls onto the floor behind the door and bounces away." ;
               : print "More planning is perhaps required." ;
               : print "GAME OVER" ;
               : end_game ;
            }
         }
         : else {
            : print "Your finger is too big." ;
         }
      }
      : else {
         : print "The key has already fallen" ;
      }
   }

   : match "pull paper; get paper"  {
      : if (is_paper_under_door) {
         : pocket "wallpaper" ;
         : if (is_key_on_paper) {
            : print "You pull the paper back from underneath the door. You also take the key that is resting upon it." ;
            : pocket "key" ;
         }
         : else {
            : print "You pick up the wallpaper." ;
            : pocket "wallpaper" ;
         }
         : set_false "is_paper_under_door" ;
         : set_false "is_key_on_paper" ;
         : press_any_key ;
         : redescribe;
      }
   }

   : match "unlock door; open door"  {
      : if (is_carried "key") {
         : print "Using the small key, you unlock the door, open it, and continue onward to your next adventure." ;
         : press_any_key ;
         : end_game ;
      }
      : else {
         : print "The door is locked" ;
      }
   }
}

9.18. The Cave of Magic

The Cave of Magic is a very simple game, implemented in Adventuron, and placed into the public domain by Chris Ainsley.

It forms the basis of the Adventuron Cavejam, which is (or was) a gamejam to remix and improve this game.

// (1) Please watch the following video to
//     demonstrate the editor features of Adventuron
//     ... https://www.youtube.com/watch?v=zbC_bSysbrA

// (2) To get rid of the tutorial side panel
//     Select MENU / Display Side Documentation

// USEFUL SHORTCUTS

// Click the header in Adevnturon Classroom to quickly
// navigate to different code sections
// Press Control + SPACE (or ALT + SPACE) to access code completion
//        ... see youtube video for demonstration of this feature.
// Press Control + F (to find code)
// Press Control + F x2 (to search and replace)
// Press Control + S to save the code and execute.
// Click Menu / Compile to export game as HTML.

######################################
# Code Start                         #
######################################

// Set the Start location to be lakeside

start_at                 = lakeside
start_theme              = my_theme

// Set the initial (or loading) screen to be
// the graphic asset with id 'loading_screen'

loading_screen           = loading_screen

######################################
# locations                          #
######################################

locations {
   forest       : location "You are on the forest path.\nTall <TREES<4>> tower over you on both sides." ;
   outside_cave : location "You are standing outside <THE CAVE OF MAGIC<5>>" ;
   inside_cave  : location "You are inside <THE CAVE OF MAGIC<5>>" ;
   lakeside     : location "You are by the side of a <BEAUTIFUL LAKE<2>>." ;
}

######################################
# connections                        #
######################################

connections {

   // The lakeside connects northwards to the foresat
   // So we can imply that forest connects southwards
   // to the lakeside.

   // When connecting locations, do not consider the blocks
   // between locations

   // Mazes are possible using north_oneway , south_oneway,
   // etc, but be careful not to frustrate the player.

   from, direction, to = [
      lakeside,     north, forest,
      forest,       north, outside_cave,
      outside_cave, north_oneway, inside_cave,
   ]
}

######################################
# Objects / Scenery                  #
######################################

objects {
   troll          : scenery "an enormous troll" start_at = "outside_cave" ;
   sleeping_troll : scenery "an enormous troll (sleeping)" ;
   apple          : object  "an apple" ;
   treasure       : object  "a pile of treasure" start_at = "inside_cave" ;
}

######################################
# barriers                           #
######################################

barriers {

   // Blocks entry to the cave if the troll exists.

   block_cave : block {
      location               = inside_cave
      message                = THE TROLL IS GUARDING THE CAVE.
      block_when_exists      = troll
      show_blocked_exit      = true
   }
}

######################################
# on_startup                         #
######################################


// The on_startup hook runs at the start of the game, one time per game.

on_startup {

   // Print the graphic of the outside of the cave
   // This uses the png data of the graphic encoded
   // as text (at the bottom of this source code)
   : print_graphic "outside_cave" ;

   // ^c^ Tells adventuron to centre the paragraph horizontally.
   : print "^c^<- THE CAVE OF MAGIC DX -<12>>\n<A One Puzzle Game\nby Chris Ainsley<10>>" ;

   : beep millis = "100"  pitch = "0" ; // Pitch 0 = middle C.
   : beep millis = "100"  pitch = "2" ;
   : beep millis = "100"  pitch = "4" ;
   : beep millis = "100"  pitch = "6" ;

   // Waits for the player to press a button
   // click the mouse, or touch the screen.
   : press_any_key ;

   : beep millis = "100"  pitch = "6" ;
   : beep millis = "100"  pitch = "4" ;
   : beep millis = "100"  pitch = "2" ;
   : beep millis = "100"  pitch = "0" ;

}

######################################
# on_command                         #
######################################


// The on_command block is used to handle player text input

on_command {

   // If the player types "examine trees" or "examine tree"
   // Then run the inner code. NOTE, adventuron automatically maps
   // examine to "look at" so if the player were to type
   // "look at tree" or "look at trees" it would also match

   : match "examine trees; examine tree"  {
      // If the player is located in the forest and has typed "look at tree"
      // or "look at trees" or "examine tree" or "examine trees"
      // then the game will print "Apple Trees".
      : if (is_at "forest") {
         : print "Apple trees." ;
      }
   }

    // If the player has typed "pick apple" or "get apple" then run the code inside this block
    // NOTE : Adventuron automatically associated verbs get with take, so this would
    //        automatically test for get apple, pick apple, or take apple.

   : match "pick apple;get apple"  {

      // The && characters represent an AND clause
      // is_at "forest" returns a TRUE value when the player in in the forest location
      // has_not_created "apple" returns TRUE if the game has never created the object with id 'apple' before.
      // --------------------------
      // The inner coade is only executed if the player typed "pick apple" or "get apple"
      // and the player is in the forest and if the apple has not been created before.
      // --------------------------

      : if (is_at "forest" && has_not_created "apple") {
           : print "You take an <APPLE<12>> from one of the trees." ;
           : beep millis = "100"  pitch = "0" ;
           : beep millis = "200"  pitch = "8" ;
           // put the apple in the players pocket (inventory), create + get.
           : pocket "apple";
      }
   }

   : match "examine troll;talk troll"  {

       // Colouring in text is possible using <sometext<n>> pattern (where n is a number between 0 and 15 representing a palette number)
       // By default 0 = black, 1 = blue, 2 = red, 3 = magenta, 4 = green, 5 = cyan, 6 = yellow, 7 = white, 8 = black, 9 .. 15 are bright versions of 1 .. 17.

      : if (is_present "troll") {
         : print "<\"I'M SO HUNGRY\"<3>>, says the enormous TROLL in the deepest possible voice." ;
      }
      : else_if (is_present "sleeping_troll") {
         : print "The troll is fast asleep." ;
      }

   }

   : match "give apple"  {
      : if (is_present "troll" && is_carried "apple") {
         : print "The troll grabs the apple from you hungrily. Unfortunately (for the troll), the apple is an <ENCHANTED APPLE<12>>, and sends the troll directly to sleep." ;

           // Destroying an object will move it into a non-existing state (into the ether)
         : destroy "apple" ;
         // Change the location of the troll and the sleeping troll
         // (move troll to nowhere, and sleeping_troll
         // to the location of the current troll)
         : swap o1 = "troll"  o2 = "sleeping_troll" ;
           : beep millis = "100"  pitch = "0" ;
           : beep millis = "100"  pitch = "6" ;
           : beep millis = "100"  pitch = "12" ;
           // Wait for the player to press a key, touch the screen
           // or click the mouse
         : press_any_key ;
         // Then redescribe the current location
         : redescribe;
      }
   }

   // If the player types 'eat apple'
   : match "eat apple"  {
      // And if the apple is present (in same location or carried)
      : if (is_present "apple") {
         // Then display a GAME OVER screen.
         // On larger games, instant death is not at all
         // advised, except if explicitly signposted perhaps.
         : print "Unfortunately, the apple was an <ENCHANTED APPLE<12>>, and you will now go to sleep - forever." ;
         : print "^r^<GAME OVER<2>>" ;
         : end_game ;
      }
   }
}


######################################
# on_tick                            #
######################################

// The on_tick code is executed after a command has been dealt with.

on_tick {

   // is_just_entered() only returns true when the player has just
   // entered the current location (not on second tick in the same
   // location).
   : if (is_present "troll" && is_just_entered () ) {
      : beep millis = "100"  pitch = "-2" ;
      : beep millis = "100"  pitch = "-4" ;
      : beep millis = "300"  pitch = "-8" ;
      : print "The troll says, <\"THE CAVE IS MINE, GO AWAY\"<2>>." ;
   }

   : if (is_at "lakeside" && is_just_entered () ) {
      : print "Type <HELP<13>> to see a list of useful commands." ;
      // NOTE : Authors can override the default help screen
      // with a : match "help _" in the on_command{} section
   }

   // If the player is inside the cave, then trigger the win
   // game messages.
   : if (is_at "inside_cave" ) {

      : beep millis = "200"  pitch = "0" ;
      : beep millis = "400"  pitch = "10" ;
      // ^r^ tells adventuron to right align the text horizontally.
      : print "^r^<CONGRATULATIONS !<11>>" ;
      : print "^r^<YOU WON THE GAME !<10>>" ;
      : print "^r^<YOUR RANKING IS : JUNIOR ADVENTURER !<12>>" ;
      : end_game ;
   }
}

######################################
#  On Describe                       #
######################################

on_describe {
   // Put code here that is printed when a location is described.
}

######################################
#  Subroutines                       #
######################################

subroutines {
   // Add your subroutines here, could be useful for commonly
   // used beep commands, or decorative game over screen
}


######################################
#  Themes                            #
######################################

themes {
   my_theme : theme {
      theme_settings {
         // H = Header
         // G = Graphics
         // D = Description
         // X = Exit List
         // O = Object (or entity) List
         layout                       = H G D X O

         // Enables scanline emulation (experimental Adventuron feature - subject to change)
         experimental_enable_crt      = true
      }
      screen {
         // The space between paragraphs in terms of font height, 0.5 = half the height of the current font
         paragraph_spacing_multiplier = 0.5
         border_mode_vertical_percent = 1
      }
   }
}

######################################
# game_information                   #
######################################

// This information is used when packaging the html file
// and for determining the key to use for save slots in
// the browser (the uuid stops save game collisions)

game_information {

   game_name                    = The Cave of Magic
   game_version                 = 1.0.0
   game_shortname               = Magic Cave
   written_by                   = Chris Ainsley
   //uuid                         =
   year                         = 2019
   copyright_message            = The Cave of Magic was written by Chris Ainsley and is public domain.
   short_synopsis               = In the Cave of Magic, Treasure Awaits.
}

######################################
#  Graphics                          #
######################################
assets {

   // Graphics are base64 encoded, and graphics that
   // share an id with a location are automatically
   // associated with that location (and shown if G
   // is included in the theme / layout)

   // NOTE : Use the Menu button, and select Import, to import
   //        more graphics. Graphics should ideally be either
   //        128 pixels by 40 or 256 x 80 pixels (for the jam)
   //        PNG Images can be created with any tool, but pixel art
   //        editors work best, such as https://lospec.com , choose
   //        a consistent palette for your game.
   //        Adventuron will be getting an integrated pixel art editor
   //        in a later release.
   //        PNGs can be compressed quite nicely using https://squoosh.app/

   // Placeholder graphics are listed here, but graphics
   // cam be replaced with textual base64 encoded representations of
   // PNG files.

   graphics {
      logo           : placeholder;
      loading_screen : placeholder;
      inside_cave    : placeholder;
      lakeside       : placeholder;
      outside_cave   : placeholder;
      forest         : placeholder;
   }
}

9.19. Advanced Theming

9.19.1. Changing The Font

Fonts are defined at theme level. The default font is Bamburgh, but you can change fonts here.

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,
   ]
}
objects {
   lamp : object "a magical glowing lamp" start_at = "village" ;
}

themes {
   my_theme : theme {
      font = clairsys_10
   }
}

User imported fonts (use the MENU / IMPORT option in the Adventuron Classroom editor) can be referenced via pressing CONTROL (or ALT) + SPACE after "font = ", all user fonts are named userfont_xxxxxxxxxx (where xxxxxxxxx is the filename of the ttf font imported).

9.19.2. Setting border mode on.

If you set 'border_mode_vertical_percent = x' (where x is usually best with a value of 1), then this will reserve a MINIMUM of x percentage of the screen as a vertical border (non mobile mode only).

As the content panel of the display area generally only scales in integer amounts (pixel doubling, tripling, etc), then it will be likely that a lot more of the vertical section of the screen will be lost, in order to fit with this request without blurring the bitmap text.

If in doubt, use a value of 'border_mode_vertical_percent = 1'.

9.19.3. Setting border colour.

To set the border colour, just set border = x in the colors{} section inside a theme (where x = #000 - #fff, or a palette entry colour 0 - 15 - which corresponds to the zx spectrum palette by default).

Note
I’m using the spelling of "colour" in my description (because I’m British), but the name of the color fields in Adventuron is in American English (as is the coding convention). I’m sure Webster though he was making things easy.

9.19.4. Theme Inheritance

As border colour is tied up to the theme, then there would normally be a lot of copying and pasting of themes to be identical except for the border colour change.

This is simplified in Adventuron with theme inheritance. Simple write extends = theme_id (where theme is the name of another theme), and all the settings of that theme will be applied, before the settings of the current theme are applied.

You can extend to any depth you like, but do not specify circular inheritance (theme a extends theme b which extends theme a which extends theme b, etc).

9.19.5. Changing The Border Colour

To change the border colour, simply call the name of the theme that has the border colour (via : set_theme "theme_id";).

This feature, and theme inheritance was used in the final public-facing version of Excalibur.

Upon entering a location, in on_describe{} a theme would be set for the current location, which allowed the border colour to match the artwork and the tone of the current location.

start_at    = room
start_theme = base

locations {
   room : location "You are in a room.\n^n^   Type 'GREEN'  to set the border green.\n   Type 'YELLOW' to set the border yellow.^m^\n   (non-mobile clients only).\n" ;
}

on_command {
   : match "green _"  {
      : set_theme "green";
      : print "OK" ;
   }
   : match "yellow _"  {
      : set_theme "yellow";
      : print "OK" ;
   }
   : match "grey _"  {
      : set_theme "base";
      : print "OK" ;
   }
}

themes {
   base : theme {
      font    = clairsys_10
      columns = 50
      screen {
         content_width                = 400
         border_mode_vertical_percent = 1
         paragraph_spacing_multiplier = 1
      }
      colors {
         paper     = 7
         story_pen = 0
      }
   }
   green : theme {
      extends = base
      colors {
         border  = 4
      }
   }
   yellow : theme {
      extends = base
      colors {
         border  = 6
      }
   }
}

9.19.6. Dynamic Text In The Screen Layout

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" start_at = "village" ;
}

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

themes {
   my_theme : theme {
      layout = H G D X P* "some_dynamic_string" O SEP "adv_line_red"
   }
}
  • H = Header (if exists for location)

  • G = Graphic (if exists)

  • D = Description (if exists for location)

  • X = Exit List (if exists for location)

  • P* "string_id" = pointer to a string id of a string containing text to be rendered (this can be a dynamic string which will resolve lazily).

  • O = Object list for conspicious objects in location (if exists for location)

  • 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.

More layout options are available, to be documented later.

9.19.7. Making sure that images are scaled correctly

Use the width = xxxx attribute inside the screen block inside a theme to make sure that the horizontal width of the play area is scaled by multiples of this figure.

Note
Mobile clients do not use this setting and always use 100% of horizontal width (high dpi means that artifacts are barely visible on mobile).
start_at = village

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

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

######################################
#  Themes                            #
######################################

themes {
   my_theme : theme {
      screen {
         // Setting the width to 256 will snap the screen scaling factor in integer increments of 256 pixels (meaning graphic scaling can be crisp for precise pixel art)
         content_width = 256
      }
   }
}

9.20. Music

Note
THIS IS VERY EXPERIMENTAL AND MAY NOT WORK WELL OR AT ALL

Playing music is experimentally implemented in Adventuron.

MP3s can be referenced via absolute url (starting with http:// or https:// or relative urls).

If using relative urls, then to test your game, you must compile the game and use it from your local file system, or compile it and host it on a website. The relative urls
will not work using the classroom website as the assets will not be hosted there.

If there is a desktop version of Adventuron Classroom produces, this will not be an issue.

start_at = river

locations {
   river : location "You are in the river.\n" ;
}

on_tick {
   : if (is_just_entered () ) {
      : if (is_at "river") {
         : play_music sound="song_river";
      }
      : else {
         : stop_music;
      }
   }
}

assets {
   sounds {
      // NOTE :: Make sure that only reference content you are
      //         licensed to use.

      // ALSO :: You can use relative paths here, but you can only
      //         test in compiled versions of your code (not the
      //         web editor)
      song_river : sound_sample "https://somedomainid.com/sounds/river.mp3" ;
   }
}

9.21. Darkness

Darkness is a special state where a location cannot be described.

It’s not generally a very friendly state to leave the player in as it stops object lists and exit lists from being displayed (by default) but some people might want to add this to their game.

Darkness requires:

  1. A boolean that describes if the current state is dark or not

  2. Setting up a reference to the darkness boolean in the settings{} block.

  3. (Optionally) Customizing the darkness message, and possibly the darkness text colour.

In this example we use a dynamic boolean to dynamically calculate if it is dark.

Before a location is described, the darkness expression is evaluated and if it is dark, then the darkness message is displayed in place of the regular location text.

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" ;
}

// Zones are ways to define a group of locations. In this case
// we just choose the locations we will mark as dark.
zones {
   dark_zone : zone {
      locations = [ forest_1, forest_2 ]
   }
}
booleans {
   // A dynamic boolean is an expression that is
   // freshly calculated every time it is referred to

   // The part within the {( )} characters is just like
   // an expression you would find between the () of an :if
   // statement
   is_dark : boolean_dynamic {(
      is_at "dark_zone" &&
      is_present "lamp" == false
   )}
}
settings {
   dark_expression = is_dark
}

connections {
   from, direction, to = [
      village, east, forest_1,
      forest_1, east, forest_2,
   ]
}
objects {
   lamp : object "a magical glowing lamp" start_at = "village" ;
}

// Setting the dark message is optional here
themes {
   my_theme : theme {
      system_messages {
         it_is_dark = Darkness surrounds you !
      }
   }
}

9.22. Advanced Darkness

This more advanced demonstration of darkness uses dynamic booleans to simplify in_game logic.

Boolean dynamics are used to simlify the logic in the on_command block.

Light lamp is matched before the darkness verb blocking.

start_at                 = start_room

locations {
   start_room : location "You are in a lovely treasure room." {

      on_command {
         : match "test _"  {
            : print "Should be blocked in the dark!" ;
            : done ;
         }
      }

   }
}

objects {
   // The crown is in the same location as the player at the start, but GET is blocked
   // so cannot be taken even if the player knows it's there.
   crown : object "a gold crown" start_at = "start_room" ;

   // The lamp description is dynamic, based on the state of the lamp
   lamp  : object "a lamp{is_lamp_lit ? ` (lit)`}" start_at = "inventory" ;

}

booleans {

   is_lamp_lit : boolean "false" ;

   is_dark     : boolean_dynamic  {(
      is_at "start_room" && is_lamp_lit == false
   )}

   // Everything except [movement, quit, save, load,
   // inventory, turns, look] is banned in the dark.
   is_inaccessible_darkness_verb : boolean_dynamic {(
      (
         /* is movement command matches any system compass direction verb + all aliases */
         is_movement_command () ||
         verb_is "quit"         ||
         verb_is "save"         ||
         verb_is "load"         ||
         verb_is "inventory"    ||
         verb_is "turns"        ||
         verb_is "look"
      ) == false
   )}
}

on_pre_command {

   // This comes before the darkness action block
   // so we can perform this action in the dark.

   : match "light lamp"  {
      : if (is_carried "lamp" && is_lamp_lit == false) {
         : set_true "is_lamp_lit" ;
         : print "You light the lamp" ;
         : press_any_key ;
         : redescribe;
      }
   }

   // Blocks everything except movement, quit, save, load, inventory, turns, look
   : if (is_dark && is_inaccessible_darkness_verb) {
      : print "You fumble in the dark." ;
      : done ;
   }
}


settings {
   // Tells Adventuron when to override the location description with
   // the darkness message (in the theme system messages), plus will remove direction list
   // and object list from the location layout (when is_dark resolves to true)
   dark_expression = is_dark
}

themes {
   my_theme : theme {
      colors {
         // Set the darkness pen colour to dark blue.
         dark_pen = 9
      }
      system_messages {
         it_is_dark = Darkness surrounds you.
      }
   }
}

9.23. Presentation Mode 2

Warning
This is highly experimental.

Presentation Mode 2 is a work in progress, and changes the way that the event model works in Adventuron.

Essentially, the screen will refresh if the object list or exit list changes as a result of an action, automatically, without having to issue a screen refresh.

The system handlers for get and drop are defaulted to being silent (as getting and dropping success will be conveyed by the updated object list). You can override this if you wish in the on_command block by matching "get _" and "drop _" then doing whatever you like.

Presentation mode 2 also changes the default layout to something more appropriate for object centric gameplay. The layout can be manually restored to whatever you like in the theme. Presentation mode 2 just affects the default.

If something is printed, then Adventuron will automatically insert a press_any_key command before refreshing the screen.

There are a number of gotchas to this approach, the first of which is that an auto-refresh is currently not a full refresh. It won’t call the on_describe() method.

There are a number of ways to mitigate this issue, and more will be forthcoming.

Warning
There is a bug that exists in GET ALL and DROP ALL right now in that one additional tick is being used, but no ticks are being registered. This will be resolved, no need to report it.

Why not just update the object list and exit list in place?

Well, firstly, it’s not as easy as it sounds on different screen sized devices. It may be that there are a lot of objects to display, and adding them will push the screen down. It may be there is a judder. It almost certainly requires a split window, which is something that doesn’t work very well on screens with limited vertical pixels (such as phones with greedy keyboards or excessive notches or both). This approach is the simplest to code and the simplest to use right now. Better approaches may follow.

9.23.1. Basic Demonstration

##############################################
##
## Presentation Mode 2 will automatically
## clear down the screen when the visible objects
## or visible exits change in the current location
##
## In presentation mode 2, auto redescribes do not
## generate a call to on_describe() when
## redescribing. on_describe() is only called when
## a : redescribe; command is issued or when the
## player changes location.
##
##############################################

start_at  = village

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

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

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

barriers {
   block_forest : block {
      location               = forest
      message                = The path is blocked by rubble
      block_when_carried     = sword
   }
}

themes {
   my_theme : theme {
      ## NOTE :: Treat this as experimental for now ..
      presentation_mode = 2
   }
}

9.23.2. Advanced Demonstration

##############################################
##
## Presentation Mode 2 will automatically
## clear down the screen when the visible objects
## or visible exits change in the current location
##
## In presentation mode 2, auto redescribes do not
## generate a call to on_describe() when
## redescribing. on_describe() is only called when
## a : redescribe; command is issued or when the
## player changes location.
##
##############################################

start_at  = village

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

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

on_startup {

   : print "^nc^<-------------------------------------\nPresentation Mode 2 - Auto Refresh Mode\n-------------------------------------<15>>^m^" ;

   : print "<* Type UNLOCK to unlock the exit to the forest without printing anything (instant automatic refresh).<10>>" ;
   : print "<* Type UNLOCKP (after restarting) to unlock the exit to the forest whilst printing a message (a press any key will automatically be placed after the final print message).<11>>" ;
   : print "<* GET/DROP an object to auto refresh the screen.<12>>" ;
   : print "<* GET ALL or DROP ALL to observe one screen refresh only.<13>>" ;
   : print "<* When not unlocked the forest manually (seperate restart) getting the sword will unlock the forest, dropping the sword will lock the forest (exit list automatically updates).<14>>" ;
   : print "<* Auto redescribes do not trigger on_describe() as the describe happens after the on_tick() event therefore it would be dangerous to execute out of sequence or to run another describe without a tick.<15>>" ;

   : press_any_key ;

}

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

barriers {
   block_forest : block {
      location               = forest
      message                = The path is blocked by rubble
      block_when_not         = is_forest_unblocked
   }
}

booleans {
   is_forest_unblocked : boolean_dynamic {(
      is_carried "sword" || is_unlocked
   )}
   is_unlocked : boolean "false" ;
}

on_command {
   : match "unlock _"  {
      // NOTICE :: We do not need to call redescribe here ...
      // If there is no printing, then a describe is automatically
      // called (but on_describe() will not be called in this instance)
      : set_true "is_unlocked" ;
   }

   : match "unlockp _"  {
      // NOTICE :: We do not need to call redescribe here ...
      : set_true "is_unlocked" ;
      : print "You unlock access to the forest" ;
   }
}

on_describe {
   // Playing some beeps to demonstrate when on_describe is called
   // If we printed on_describe here, then it would
   : print "on-describe()" ;
}

on_tick {
   : if (is_at "village" && is_first_entered()) {
      : print "NOTE : There is a tick counting bug on GET ALL and DROP ALL at the moment, this will be fixed shortly." ;
   }
   : beep millis = "80"  pitch = "0" ;
}

themes {
   my_theme : theme {
      ## NOTE :: Treat this as experimental for now ..
      presentation_mode = 2
   }
}

9.24. Linking External Assets

Adventuron supports referencing resources (such as graphics) from external files but the web based editor currently can’t render resources supplied with a relative path (using an explicit url is fine).

To use external graphics files, first put your graphics in a folder, then add records like this to your assets { graphics {} } section.

graphics {
  // The png file will be read from the same path as the game html file
   blah : png "mypng.png";

  // This file should be referencable from anywhere (but only if playing online). Absolute paths can be convenient in development, but for packaging, relative paths are better.
   blah2 : jpeg "https://somedomain.com/somepath/myjpeg.jpg";
}

9.25. Finding An Object

Note
This snippet only checks for direct ownership, and will not snap up to the location id.

Use the < parent_of "entity_id" > function to access the id of the direct parent (or holder) of an object.

start_at = village

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

objects {
   sword : object "a sword"  ;
   lamp  : object "a lamp"  start_at = "inventory" ;
   spoon : object "a spoon" start_at = "village"  ;
   fork  : object "a fork"  start_at = "bag";
   bag   : object "a bag"   start_at = "inventory" container_type="bag";
}

on_tick {
   : if (parent_of "lamp" == "inventory") {
      : print "The lamp is in your inventory." ;
   }
   : if (parent_of "spoon" == current_location()) {
      : print "The spoon is in the same location as you." ;
   }
   : print {( "Location of Lamp  : " + parent_of "lamp" )}
   : print {( "Location of Sword : " + parent_of "sword" )}
   : print {( "Location of Spoon : " + parent_of "spoon" )}
   : print {( "Location of Bag   : " + parent_of "bag" )}
   : print {( "Location of Fork  : " + parent_of "fork" )}

}

9.26. Pocket When Inventory Space Is Short

The following example demonstrates that Adventuron will recover when a pocket command is executed when the player has no more inventory capacity. The gifted object is simply placed on the floor in the location where the player is next. This is very important as some in-game events cannot be repeated, and the object needs somewhere to be.

start_at = village

locations {
   village  : location "You are in the village.\nType <SWORD<12>> to attempt to place a sword in your pocket / inventory (inventory limit is 1 in this game) then it will move the player to the forest." ;

   forest : location "You are in a forest.\nType <SWORD<12>> to attempt to place a sword in your pocket / inventory (inventory limit is 1 in this game)." ;

}

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

integers {
   inventory_limit : integer "1" ;
}

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

on_tick {
   : inventory;
}

on_command {
   : match "sword _"  {
      : print "Attempting to create and put a sword in your pocket, then moving to the forest." ;
      : pocket "sword" ;
      : goto "forest" ;
      : press_any_key ;
      : redescribe;
   }
}

settings {
   inventory_items_limit_var = inventory_limit
}

9.27. Eliminating Parser Delay

Adventuron comes pre-configured with a small amount of parser delay. To switch off this delay, use the following snippet.

start_at = village

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

themes {
   my_theme : theme {
      delays {
         // 0 milliseconds of delay
         default = 0
      }
   }
}

9.28. Implementing A Safe

Adventuron naturally tries to match inputs that the player enters against its vocabulary. There is one exception, and that is in the case of a very and a noun entered.

In the case that one word is entered, or two words are entered (language independent), then Adventuron records the original verb and the original noun.

These will store the exact inputs the player entered. In English, the verb comes before the noun. In other languages, vice versa. The parser is aware of which logic to apply depending on the language it is dealing with.

So, we can access the original verb with original_verb() and the original noun with original_noun(). These are functions that return string values, empty if there was not a value provided.

When dealing with safe combinations, we want to check that the player either entered a number in the verb or noun position.

To do this we simply check that we are in the correct context (in the same location as a safe), then we check to see if either the verb or noun are numeric using the is_int() function (is integer?).

If the original verb contains an integer, then match it in the verb position using match. Match the correct combination first. After matching the good combination, we use a : done; command to stop handling items in the current event block (on_command{}).

We use a similar pattern for matching the combination in the noun position, except that we also check for "dial" as the verb.

start_at  = office
locations {
   office : location "You are in an office." ;
}
objects {
   safe : scenery "a safe" start_at = "office" examine_message="The safe has a keypad.\nType DIAL XXXX (where XXXX is a number to try to open the safe).";
}
on_command {
   : if (is_present "safe") {
      : if (is_int (original_verb())) {
         : match "1234 _"  {
            : print "You enter the correct safe combination" ;
            : done ; // Stops it from matching anything else
         }
         : print "Wrong Combo" ;
      }
      : match "dial _"  {
         : if (is_int(original_noun1())) {
            : match "dial 1234"  {
               : print "You enter the correct safe combination" ;
               : done ; // Stops it from matching anything else
            }
            : print "Wrong Combo" ;
         }
         : else {
            : print "Please type DIAL XXXX (where XXXX is a number)." ;
         }
      }
   }
}

9.29. Containers

Containers are not yet supported by Adventuron (preliminary support is in the engine).

9.30. List Capitalization

The formatting of the object list, exit list, and inventory list can be overridden within the theme settings.

Note
If you only declare one theme, this will become the default theme, no matter what the identifier of the theme is.
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,
   ]
}
objects {
   lamp : object "a magical glowing lamp" start_at = "village" ;
}

themes {
   my_theme : theme {
      lister_objects {
         item_capitalization = original
      }
   }
}

9.31. Masking Commands

The on_command {} event handler contains code that will override the system handlers.

System handlers such as get, drop, wear, remove, go east, go north, etc, are executed when the player input doesn’t match something in the on_command {} block.

If something does match in the on_command{} block, and it’s not a control command (such as done, if, match, else, else_if), then it overrides the system handler (the system handler doesn’t execute).

99% of the time, this is correct behaviour, but sometimes you may want to do something in addition to the system even handler. In these cases, you need to hide your handler from Adventuron so it doesn’t know you’ve executed your own code.

Anything inside the : mask {} command will hide the user handler from the system. This means that the system handler will be executed in addition to the code inisde your mask{} block.

As always, this concept is best demonstrated.

In the code below, try running it as is, then remove the : mask{} block (comment it out) and observe the behaviour difference.

start_at = field
locations {
   field      : location "You are in a field." ;
   meadow     : location "You are in a meadow." ;
   river_bank : location "You are at a river bank." ;
}
connections {
   from, direction, to = [
      field,  east, meadow,
      meadow, east, river_bank,
   ]
}

integers {
   num_times_try_go_east : integer "0" ;
}

on_command {
   : match "e _"  {
      // Anything inside a mask will not override a
      // system handler. In this case, we wish to
      // increment a counter everytime we try to
      // head east, but we don't want to block the
      // system movement handler.
      : mask {
         : increment "num_times_try_go_east" ;
      }
   }
}

on_tick {
   : print "You have tried to move east {num_times_try_go_east} time(s)." ;
}

9.32. How to see which locations are adjacent to the current location

The try_move() function will return a string containing the id of the location in the direction of the verb that the player entered. If there is no accessible location in that direction (no connection, or an active block), then a blank string will be returned.

To check to see that there is a valid location:

: if (try_move() != "") {
   // Do something
}

To check to see there is no location or a blocked location:

: if (try_move() == "") {
   // Do something
}

A larger example is here !

start_at = meadow
locations {
   field      : location "You are in a field." ;
   meadow     : location "You are in a meadow." ;
   river_bank : location "You are at a river bank." ;
}
connections {
   from, direction, to = [
      field,  east, meadow,
      meadow, east, river_bank,
   ]
}

on_command {
   : match "e _"  {
      : if (try_move() != "") {
         // Note :: This overrides the system movement handler (see the mask section for more information on this)
         : print "You can go east, but you choose not to go.";
      }
   }
}

A masked example (uses mask + try move):

start_at = field
locations {
   field      : location "You are in a field." ;
   meadow     : location "You are in a meadow." ;
   river_bank : location "You are at a river bank." ;
}
connections {
   from, direction, to = [
      field,  east, meadow,
      meadow, east, river_bank,
   ]
}

integers {
   num_times_gone_east : integer "0" ;
}

on_command {
   : match "e _"  {
      // Anything inside a mask will not override a
      // system handler. In this case, we wish to
      // increment a counter everytime we successfully
      // head east, but we don't want to block the
      // system movement handler.
      : mask {
         // Try move contains the id of the location
         // correspondin to the direction verb in
         // the logial sentence
         // If the direction leads nowhere or it
         // is blocked, then a blank string is returned.
         : if (try_move() != "") {
            : increment "num_times_gone_east" ;
         }
      }
   }
}

on_tick {
   : print "You have successfully gone east {num_times_gone_east} time(s)." ;
}

9.33. Copying The Value Of A Variable To Another Variable

To copy the value of a variable into another variable use set_integer (for numbers), set_string (for text) and set_boolean (for booleans).

## int_b = int_a
: set_integer var = "int_b"    {(int_a)}
## string_b = string_a
: set_string  var = "string_b" {(string_a)}
## bool_b = bool_a
: set_boolean var = "bool_b"   {(bool_a)}

A full demo of all three types of copy is included below (type COPY at the command to initial the copy.

The location text is formatted to debug the value of all the variables.

start_at = my_location

locations {
   my_location : location "^n^int_a is {int_a}\nint_b is {int_b}\nbool_a is {bool_a}\nbool_b is {bool_b}\nstring_a is {string_a}\nstring_b is {string_b}^m^\nType <COPY<12>> to copy A variables to B variables.";
}

integers {
   int_a    : integer "5" ;
   int_b    : integer "0" ;
}
booleans {
   bool_a   : boolean "true" ;
   bool_b   : boolean "false" ;
}
strings {
   string_a : string "toast";
   string_b : string "eggs";
}

on_command {
   : match "copy _"  {
      : set_integer var = "int_b"    {(int_a)}
      : set_string  var = "string_b" {(string_a)}
      : set_boolean var = "bool_b"   {(bool_a)}
      : print "Copied all A variables into B variables." ;
      : press_any_key ;
      : redescribe;
   }
}

(Advanced)

It’s also possible to include expressions on the right hand side:

# If we are running on a mobile client, then "copy the value of a and add 1 into b", else "copy the value of a into b".
: set_integer var = "int_b"    {(is_mobile() ? int_a + 1 : int_a)}

9.34. Disambiguation of user handled commands

Adventruon currently offers system level disambiguation for system commands (get, drop, wear, remove, examine) but it currently does not support auto disambiguation of user matched commands.

A future version of Adventuron will radically alter the matching system to assist with this so that all user "match" patters can benefit from the same disambiguation without any specific code..

But, for now, here is an example of a workaround when you have multipke objects of scenery with the same noun but different adjective.

Yes, yes, yes, this is a horrible workaround, but it does work, and only needs to be implemented for handlers of objects that have shared nouns.

Something a LOT better is coming - I promise.

start_at                 = my_location

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

connections {
   from, direction, to = [
      my_location, east, my_location_2,
   ]
}

objects {
   white_horn   : object "a white horn"   start_at = "my_location" ;
   magenta_horn : object "a magenta horn" start_at = "my_location" ;
   cyan_horn    : object "a cyan horn"    start_at = "my_location" ;
}

integers {
   horn_count : integer "0" ;
}

on_command {
   : match "examine horn" {
      // Use masking so that this setup part does not override the system handler.
      : mask {
         : set_integer var="horn_count" value="0";
         : if (is_present "white_horn")   { : increment var="horn_count"; }
         : if (is_present "magenta_horn") { : increment var="horn_count"; }
         : if (is_present "cyan_horn")    { : increment var="horn_count"; }
      }

      : if (horn_count >= 1) {
         : if (adjective1_is "white") {
            : if (is_present "white_horn") {
               : print "The white horn makes a DEEP booming sound.";
            }
            : else {
                : print "Not here";
            }
         }
         : else_if (adjective1_is "magenta") {
            : if (is_present "magenta_horn") {
               : print "The magenta horn makes a TINNY sound.";
            }
            : else {
                : print "Not here";
            }
         }
         : else_if (adjective1_is "cyan") {
            : if (is_present "cyan_horn") {
               : print "The cyan horn makes a SMOOTH GROOVY sound.";
            }
            : else {
                : print "Not here";
            }
         }
         : else {
            : print "Be more specific please.";
         }
         : done;
      }
      : else {
         : print "There are no horns present." ;
      }
   }
}

9.35. ADVANCED TOPIC - Understanding Turns and Ticks (Beginners do not read)

Note
This is VERY advanced, and is only provided to better understand the Adventuron game lifecycle better. Beginners - DO NOT READ THIS SECTION - it’s generally not needed.

A turn represents the number of inputs received by the player.

A tick is the number of times that the on_tick {} event handler block has occured in the game (excluding the startup tick).
The first tick is tick 0, and the first turn is turn 1.

Tick 0 runs before first input has been entered by the game (upon presenting the first location). Tick 1 is the first tick that can follow turn 1 (even though it’s technically the second tick). There is no turn 0.

#############################################
# The first tick is TICK 0 (after the first
# room is described). The first tick is enabled
# by defauly but this tick may be configurable in
# a later version of Adventuron.
# -----------------------------------------
# Every submitted command increments turns()
# But some system commands (such as SAVE)
# do not increment the tick counter.
# -----------------------------------------
#
# In the below sample code, the commands ONE, TWO, FOUR
# all generate ticks, INVENTORY and THREE do not generate
# ticks. THREE purposefully stops a tick with the : stop_ticks;
# command.
#
#############################################

start_at                 = my_location

locations {
   my_location : location "You are in a room.\nType the following commands one at a time at the command line (inventory will not generate a tick):\n^n^(1) ONE \n(2) TWO\n(3) THREE\n(4) INVENTORY\n^m^(5) FOUR" ;
}

on_command {
   // Match all words
   : match "_ _"  {
      // Do not match "inventory" (let the system handle it)
      : if (verb_is "inventory" == false) {
         // If the input is "three" then skip downstream ticks
         // (this allows custom responses without the game world pproceeding)
         : if (verb_is "three") {
            : stop_tick;
         }
         // Print how many ticks and turns have elapsed so far
         : print {(
            "Ticks : " + ticks() +  " Turns : " + turns()
         )}
      }
   }
}

settings {
   // This is set to false by default (inventory generates a tick by default, but we can disable that here)
   // NOTE : This is an experimental setting, and may change in a future release.
   experimental_inventory_stops_tick = true
}

on_tick {
   : print {("TICK #" + ticks() )}
}

Expected results:

tick

9.35.1. More on Ticks & Turns

Here is another demonstration of turns() and ticks().

  • The turns() function will return a number that is incremented just before on_command() is executed (can think of turns as commands processed so far).

  • The ticks() function will return a number that is incremented just before on_tick() is executed (can think of ticks as ticks processed so far).

turns() and ticks() can be very much out of synch, and this is normal, as some commands are timeless.

Items in GET ALL | DROP ALL | etc. get their own turn followed by their own tick.

A general rule of thumb is only to use the ticks() function in the on_ticks{} block and only use turns() {} in the on_command block.

start_at = village

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

objects {
   lamp  : object "a lamp"  start_at = "village" ;
   spoon : object "a spoon" start_at = "village"  ;
}

on_startup {
   : print {("- on_startup (ticks so far:"+ticks() + ", turns so far:" +turns()+")" )}
   : press_any_key ;
}
on_command {
: if (true) {
      // Masking makes sure that a command handler doesn't override a system handler.
      : mask {
         : print {("--------------------" )}
         : print {("- on_command (ticks so far:"+ticks() + ", turns so far:" +turns()+")" )}

      }
   }
}

on_tick {
   : print {("- on_tick (ticks so far:"+ticks() + ", turns so far:" +turns()+")" )}
}

on_describe {
   : print {("- on_describe (ticks so far:"+ticks() + ", turns so far:" +turns()+")" )}
}

themes {
   my_theme : theme {
      theme_settings {
         clear_screen_enable = false
      }
   }
}

GET ALL (turn, tick, turn, tick)

tick2

GET LAMP (turn, tick)

tick3

GET LAMP, GET SPOON (turn, tick, turn, tick)

tick4

10. Licenses / Acknowledgements

10.1. Adventuron Classroom License

Adventuron Classroom is licensed for personal non-commercial use.

Free 12 month licenses available to schools.

Currently looking for school pilot-scheme partners.

Use contact information below for enquiries.

Adventuron Classroom License
Adventuron Classroom - Personal Non Commercial Use EULA

Copyright of Adventuron Software Limited, 2017-2019, 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.

10.2. "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.

10.3. 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.

10.4. 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 - 2019 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.

10.5. URLS

Adventuron Homepage:

Adventuron Games:

(sample games can be found here)

Adventuron Classroom Editor:

(desktop computer required)

10.6. 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).

10.7. Contact

Adventuron is written by Chris Ainsley, and Copyright of Adventuron Software Limited, All Rights Reserved.

10.8. 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.
 */

10.9. Libraries Used by Adventuron Platform - Including Adventuron Junior and Adventuron Junior 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
  */