Official Blog of the Adventuron Text Adventure Creation System

Tuesday, 21 July 2020

LOOK, SEARCH, & EXAMINE


What follows is a very personal opinion on the use of LOOK, SEARCH and EXAMINE in the context of interactive fiction / text adventure games.

Traditional IF/TA games typically allow the player to move around quasi-geographic locations in an environment - described in some detail initially. Nouns representing scenery and objects within a location in the environment may be interrogated to find out more information, to discover new layers of descriptions, or even discover new objects.

There are largely three verbs that are employed in this interrogation. EXAMINE and LOOK are generally synonyms, and refer to the act of looking at an object. SEARCH is an additional verb that generally means rummaging or deeply looking at or inside or atop of an object (or noun). 

Many text adventure / IF games take the approach that examining and object and searching an object are two different actions and therefore should be represented by separate verbs. Superficially, this makes perfect sense. Looking at a bag is not looking inside a bag after all.

The former is the act of looking at something (somewhat passively), and the latter is the act of digging through or thoroughly looking at the contents of something (an active action).

When the player types EXAMINE an object should be looked at, when the player types SEARCH, the object should be thoroughly examined inside and out.

Whilst EXAMINE (or the common synonym LOOK) is almost unavoidably required for the purposes of revealing new clues or sub-items that would not fit in the location text (examine and look are synonyms in Adventuron by default), SEARCH is something that really essentially means EXAMINE MORE (in the context of the object).

There is a correctness to keeping SEARCH and EXAMINE separate, but just like gameplay physics in 3d action games does not represent reality, perhaps we need less correctness for the purposes of gameplay in IF/TA.

So let’s get started …

The problem with using SEARCH is that, except when clearly signposted, the player has no idea when something should be examined and when something can additionally be searched.

Some games never use SEARCH, and some games use SEARCH for a few or just one object.
This is purely my own opinion, but SEARCH, if in your game, should be a synonym for EXAMINE (or look).

Making the responses to EXAMINE and SEARCH is padding at best (EXAMINE could fulfil the same role), frustrating at least (if the player knows SEARCH is a verb in the game, then when they are stuck they now have to scour the games for new nouns to SEARCH), and game breaking at worst (the player has played games without SEARCH and thinks that EXAMINE is the same as search, and therefore the game is unwinnable for the player).

There may perhaps be benign uses of search such as items that literally beg to be searched, such as piles of leaves or bodies, but I would still say that the problem with implementing SEARCH as a separate action even if just once in your game is that now the player has uncertainty if every noun in the game will yield progress if they try SEARCH on it too.

To make SEARCH and EXAMINE different response handlers is to invite the player to have to SEARCH and EXAMINE every object, once the moment comes in the game where they get stuck.
In the case of the pile of leaves, you could code a joint EXAMINE and SEARCH routine that yields the same result. If there is an object hidden in the leaves, then reveal it with the examine after describing the leaves.

If an object is clearly signposted as being searchable, then the separate SEARCH is redundant, tell the player upon examination that an additional search was performed if a search action is required to move the game forward.

If the SEARCH is difficult to predict that it will yield a different result to an EXAMINE, then all the more reason to not not require an input the player is unlikely to type (except via a grind pass of the nouns).

If you don’t want to code a combined handler for EXAMINE and SEARCH, then code a single routine that will point the player towards examining “Examining objects will also search them if necessary.”.

As long as the player views SEARCH and EXAMINE as the same then they will not think they have to brute force nouns when the going gets tough. The moment they find one different response for SEARCH, then they now know that they have to grind, or even worse, they are not aware to SEARCH.

If parser-based IF/TA ever has a hope of being acceptable again to a winder audience, then in my view, then reducing parser friction is the only priority.

Almost all graphical adventures have an EXAMINE feature, but not one of them (to the best of my knowledge) has a SEARCH features, because it’s redundant. Imagine there was a SEARCH verb in Monkey Island, and one object something hidden inside. Would that add or detract from your enjoyment of the game?

This isn’t saying that a game can’t be complex, but a game should not be designed to integrate TWO grind mechanics. The EXAMINE mechanic is somewhat of a necessary grind evil, given that examining nouns in a room has next to no creative input from the player. Doubling up the grind, however “correct”, has an adverse impact on game flow (imho).

I’m advocating for making SEARCH and EXAMINE interchangeable ESPECIALLY when the game has an object that must logically be searched. It’s a small precision compromise, but I wholeheartedly believe it’s the right thing to do.

LOOKING IN or LOOKING ON something is different to search in my view. Containers are clearly understood by humans and it’s entirely natural to look in a container therefore if a grind instinct was invoked on LOOK IN and LOOK ON, you will be dealing with a very small (and non frustrating subset) of nouns in the game.

I see no reason why a LOOK IN or LOOK ON can’t be a separate handler without triggering a grind instinct in the player. LOOK UNDER is something I generally don’t think is a good idea to have a different response (to EXAMINE) for as again it could invoke grinding (player trying to look under everything after they get one positive response).

I do think that we are on the cusp of a mainstream IFTA comeback, but if we want to escape the prejudice of the past with regards to parser friction, we should do some work ourselves to meet the player half way.

Tuesday, 26 November 2019

TWO - A Two Word Text Adventure


I recently released TWO, which is a two word text adventure game, written in Adventuron Classroom.



The idea behind TWO is to strip away anything resembling a story, and just focus on puzzles.

The game is available to play here:

https://adventuron.itch.io/two

The treasure hunt genre was chosen for the game because it doesn't require a story and a two word game is a puzzle box rather than IF.

The game plays well on mobile:



"I see more than two words on the screen."

Here are the quite arbitrary rules:


  • Every location has a maximum of two words description.
  • Every object has a maximum of two words description (multiple objects may be listed in a location).
  • Apostrophe'd words count as one word, but no using the - characters to connect words.
  • Every response message is a maximum of two words.
  • The intro text is a maximum of two words.
  • The game over text is a maximum of two words.
  • Items in lists have their own two word allocations (such as directions, objects).

I really enjoyed this exercise in puzzle building, and I think that minimal parser based games really suit mobile as a platform. I'll be creating a gamejam around this rules shortly.

The link above has the full game, as well as full clues, encoded with base64, to avoid spoiling later puzzles. It also has a puzzle dependency chart for the game downloadable as an SVG, a preview (probably non readable, available here. Don't read onward if you want to avoid spoilers ...






































































































Sunday, 28 July 2019

Video Tutorial - Beginners Guide To Coding An Illustrated Text Adventure Game



I very quickly put together a little video on how to create a simple text adventure game involving event hooks, command processors, locations, connections, objects and a block.



Full game available to play here : https://adventuron.itch.io/cave


Source (Non Graphic Version)

start_at                 = lakeside

//loading_screen           = loading_screen

game_information {
   game_name                    = The Cave of Magic
   game_shortname               = Magic Cave
   written_by                   = Chris Ainsley
   year                         = 2019
   short_synopsis               = Find the treasure
   game_version                 = 1.0.0
}

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>>." ;
}
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" ;
}
connections {
   from, direction, to = [
      lakeside, north, forest, 
      forest, north, outside_cave, 
      outside_cave, north, inside_cave, 
   ]
}
on_startup {
   // : print_graphic "outside_cave" ;
   : print "^c^THE MAGIC CAVE AWAITS YOU" ;
   : beep millis = "100"  pitch = "0" ;
   : beep millis = "100"  pitch = "2" ;
   : beep millis = "100"  pitch = "4" ;
   : beep millis = "100"  pitch = "6" ;
   
   : 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 {
   : match "pick apple;get apple"  {
      : if (is_at "forest" && has_not_created "apple") {
         : create "apple" ;
         : redescribe;         
      }
   }
   : match "examine trees"  {
      : if (is_at "forest") {
         : print "Apple trees." ;
      }
   }
   : match "examine troll;talk troll"  {
      : print "<\"I'm so hungry\"<3>>, says the enormous TROLL in the deepest possible voice." ;
   }
   : 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." ;
         : destroy "apple" ;
         : swap o1 = "troll"  o2 = "sleeping_troll" ;
         : press_any_key ;
         : redescribe;
      }
   }
   
   : match "eat apple"  {
      : if (is_present "apple") {
         : 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 Describe                       #
######################################

on_describe {
   
   : if (is_present "troll") {
      : 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>>." ;
   }
   
}

on_tick {
   : if (is_at "inside_cave" ) {
      : beep millis = "200"  pitch = "0" ;
      : beep millis = "400"  pitch = "10" ;
      : print "^r^CONGRATULATIONS !" ;
      : print "^r^YOU WON THE GAME !" ;
      : print "^r^YOUR RANKING IS : JUNIOR ADVENTURER !" ;
      : press_any_key ;
      : clear_screen;
      //: print_graphic "logo" ;
      
      : print "This tiny adventure was written using Adventuron." ;
      : print "Adventuron is a free text adventure creation language and development system." ;
      : print "Visit the website, and make a world of your own." ;
      : print "^r^<www.adventuron.io<12>>" ;
      : end_game ;
   }
}

barriers {
   block_cave : block {
      location               = inside_cave
      message                = THE TROLL IS GUARDING THE CAVE.
      block_when_exists      = troll
      show_blocked_exit      = true
   }
}




Source (With Graphics Embedded as Base64 Text)


start_at                 = lakeside

loading_screen           = loading_screen

game_information {
   game_name                    = The Cave of Magic
   game_shortname               = Magic Cave
   written_by                   = Chris Ainsley
   year                         = 2019
   short_synopsis               = Find the treasure
   game_version                 = 1.0.0
}

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>>." ;
}
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" ;
}
connections {
   from, direction, to = [
      lakeside, north, forest, 
      forest, north, outside_cave, 
      outside_cave, north, inside_cave, 
   ]
}
on_startup {
   
   : print_graphic "outside_cave" ;
   
   : print "^c^THE MAGIC CAVE AWAITS YOU" ;
   : beep millis = "100"  pitch = "0" ;
   : beep millis = "100"  pitch = "2" ;
   : beep millis = "100"  pitch = "4" ;
   : beep millis = "100"  pitch = "6" ;
   
   : 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 {
   : match "pick apple;get apple"  {
      : if (is_at "forest" && has_not_created "apple") {
         : create "apple" ;
         : redescribe;         
      }
   }
   : match "examine trees"  {
      : if (is_at "forest") {
         : print "Apple trees." ;
      }
   }
   : match "examine troll;talk troll"  {
      : print "<\"I'm so hungry\"<3>>, says the enormous TROLL in the deepest possible voice." ;
   }
   : 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." ;
         : destroy "apple" ;
         : swap o1 = "troll"  o2 = "sleeping_troll" ;
         : press_any_key ;
         : redescribe;
      }
   }
   
   : match "eat apple"  {
      : if (is_present "apple") {
         : 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 Describe                       #
######################################

on_describe {
   
   : if (is_present "troll") {
      : 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>>." ;
   }
   
}

on_tick {
   : if (is_at "inside_cave" ) {
      : beep millis = "200"  pitch = "0" ;
      : beep millis = "400"  pitch = "10" ;
      : print "^r^CONGRATULATIONS !" ;
      : print "^r^YOU WON THE GAME !" ;
      : print "^r^YOUR RANKING IS : JUNIOR ADVENTURER !" ;
      : press_any_key ;
      : clear_screen;
      : print_graphic "logo" ;
      
      : print "This tiny adventure was written using Adventuron." ;
      : print "Adventuron is a free text adventure creation language and development system." ;
      : print "Visit the website, and make a world of your own." ;
      : print "^r^<www.adventuron.io<12>>" ;
      : end_game ;
   }
}

barriers {
   block_cave : block {
      location               = inside_cave
      message                = THE TROLL IS GUARDING THE CAVE.
      block_when_exists      = troll
      show_blocked_exit      = true
   }
}

######################################
#  Themes                            #
######################################

themes {
   my_theme : theme {
      settings {
         layout                  = H G D X O
         experimental_enable_crt = true
      }
      screen {
         paragraph_spacing_multiplier                = 0.5
      }
   }
}

assets {
   graphics {
      lakeside       : base64_png "iVBORw0KGgoAAAANSUhEUgAAAIAAAAAoCAMAAAABrwJ6AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAMAUExURQAAAADPAADPz///AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHGCbIwAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjHxIGmVAAABBElEQVRYR+3T0RKCIBCFYaje/5lb4FfEgBFZYKbxu2iK4OzRzLwWewo8BbYCH48PM6V3YEGNGz+BbsmmAn608g1a8hAeL2N2gZ97uOQOHKkX8JfY8KBkChARsNbs8un/+wlaPQWeAmMLhD9jwNJZQwGTYrVXNYdRZezrcc4gOeedYFFw8iZTvUyGFbFNENeO8zuSW3BSkHkVp4jpRJggvY69DgEqiBTMyWCDE874V02kC0buWHbYK/QLeMwRldne6bMVvO3GwIj1lPEzU3ylojbbMww94quxmGVzBRy2DcIQp1RgZAUGBPMLEL+ZXYDwqFiAA9pIj2Y/hMRH+QLs1kf+ztovLtcqnejM1JkAAAAASUVORK5CYII=";
      forest         : base64_png "iVBORw0KGgoAAAANSUhEUgAAAIAAAAAoCAMAAAABrwJ6AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAMAUExURQAAAAAAzwDPAM8AAP8AAP//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgbSMAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjHxIGmVAAAB3ElEQVRYR+2R0XaDMAxD2Vj//5fnyDeJYwKFbmMvvZwxsCSswvLmza/xWeD6gDOeI3bz2t9hmjjSnuPpnTzaCFqF6WsFyBaYDCAlqubnjsbXIOkwC2j8pXOkawkJVyBXYdpgDF6knLPYK0q5ALEGY2C4pYvx7ehawdMoZ8x/AaMJR6qiJyEygFRgMuFQPKiQZd1n0Loa37IT1Q3KzsHRPNxlUI93cGWM/Tw5B4sx3NcHtAe56jAKFNtUcDw2BYfI9wNyNxgaK/+LQ//6by9X3BHb4GplO+nIHmG+rmu93A8bpBKIlTjqv8NZlo+CYhUb2/7Vr14pgGaEF+VXGduvyNigrFcBxfy8h1wJpM58WnhaoII/gZhBDezNzxcgHb4g4wkY4tcelY7NTheI8a0WwRRBGSRGFwp4fk/r6PEJJJ7NtbhUoEoT7QGz/V1vBfx2ipllmrlCASaVsgPYCgwbxAMPHQMyTX6l4dJcAzYbM9sm7vvHBjK9XMAbyMkgsonb27PjVwuUBu7kPrKJ/8EbsAb2t2PL8bp/aCDTTwoUdmw57l8gfQOZ7irQjoBM9xTo+2MDmW4q0Pb/V4FwdGS6pUDcHxrIdE+BsP9/CgxHQ6Y7CsTt5ajIdKXAsnwDCusRZcRkfHUAAAAASUVORK5CYII=";
      outside_cave   : base64_png "iVBORw0KGgoAAAANSUhEUgAAAIAAAAAoCAMAAAABrwJ6AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAMAUExURQAAAAAAzwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEyzCWUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjHxIGmVAAAATElEQVRYR+3OsQ0AIAzEwLD/0jSpIEmFLCHZ5Td/YWZmn7bOcqe6/1hB9UYK6i9O0D1Rgv6HEUwvhGD+AAQCBAgQIECAAAECBDwGRGyT6ABKL7FnoAAAAABJRU5ErkJggg==";
      inside_cave    : base64_png "iVBORw0KGgoAAAANSUhEUgAAAIAAAAAoCAMAAAABrwJ6AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAMAUExURQAAAAAAzwAA/wD/AP8AAP//AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOYrpxQAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAZdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuMjHxIGmVAAAB3klEQVRYR+WWy4LCIAxFO6PO/3+ykFwgQB5AdTVnYSskOSmW1kvjB0cBDykTX+FzDbyIPz68MBjzgQagHMBkyO0G4OuhdUBAwL0GyEb84ihATMCtBmCqcBcP+kwgyudGA9CAcveB3AXifM4bIM+gHUCky3EDcBBP8VkOGYS6nDYARQCCPc4ayMXrvdZtAPmbPL/UAMpPiLWvIMXBbkAHhRN0rSStayHhdUEWQ3VHrAb0aPPqxc/QP5KQZ2M0sOmvTIuBRBu9gcDv7/4epJqoDRh+BVgUEBCiNWD5UVqCGQUEhJ2oK2CAipsg2WK2mf6xgUe7F7RHQAHJFpNuwW/r2rOBQKLL6LP9GRRO9Ls9M26NGs6pFoPQ85daXLZD2/4422vAvX7UG7uY1yJF4IShBItO6fr7qvNIpQ6ndaHfhWMNpDPwKz6M14nuS4VGLYQ09OfayoInMD27CUzqNOuCvxjU929j631YtUv+/hrLhhf9tL2YJ/NESkGqTvEu+hNUXkF9POV4TrOAeN2fQfUIDqUMGzbv+RlYHIM7WSD1iV9AbTTkPYgIh+w+vf5yZMpjJ4MTigxI8sPr7xX0jSl3I2YCdv5/TZCHfRjZx/z/tUyyizcxBte57b/Jf/Jf1xueGxqz721j7wAAAABJRU5ErkJggg==";
      loading_screen : base64_png "iVBORw0KGgoAAAANSUhEUgAAAIAAAABgCAIAAABaGO0eAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAQ+SURBVHhe7ZddspswDEaziy6nr53p4rOFPt7nbiC1I1Bl+QeDLQnn6sw3rW0IhPNBaB+34bn97RjhBRjjBRjjBRjjBRjjBRjjBRjjBRjjBRjjBRjjBRjjBRjjBRjjBRjjBehRdO0FiBMUQ2DM8AIEQe+IF6ABeC+a9QJkqXlHvAApDtUDXsBkwHu/RC9gGqe8I17AHC5b8wLm4AUY4wUY4wUY4wUY4wUY4wUY4wUY4wUY4wUY88kFvF55AmwlxpAPKYAJvRArli+AeTyf5JnQZ9UCqLU8cXu22BN9liyAWTtM3scjndIos1gBTFYzJx4C2ocyKxWAjvacUHwqmixTAHNUTr5b8YNHR9NkjQKYIIWocfcCEilkzBJ3zBZL6djtfVI1blpAYmQkA4fSYW4Bo2EKsqT3byq38Xz0JB6Mr/CvV8kQlz/PPjj6PQLs+i8nV8lyuANGgSkF3Mh+IxceEQXGCxC133urykWawQIm2L8MMzUYK0YKmGOfiejPXNjBaUQZKWAO7GpvGFGueZxmP8Cutp39RVp/Nwg0KsoFlVr2J6tMO2seXJOzNmfapzAFLHF7ttiRc59C2HqIHKeEzrdfu0JcP5uRf+yzdRo5+p2K3PvsOjEMtpUlbs8WewKwxVqE6NQqYh9g11lMDtvhbBoHIc9Q0qsQPWYF7QP0OjtTg+2GYbCtPRHiUK64fWC/yIs/JpgabLcLEaLtV8k+wC445MIbtT/9ZYvSUKxqH2BXXk5lt462msbJYemh8IsJUbNsYB/Bix/N2KEQOp5OUbSlfQrVoRZKvjKd3PVd7OegozwTETpsDab7vvYPoeIOE3fPFll0oMbXuPcpdD0PeZc2dBc2aYLSF7j3+zWxPQup7KMPeF/APoVZy20uRFC/mP0cor7we0JzQ5a3vzRu3xK3b4nbt8TtW+L2LXH7lrh9S2baj//zLCVu+v0j5D2M0OnrL88x4VtjKF9fW3Z+/voTsk3S6fPxZIF1TSafElwH0HugXQCT3lUA9U7HqJ50UCuASTcpQPB8tACgXcAJqHEKkR7Zp+0CYNEE2XPXCmCJ6/sTgDmgXQBLxxOAgR10ED9ZowA6jYMe6ZR2AUhaAEinY33piMZZawVsk6wA7KCrD9oBjisFBNA72g+wG1+tD41zgH3WQa2AON47wBwD3iEALYCO3zD7AHaA2TaIIX6CO8Ps6/Ot7Zvj9i25kf3815a+MDAN4OUB7w/6IgHKb5FwNhoA3hM0BHxnjP9w4QntQfW0A2a8vwCabdOuPumASg/gFIyjelIA9T7YAT2zMVR6AKeHxhloHP/cBumN/3+KxotgATuDxhnLFIA5pF0ASwQLgAFOAeECbkS7gH7aBSCFAgA2/T4FBFA6DgKXCwDOFQBjmIJ3LIDUQDv4tD5APdoPjBSQjEkBdBxB73Ba+BPU0xDA+6fZdxxFHo9/8ttiddHMrZsAAAAASUVORK5CYII=";
      logo           : base64_png "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";
   }
}

Wednesday, 22 May 2019

Theming


I made a short video demonstrating how to import custom fonts + images into Adventuron (Classroom).




The font used in the screenshot is "Dead Forest" by Damien Guard, and the image used is by Andy Green.


Monday, 20 May 2019

Coding A Room Escape Game In Adventuron


Single location "escape from the room" games started with the parser, with 1988's "Behind Closed Doors" series, and sans-parser, the genre is more popular than ever. I thought I'd produce a tutorial of how one might take the genre back to its roots.

In this post I include the Puzzle Dependency Diagram of a trivial room escape game, and include the final source code for the game (minus theming).

  • The full step by step tutorial is available here.
  • The game can be played here.
  • The PDC was produced using Vizon, here.








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" ;
      }
   }
}