X‐TADS ‐ An XML Driven Text Adventure Development System - ThunderSOS/1984 GitHub Wiki

Introduction

Welcome to the XML Text Adventure development system!

I’ve used a few of these in the past, early ones for the old ZX Spectrum home computer back in the 80s – I remember The Quill and Graphic Adventure Creator! I owe a large debt of gratitude to these creations (and indeed the many text adventures I played on those platforms way back when) for the inspiration to write something like this.

The system is written in the Java programming language. It is already extensible in many ways but it is my intention to make it possible to add new custom Renderers and other things (we'll see exactly what that means later on) extensible but for now I may just document a few of the key classes.
I’ll relegate that to the appendices for later.

So let’s start with the basics. Are you familiar with XML? Probably not but it’s a simple system, you have HTML-like tags with attributes except with XML you can make up your own tags, so they can be pretty much anything you like, they don’t have to describe a web page.

There’s no programming in this system; everything can be described using various files with some XML. I will endeavour to show you what the system expects in terms of room descriptions, items, tasks, events and non-player characters (referred to throughout this document as NPCs).

All you need to create your adventure is an idea for a game!

XML – A Very Brief Introduction

This guide is not intended to be a tutorial on XML, suffice to say XML is a flexible markup that is pretty good for defining structured data, particularly text data. And any text adventure requires a decent amount of data – think of all the locations you visit, objects and characters you can interact with, events that occur and all the other things that you can do in these immersive worlds.
All this is data so we need to be able to define this data in a sensible and structured way.

https://aws.amazon.com/what-is/xml/ looks like a reasonable introduction.

General Syntax

All the game files need to follow the syntax rules briefly described here.

XML allows you to define “elements” also referred to as “tags” that may have “attributes” and use these as a simple markup. The terms ‘tag’ and ‘element’ do have specific meanings but are often used interchangeably.

Elements are just names surrounded by angle brackets, e.g. <room>. No spaces are allowed in these names so you can’t have <living room> as an element but you could have <living-room> (with a hyphen).

Elements can contain attributes. Attributes sit within the tag as a name=”value” pair; value is always in quotes. The attribute name is separated from the element name by a space hence why you can’t have a space in the element name, that would be interpreted as an attribute.
For example:

<room id=”1">

room is the element name and id is an attribute.

There can be as many attributes as you like, e.g.

<room id=”1” name=”Living room” purpose=”relaxing”>

Every element must be closed with a closing tag so <room id=”1”> is closed with </room> or if there’s nothing else inside it (you can have elements within elements, see below) then you can use the shortcut slash at the end like this:

<room id=”1”/>

An element can contain what is called character data or CDATA for short, this is just some text that lives between the open and close tag. For example:

<room id=”1” name=”Living room”>Description of room can go here.</room>

Elements can be nested (elements within elements) so

<garden>
  <furniture>Table</furniture>
</garden>

is valid and you can have multiples of the same element inside another element e.g.

<garden>
  <furniture>Table</furniture>
  <furniture>Deckchair</furniture>
</garden>

You can have multiple of the same element inside another element and/or multiple different elements inside one another.

In fact every element in the whole document must be nested inside a ‘root’ element. So for example in a rooms.xml definition file we have:

<rooms>
  <room id=”1” name=”Living room”>… </room>
  ... more rooms ...
</rooms>

One restriction is elements can’t have both text and other elements inside so:

<garden>Description of garden
  <furniture>Table</furniture>
  <furniture>Deckchair</furniture>
</garden>

is not valid in this system. When we need both we just make another element containing the text, e.g. a <description> inner element.

(Technically, this kind of thing is legal in XML generally but the JAXB system I'm using to parse it doesn’t support this and to be fair, we don’t need it so it’s OK).

XML Entities

Lastly, you may wonder what happens if you need to use < or > in your CDATA text or " (quotes) in an attribute value?
The answer is something called an entity reference. Sounds mysterious and complicated but all it is doing is replacing those characters with a small alternative sequence of characters that mean the same thing. There are only five of these (by default). They are as follows:

Entity Meaning
&lt; < less than
&gt; > greater than
&amp; & ampersand 
&apos; ' apostrophe
&quot; " quotation mark

Just use for example &gt; wherever you want want > to appear in text.
See further down when we describe some verb definitions.

So that’s pretty much all there is to it.

XML Header

One last post script, you will notice every file starts with the following line:

<?xml version="1.0" encoding="UTF-8"?>

Nobody knows why anymore... we just do it. Well, OK – it defines the character encoding the XML parser uses; UTF-8 but I can’t remember ever using anything else.
There’s no real need to go into it here but UTF-8 is a character encoding computers understand that includes loads and loads of different characters such as Greek and Arabic letters, mathematical symbols, basically everything you’ve ever seen written down.

You'll never need to change the version number.

Last Note

XML is not a programming language so don’t panic if you’re not a programmer. It’s just a convenient and flexible way to describe data.
If you make a mistake when typing something in the game will show an error when you try to start it up and often it will give you a line number and position where the error is.

There will be plenty of examples as we go along.

Game XML Files

There are a standard set of data files expected for your adventure, each one has a .xml suffix. All of these files can be split across multiple files of the same type. Multiple rooms_xxx.xml files, items files etc.

The files are:

game.xml – This file gives you startup conditions, the game clock definition, wallet and currencies, the player - what items are initially being carried, hit points, etc. Basically all your initial game state. You can also set some global properties (flags) and counts here if you wish.

One very important thing the game.xml file does is it defines the debug flag. If you set <game debug="true"> in the root <game> tag, extra information about everything the engine is doing as it evaluates your conditions and consequences will be output which could be useful when something isn't working as you expect it.

Remember to switch it off again before releasing your game!

The last thing the game.xml file does is give you the definition of every verb the engine understands including all the directions it knows about.

To define these things you need to know what "class" to map the verb to. This is the thing that defines what the system does when it interprets a verb, like when you type INV or INVENTORY and it lists everything you're carrying - something behind the scenes needs to actually do that.

You don't need to know anything about how these things work, just that the verbs defined in the game.xml file use them. It's important to get the spelling of the class name the exactly right including capitalisation if you define any new verbs.

I've given a complete list of each of these classes in the Appendices, there's not many and I don't envisage many new ones being needed as (we'll come it) the DoTaskHandler can cope with almost anything that needs to change in the game world. And you can map as many verbs as you like to it.

A complete description of the game.xml file is given in Appendix B.

The rest of the files the system expects are as follows:

rooms_xxx.xml – descriptions for every room. There can be multiple of these files all starting with the prefix ‘rooms’ and ending with .xml so you can group rooms logically into areas of your map.

items_xxx.xml – all the items that can be found, picked up or otherwise interacted with. Again items can be split among multiple files with name starting items and having a .xml file type.

synonyms.xml – supplies some synonyms for nouns although another way to achieve this is to define empty items with the synonym you want as its name. Swings and roundabouts. There are advantages and disadvantages to each approach.

Then after that we have the files that essentially define puzzles and interactions.

events_xxx.xml – events that can happen either as a consequence of player actions or they are just things that happen randomly in the background. These are split into multiple files so you can group them logically, each file shout be prefixed ‘events’ and ending with extension .xml.
I tend to split these according to events associated with areas of the map plus another file for more general events.
We'll come to types of event and how to define them later on.

tasks_xxx.xml – tasks are essentially the puzzles you solve.
Again we can split these either logically or simply because you don’t want the file to get too big.
I tend to split these along the same lines as events.

npc_xxx.xml – Non Player Character state machines (NPCs). Unless you have a bunch of NPCs that don’t do anything except say hello I’d definitely split these into different files as even two NPCs in the same file can get quite difficult to read through.

And that’s it! You’ll be amazed with what can be done with minimally just seven files. Actually even less if you don’t define any events or synonyms.

Game Development

When developing your game these .xml files need to live in a folder called dev under the main folder of your install.

Simply typing run (run.bat or ./run.sh on Linux or MacOS) will run your game directly from the XML in the dev folder.

If you prefer to keep your files in a different folder you can use run <folder> to run your game from there instead.

If there is no folder then the run script will look for a file with the same name which contains an encrypted version of the folder contents.

If you don't provide a folder name and there is no dev folder either then the run script will attempt to run a game from a file called gamedata.dat.

So it will check for a specified folder first if provided, then a folder called 'dev', if that doesn’t exist ir isn't specified it will expect a gamedata.dat file to run a game from.

gamedata.dat is an encrypted version of all the game xml files found in the dev folder. Encrypted because obviously these files contain the solutions to all your puzzles.
Of course anyone with enough tenacity and know-how will be able to figure out how to decrypt it but it will at least keep your puzzles safe from most prying eyes.

There are a few options for generating the gamedata.dat file (it doesn't have to be called gamedata.dat for starters) but we will cover that in Appendix A.

A sample folder is provided with a game.xml file providing verb definitions and (eventually) a skeleton game. You can rename this folder to dev to start building your own game.

When a player SAVEs their game the save files are also encrypted in the same way.

Verbs

So let's have a closer look at verbs and how they are defined.

All verbs are defined in the game.xml resource file. This defines the verb, any prepositions or adverbs it understands, any synonyms for the verb and it’s implementation class (as touched upon above).
You will also define the help output that shows verb syntax that should be used by the player.

You can create as many synonyms for any verb as you like, they will all automatically point to the same handler. Synonyms are defined by using the | (pipe) character to create a list.

Technically the parser will only interpret words it knows and should there be more than one verb in a sentence only the last verb read will matter. So it won’t make any difference if the player types something like GO NORTH, GO will be ignored unless you explicitly define it as a verb and map it to a handler.

Words the parser doesn’t know as verbs, adverbs, nouns, adjectives or prepositions are actually stored up and if needed it will attempt to interpret them as the name of an NPC.

As an aside:
Internally every action requires a handler, e.g. directional movements are all handled by the DirectionHandler class.
The majority of verbs are handled by the general DoTaskHandler class which invokes a set of actions that you define so it can be made to change almost anything in the game world.
This means new verbs rarely require a new specialized handler, the existing handlers should cover everything.

Tasks are fully described later.

The verb handler classes are all found in the java package
org.happysoft.games.action.handler
in the jtextadventure.jar library file for those interested.

Directional Verbs

The first category is directions.
OK, yes technically these aren't verbs but they are treated as such.

All compass directions plus N, S, E, W, NE, NW, SE, SW (plus their fully spelt out versions, NORTHEAST, etc) and UP and DOWN are category one verbs mapped to the DirectionHandler class.

The system actually understands a set of canonical directions (standard directions) and you map the directions the player types to these, i.e. you map NORTH and N to the canonical direction NORTH.
This sounds redundant but imagine if you're writing in another language and your word for NORTH is ZULU - doing it this way means you can map ZULU and Z to the internal direction the system understands as NORTH.

Directions are defined in the game.xml in a <directions> element as follows:

<directions defaultHandler="org.happysoft.games.action.handler.DirectionHandler">
 <defaultHelp>
   Move the player in the compass direction specified or UP or DOWN. 
 </defaultHelp>
 <direction direction="NORTH" canonicalDirection="NORTH" display="North"/>
 <direction direction="N" canonicalDirection="NORTH" display="North"/>
  ... more direction definitions
</directions> 

You'll notice there are three attributes for each direction definition:
The first direction is the verb or what the player is expected to type.
The second canonicalDirection is the 'system' or underlying direction its mapped to.
The third display is what is output when describing a room and its exit list.

Note that this (for the time being at least) is one of the few places where a | separated list of words isn't supported. You can't define NORTH|N against the canonical direction NORTH.

The set of canonical directions can be added to as well using the <canonicalDirections> element in the game.xml file.
Using this you can expand the compass directions to a 16-point compass or even 32-point.
You can add IN and OUT if you need them.

An example is provided in game.xml, commented out by default.

The default set of canonical directions is what you'd expect:
NORTH, EAST, SOUTH, WEST
NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST
UP, DOWN.

These can be added to but you can't remove any.

Movement Modes

<movementModes>
  <mode verb="CRAWL" timeMultiplier="2"/>
  <mode verb="RUN" timeMultiplier="0.5"/>
</movementModes>

Movement modes primarily change the amount of time taken to get somewhere. CRAWL SOUTH takes longer than just SOUTH (twice as long) and RUN SOUTH is faster still taking half the amount of time.
The timeMultiplier attribute changes the default amount of time taken to get from one location to the next. This is defined with the exit definitions in each location on the map.
There's a second use for movement modes when defining room exits. We'll cover this later when we get to room definitions.

General Verbs

The second category is for standard things you can do in any text adventure: picking up and dropping items, (re-)describing the current location, checking your inventory, examining objects fighting, etc.
These verbs can be used in any location.

Other standard category one actions include:

ATTACK|KILL, attack an NPC (optionally WITH a weapon).
BUY and SELL – Buy or sell something from an NPC.
EXCHANGE|SWAP, swap an inventory item for something an NPC is offering (item price matters here).
EXAMINE|EXAM, take a closer look at an item.
GET|TAKE, pick up an item.
DROP, drop an item (leave it in the current room).
HELP - Get some help (currently restricted to just syntax).
INVENTORY|INV, check what items you’re carrying and how much money you have.
LOOK, re-describe the current location. Locations may change after some actions, exits added, removed, the description has been changed or an NPC has arrived or left.
PUT, put an item in a container such as a cupboard or drawer – see below for containers (also PUT ON clothing etc).
SAVE, save your game.
LOAD|RESTORE, reload a saved game.
SCORE, show your current score.
TIME, what time is it? Game time can be disabled, if disabled this action will print a message telling you so.
QUIT – Give up and start over.
WAIT|WA, wait for a while or until a specific time.\

Here’s a typical verb definition found in the game.xml file:

<verb synonyms="SWAP|EXCHANGE|OFFER" handler="SwapHandler" acceptedPrepositions="FOR">
  <help>
    SWAP [adjective] noun FOR [adjective] noun; Ask an NPC to swap something you're carrying for something they are willing to trade.
  </help>
</verb>

Each of these verbs has it’s own handler (up to synonym), so SwapHandler above or LookHandler, TakeHandler etc.

Task Verbs

The third category is for completing tasks. These are the actions the player needs to use to accomplish any task.

Tasks can be as simple as opening a cupboard.

These verbs can only be used in particular locations or when a specific NPC is in the room or with a particular item. There is a full discussion of this class of verb in the section below on tasks.

This class of verb often makes use of a preposition so the sentence can specify an action object and a target object or an action object and an NPC.

Here’s a typical verb definition found in the game.xml file:

<verb synonyms="JEMMY|PRISE|SMASH" implementation="**DoTaskHandler**" acceptedPrepositions="WITH|USING">
  <help>
    JEMMY [adjective] noun WITH|USING [adjective] noun; Jemmy or smash something open (e.g. lock, window, door)
  </help>
</verb>

You can add more synonyms or more verbs as needed, the implementation is defined by a task in one of the tasks_xxx.xml files. JEMMY, PRISE and SMASH all do the same thing.

All of these verbs are mapped to the DoTaskHandler.

So these verbs are much more general in scope than the first category as the consequences of using them are fully scriptable and can affect the player, items the player is carrying, items in the current room or any room, the room itself (the description can be changed, exits added or removed), invoke an NPC or multiple NPCs – basically any object in the game world can be manipulated as a consequence of completing a task.

See the section on tasks for full details on how to script tasks.

Verbs With Adverbs

The last type of verb construct is those that use an adverb. Adverbs can be used to make a verb context sensitive.

These verbs can be used anywhere like category one verbs or like category two verbs where they're mapped to the DoTaskHandler or other special handlers which map certain "classes" of item (items with a particular tag) to an event.

A full discussion of this form is given later in the section on Events.

Suffice to say the event is defined per item and verb so different items can change the world in different ways with the same verb.

Other adverbs may be defined as essentially further synonyms for existing verbs, e.g PICK UP is the same thing as GET or TAKE but PICK LOCK means something different.

These verbs have to be defined against the AdverbHandler with an extra <adverbs></adverbs> element enclosed within the main <verb> element. The <adverbs> element define each adverb to be used and a more specific handler that that adverb invokes. e.g:

<verb synonyms="SWITCH|TURN" implementation="AdverbHandler">
  <adverbs>
    <adverb names=”ON” handler=”ItemActionListener” itemTag="activatable"/>
    <adverb names=”OFF” handler=”ItemActionListener” itemTag="deactivatable"/>
  </adverbs>
  <help>SWITCH ON|OFF [adjective] noun</help>
</verb>

The itemTag attributes are used by ItemActionListener to help ensure the item specified in the sentence is the right kind of object for this action.

Here’s an example of a verb where the adverb forms override the original use, so the verb performs a different action when it is used with the adverb to what it would usually do:

<verb synonyms="TAKE" handler="AdverbHandler" acceptedPrepositions="OUT" onCompleted="Taken">
  <help>
   TAKE [adjective] &lt;noun&gt;; TAKE an item from the current location. Use TAKE ALL to pick up all objects from the current location
   TAKE [adjective] &lt;noun&gt; OUT OF [adjective] &lt;noun&gt;; Take one object out of another (aka REMOVE FROM)
   see also: GET, PUT, DROP
   </help>
   <adverbs defaultHandler="TakeHandler">
     <!-- TAKE OFF x (take off mask, etc) --> 
     <adverb adverbs="OFF" handler="ItemActionListener" itemTag="wearable"/>
  </adverbs>
</verb>

The adverbs enclosing tag defines the defaultHandler which is to be used when no adverb is supplied. When the adverb OFF is supplied we delegate to the event system using ItemActionListener to invoke an event for what happens when you take the off the article.
When no adverb is supplied it reverts to the default TAKE behaviour which is a synonym for GET.

There's a little more to explore about adverbs and handler selection but I'll come back to that after we've discussed items and events. I'll endeavour to explain the ItemActionListener and how to set up more detailed verb interpretation rules where the mere presence of an adverb isn't quite enough to fully determine what to do.

Items: Nouns, Adjectives and Articles

So now we've discussed verbs let's look at nouns and adjectives. Items are the objects avaialable throughout your game that the player can interact with.

All nouns and adjectives the engine understands are extracted from item definitions in the items.xml file. So the game engine doesn’t have a fixed list of nouns that it understands, they are completely determined by you, the author.

Items may be split across multiple files each called items_<something>.xml so you can split item definitions in whichever way you feel appropriate.

Here's an example item.

<item id="432" name="ASSEMBLED BOARD" price="15">
  <description>
    An assembled circuit board for plugging into (spoilers).
    It has a connector along one side that snugly fits into a (spoilers) adaptor.
    There's a bus alongside one of the chips, you wonder what that adaptor is used for.
  </description>
</item>

Nouns and adjectives are extracted from the name attribute, so here the noun is BOARD and adjective is ASSEMBLED.

Now consider:

<item id="410" name="BOARD GAME" price="20" adjectiveIsAdjunct="true">
  <description>
    Square ivory tiles carved with a black ebony letter and a smaller number inlaid on each one. 
    All the tiles are kept in a green baize cloth bag.
    The board is of maple or similar hardwood and has curious coloured squares in a star pattern 
proclaiming double points and triple points.
  </description>
</item>

In this case the NOUN in this case is GAME and the adjective is BOARD.

There is a slight complication here – because BOARD is already a noun the grammar parser needs a little help to distinguish which one you mean, so you need to set attribute adjectiveIsAdjunct=”true” to overcome this.

Along with the name (adjective and noun) goes an article. So I could have defined name="THE ASSEMBLED BOARD" or "A BOARD GAME" but you can declare article as a separate attribute which is simply article or it can be declared with the name.
So setting name="THE ASSEMMBLED BOARD" or setting article="THE" and name="ASSEMBLED BOARD" in your item definition are the same.
The article is used when the description is output.

Most of the time the article will be THE so this is the default if not specified but A, AN, SOME, YOUR basically anything else can be used if and where appropriate. If you need multiple words, such as ‘A FEW’ then you’ll have to use the article attribute. The system will lose words if you have name="A PAIR OF SOCKS" and you'll end up with the display name as 'A PAIR SOCKS' with an adjective 'PAIR' and noun 'SOCKS' which is probably not what you want. So in the case you would set article="A PAIR OF" and noun or name as 'SOCKS'.

So, the article for any item is ‘THE’, THE ASSEMBLED BOARD, THE DESK, THE RUSTY KEY, etc but if you set an article=”A” attribute in the <item> tag or just set the name to “A BOARD GAME” you can override it to A or anything else that is appropriate.

The article is used in some output such as when the player lists their inventory or when a trader is selling something to you.

Also articles are ignored in player input so TAKE SOCKS or TAKE THE PAIR OF SOCKS are treated in exactly the same way.

Any new words introduced by the use of the article attribute are added to the ignored words list so be careful not to override an existing noun or adjective.
So article="A PAIR OF" is likely to be fine for a SOCKS item, but if you set article="BLUE" for whatever reason you might well cause problems for the BLUE WIRE or some other object.

There are also noun and adjective attributes that you can use in place of the name attribute.
I envisage the main use of this is when developing a game in languages like French where adjectives usually come last in an item name but there are some legitimate exceptions. e.g. imagine the following item:

LE PETIT PAIN:

<item id="..." noun="PAIN" adjective="PETIT"/>

if instead you'd defined:

<item id="..." name="LE PETIT PAIN"/>

you'd end up with PAIN as an adjective and PETIT as the noun because adjective is expected to be last.

Adjective last item name parsing can be switched on by default in the <system.properties> file.

Item Descriptions and Hidden Items

Description is often just a description attribute in the item tag but for more detailed or extensive descriptions you can enclose it in a <description><description> element within the full <item> definition.
If both happen to be present the (assumed to be) more detailed version in the description tag takes precedence.

One other attribute can be set, hidden=”true” (default is false). This means the item won’t be listed when the room description is output.

Sometimes because an item is listed in the location description as you enter a room that can be a clue in itself. Ah what’s that? I must have to do something with it. The hidden attribute can be used to prevent that. If you do use this attribute then the room description really should allude heavily to its existence.

Example:

<item id="102" name="LAMP" 
  description="The glass will definitely fall if struck with something. You're surprised nobody has broken it already." 
  fixed="true" 
  hidden="true"/>

The room description that the lamp is in alludes to its existence and why you might want to use it in some way:

<room id="104" name="a ruined bandstand." youPrefix="by"> 
  <description>
    The remains of a bandstand rise like broken teeth, its roof long collapsed. This part of the park feels quieter, as if it's been
forgotten.
    A lamppost stands next to the bandstand, paint peeling and it’s heavily rusted beneath. 
    It's been many years since it was last lit.
    A pane of cracked glass dangles precariously from the rusted lamp housing catching the light. 
    It looks like a stiff breeze would blow it down.

    To the South lies Freedom Square but the route is blocked by patrols.
  </description>
</room>

This attribute has a few uses apart from just hiding the item from the usual room output such as when an item is also virtual as discussed below.
Is hiding ordinary items really fair though? Well, it's up to you whether you use it of course.

Note that some items are always marked hidden such as default room items, you don't need them showing up when you walk into every single location.

Prices and Trading

All items can have a price attribute set. The price is purely numeric, the currency being defined for the game as a whole. (Yeah, there’s no international or interplanetary trade just yet).

If a price is set then the item can usually be traded with a trading enabled NPC (Non Player Character) using the BUY, SELL and SWAP verbs. Also SHOW works to get a trader to give you an offer without committing to the trade.

We cover NPCs more fully later on.

Fixed Items

<item id="2" 
  name="DESK" 
  description="It is out of sight of the Telescreen in an alcove. This means the drawer could be used to store contraband." 
  fixed="true"/>

The attribute fixed=”true” means it can’t be picked up (the default for fixed is false).

Containers

Some items are naturally used to store other items inside, obvious examples being a cupboard or the drawer of a desk.

<item id="6" name="THE OPEN DESK" 
  description="The drawer is open." 
  container="true" fixed="true" 
  prefix="In the drawer of the desk is ">
  <contains itemIds="7|8"/>
</item>

This item is a container item, meaning other items can be placed inside it. The item is also fixed meaning it can’t be moved (picked up).

The prefix attribute is used to make the description flow more naturally when the room is described or when the player enters the LOOK command.

So in the desk is item 7 (the DIARY); prefix is set to “in the drawer of the desk is “to list out the items it contains. If a container item contains another container item it will be listed but not any items it in turn contains. Technically this is known as a recursing – I did make it like that for a while but realised it’s a can of worms as you’d really have to have a sense of volume or weight to keep putting one object inside another and I don’t really want every item to need that amount of meta data. You can either it pick it up or you can’t.

Containers enable the player to type PUT X IN Y where Y is a container item. Basically you can put anything inside a container, it doesn’t check volume or weight or anything.

The upshot of all this is be careful defining containers, I recommend the following rules of thumb:
a) make them large (in description – cupboards and such things – so the player can’t put a sack of coffee beans inside a matchbox.
b) make them fixed so the player can’t move them and hence they won’t be able to put one inside another – so you can’t even create the situation where you can put a sack of coffee beans inside a matchbox.

Note that you can still create tasks for OPEN MATCHBOX to get a match without it being a full container. It just requires a bit of work. You'd need to set a flag to say matchesAvailable and then a LIGHT MATCH command can check this condition to make sure you can use them.
This way you can simulate a container but you won't be able to put any old object in it.

Tasks are discussed fully later on.

There is another option too as items can be declared that it accepts other items but this is probably overkill for a matchbox.
I'll get to how to declare and use that kind of item in the section below on Holders.

Ultimately it’s up to you as the game designer which way you go.

Holders

Other items might require further items to work or to complete them, consider the torch and batteries scenario:

<item id="23" name="A TORCH" 
  description="A battery powered waterproof torch. It requires batteries." price="4">
  <accepts itemId="24" eventId="200102"/>
</item>

<item id="24" article="SOME" name="BATTERIES" 
  description="Some standard sized batteries." 
  price="1"/>

This torch declares it accepts item 24, the batteries. This enables the player to type
PUT BATTERIES IN TORCH
without the game thinking the torch is a general container or even allowing anything else to be put in it. So, you can’t PUT DIARY IN TORCH because TORCH is not a container.

When the player types PUT BATTERIES IN TORCH, the engine runs event 200102, as specified by the <**accepts**> element.

Events are covered in detail in the next chapter. For now, simply think of an event as a list of actions that the engine performs in response to something changing in the world.

The game engine does not assume what adding one item to another should do in terms of your game. Different objects may power up, unlock, transform, or consume the added item, so the behaviour is defined by the event. The event just defines a list of things that happen in response to this particular change.

If the added item can later be removed again, the event must associate the two items using something called the combineItems consequence so that we can check the batteries are actually in the torch before removing them. This is covered in more detail when we talk about the events.

There’s lots that can be done with this mechanism, imagine PUT GEM IN STATUE and the statue sinks and a new door opens up behind it, or PUT KEYS IN IGNITION and now you can start the engine. Even PUT PASSWORD INTO COMPUTER and the computer unlocks allowing you to read previously secret information.

You don’t have to use PUT either, you can define a task and other verbs against the DoTaskHandler, e.g. ATTACH, CONNECT, INSERT, whatever is appropriate. REMOVE is a task handler verb so item removal has to scripted. i.e. REMOVE BATTERIES FROM TORCH
has to be scripted.

Tags

Items may have a list of tags. Tags define a general class for an item, wearable, activatable, stolen, contraband etc.

Tags are just words, they don't mean anything special to the system but you can define certain events to happen when the player types a command that interacts with an item that has a particular tag.

So yes, tags are mostly used in conjunction with events, the presence of a tag may incur 'consequences'.
Tags can also be added and removed by events or tasks, so stealing an item might add a tag 'stolen' that other tasks can see so a different reaction happens from usual.

Of course, groups of items can be identified by tag so multiple items can be collected together this way.

Tags are specified in the tags attribute if specified along with the item or they can be added and removed at runtime by events and tasks. If using the attribute multiple tags are specified using a pipe | delimiter, e.g. tags=”stolen|contraband”.

Weapons

Items may be weapons.
You define a weapon inside the <weapon> element inside the item tag.
Weapons need to define 2 sub elements, <hit> and <miss> and may define one further element <empty> for when it runs out (see consumable items below).
The <hit> tag defines the chance and some text to be shown if the attack is successful.
The <miss> tag just defines text for when you miss.
You may have | delimited alternatives for these text blocks and the system will choose a random one on each turn.

<item id="400" name="A CROWBAR" price="7">
  <description>A solid iron jemmy, a bit rusty but definitely still useful.</description>
  <weapon damage="15">
    <hit chance="6" probabilitySpace="10"
         selectorTag="female"
         noMatch="You swing the crowbar at :1, it connects and he staggers back."
         match="You swing the crowbar at :1, it connects and she staggers back."/>
    <miss selectorTag="female"
        noMatch="You swing the crowbar at :1 but they nimbly dodge aside."
        match="You swing the crowbar at :1 but they nimbly dodge aside."/>            
  </weapon>
</item>

You usually use a weapon from the ATTACK verb or any synonyms you define but it can be scripted from a task to support other verbs. For example you probably don't want THROW to be a full synonym for ATTACK so you can create a task to cover THROW ROCK AT <npc>. When scripting an attack this way you'd use the doAttack action which hooks back directly to the ATTACK verb handler and this way the THROW ROCK task becomes an attack as opposed to just THROW BASKETBALL AT HOOP.

See the section on combat for how to get your <npc> to retaliate to an attack.

Virtual Items

There’s one last class of item to mention, a virtual item.
Virtual items are intangible, they can’t be picked up or dropped so they represent ideas or information such as a password.
The player can only gain these items by being told them, discovering them or by trading for them. Like any other item these items can have a price and so can also be bought, sold or swapped.
The only way of adding them to a players inventory is by using an event or task consequence or an NPC action. I'll cover these later.
Virtual items cannot be added to a room definition either.

You mark an item virtual by setting the attribute virtual=”true” in the <item> tag.

If a virtual item is also marked as hidden it cannot be traded and won't appear in your inventory either. It can still be manipulated by task consequences though – if it’s appropriate being able to change it.

I've defined the ME item as a virtual hidden object. Some people like to be able to do EXAM ME to get a description of the character.

Sub Items

Sub items are items that are part of something else. They’re used when something appears in a description so it ought to be examinable in and of its own right. For example, take the Telescreen item:

<item id="2" name="TELESCREEN" fixed="true" onTaken="200001">
  <description>
    It's playing brassy music. There's a slot on the side and a camera above the main screen.
    It is securely fixed to the wall.
  </description>
</item>

The telescreen description makes mention of a slot on the side and a camera so you ought to be able to look at these objects too.

<item id="2" name="TELESCREEN" fixed="true" onTaken="200001">
  <description>
It's playing brassy music. There's a slot on the side and a camera above
the main screen.
It is securely fixed to the wall.
  </description>
  <subItems>
    <subItem name="SLOT">
      <description>It looks like something can be plugged into it.</description>
    </subItem>
    <subItem name="CAMERA">
      <description>A tiny camera mounted above the screen. You feel self-conscious looking closely at it.</description>
    </subItem>
  </subItems>
</item>

Sub items are the same as normal items in most ways so they become part of the vocabulary that your game can handle. They have their own description and name (and therefore noun and adjective).

But there are some important differences:

  • They always fixed so you can’t pick them up. You pick them up by picking up the parent item.
  • They have no price. That’s part of the parent.
  • They are never virtual.
  • They are never containers.
  • They cannot be weapons or consumable.
  • They can have their own events.
    Events (see below) such as onTaken and onExamined are inherited from the parent but can be overridden.

Consumable Items

An item may be Consumable, in which case it can have a fixed number of uses before it requires replenishing. If the item doesn’t have a limited number of uses set uses to -1.

<item id=”351” name=”FOOD RATIONS” article=”SOME”>
  <description>A box of basic rations.</description>
  <consumable uses=”10” onEmpty=”There are no rations left.”/>
</item>

An item may also be used as a weapon – this will be covered more fully in the section on combat discussed later on.

Final Word On Items (nearly)

There are a lot of variations on how you can define an item but usually an item is one thing or another so a single item definition is unlikely to get too unwieldy.

The majority of items you define will look like this:

<item id="16" name="CARETAKERS KEY" description="A heavy, iron key stamped with the flats' insignia."/>

A one-liner definition. Nothing more nothing less.

A few will be containers:

<item id="13" name="OPEN DESK" 
  description="It is strewn with bits of discarded electronics and burned out circuit boards."
  container="true" 
  fixed="true"
  prefix="In the drawer of the desk is ">
  <contains itemIds="16|22"/>
</item>

A few items will accept other items:

<item id="23" name="TORCH" article="A" 
  description="A battery powered waterproof torch. It requires batteries."
  price="4"
  tags="plural|activatable" onStateChanged="200103">
  <accepts itemId="24" eventId="200102"/>
</item>

and so on.

This next example is about as complicated as it gets - this item is both a weapon and consumable (limited number of uses):

<item id="409" name="ETCHING ACID" article="SOME" price="14" tags="dangerous">
  <description>
    A small jar of acid with a rubber stopper. It is very dangerous. 
  </description>
  <consumable uses="2" onEmpty="That was the last of the acid."/>
  <weapon damage="50"> 
    <hit chance="3" probabilitySpace="4" 
         selectorTag="female"
         noMatch="You throw the acid at :1 and he shrieks in pain as it burns through his skin."
         match="You throw the acid at :1 and she shrieks in pain as it burns through her skin."/>
    <miss>You throw the acid at :1 but miss, it splashes on the floor and hisses."</miss>
    <empty>The jar is empty.</empty>
  </weapon>
</item>

Both <hit> and <miss> are in fact auxiliary messages as defined in Appendix B but these one don't need to define a type attribute as the context is clear.
<hit> also requires you to define the chances of success or failure with the weapon.
<miss> is an auxiliary message just renamed appropriately for the context.

Note that auxiliary messages can define a fallback message if you don't need to vary it based on an item tag. This is what I've done with the message shown when you miss above. That could be varied instead using a selectorTag and the match/noMatch options.

Note that it’s conceivable a weapon could also have sub items: imagine a revolver type gun with six bullets. You might want to be able to examine the bullets.
That makes me think of an interesting issue, can you still examine Bullets when there are none left? Well, I think yes you can at the moment – that’s probably an issue. I'll get to that.

Room Definitions

Every adventure game needs a map for the player to explore. (Well OK, I suppose there are some adventures that take place in a single room).
Most adventure games need a map for the player to explore.

I use the words room and location interchangeably. These are the locations the player character can move around among – the world.

Rooms are defined across multiple rooms_<something>.xml files. You can use as many of these files as you need to keep the definitions logically grouped.

There’s not really that much to it. You need to give each room a unique id. The name and youPrefix attributes are used by the engine when describing you are in the location or describing exits from one location to adjoining locations. Here’s an excerpt from a room description:

You are in the kitchen of your flat.

name=”the kitchen of your flat.” youPrefix=”in”)

Exits are:
NORTH to the living room of your flat.

The telescreen is blaring brassy music loudly.
Through the window to the South you can see the four Ministries rising
far above all other structures in the city.

You can see: THE PLUNGER

The XML that produces this:

<?xml version="1.0" encoding="UTF-8"?>
<rooms>
  <room id="1" name="the living room of your flat." youPrefix="in" tags="home">
    <description>
      There is a sofa, a desk and the ubiquitous telescreen. The flat on the whole is dilapidated but not dirty or untidy.
    </description>
    <exits>
      <exit room="2" direction="S"/>
      <exit room="3" direction="N"/>
    </exits>
    <roomItems itemIds="2|5"/>
  </room>

  <room id="2" name="the kitchen in your flat." youPrefix="in" tags="home">
    <description>
      The telescreen is blaring brassy music loudly.

      Through the window to the South you can see the four Ministries rising far above all other structures in the city. 
Huge gleaming white pyramidal structures, a stark contrast to the grey Airstrip One skyline.

      The Party slogans, in black lettering large enough to read even at this distance, are picked out on the Ministry of Truth:

      WAR IS PEACE.
      FREEDOM IS SLAVERY.
      IGNORANCE IS STRENGTH.
    </description>
    <exits>
      <exit room="1" direction="N"/>
    </exits>
    <roomItems itemIds="11"/>
  </room>
</rooms>

Each room may have a pipe | separated list of items (id's) that are available in that room, the <roomItems> supplies this list. Each item should be defined in items.xml file described above.

Each room may also have a list of tags (pipe | separated list of strings e.g. tags=”home|safe”). Later when we come to discuss tasks and events you’ll see how you can make use of the tags during play.

Room Exits and Movement Modes

Each room has a list of exits which take a direction and the id of the room that direction takes you to.
A room can optionally have an onEntered list of events which as you might guess run when the player enters that specific location.
(onEntered events run before the room is described, there are ROOM events too which run after the room has been described but I'll cover these properly later).\

Exits work like you think, you declare direction=<compass_direction> and the room the exit leads to. You may also optionally declare some text to print if the exit is blocked using the exitBlockedText attribute. The presence of this tag means the exit is blocked and can't be used.

Exits can also have some further attributes and a movement mode verb.
The movement modes are defined in the game.xml file in the <movementModes> block and define a verb that can be used in front of a direction to augment how the movement is performed.
e.g. CRAWL, RUN, SWIM.

Movement modes can be used anywhere but if they're defined on exit then the exit can only be accessed if the player uses that verb as well as the direction.

So all the valid attributes for the exit tag are as follows:

Attribute Meaning
room The id of the room the exit leads to
direction The direction that leads there
timeCost The number of game minutes elapsed getting to the next room
blockedText Some text to show if the direction is currently blocked
verb An optional movement mode verb to use
verbMatch A message to print if a movement mode is set and the verb matches
noVerbMatch A message to print if a movement mode is set but the verb isn't present or doesn't match

If verb is specified then it must be used to access the exit. e.g. CRAWL SOUTH. Using just SOUTH results in the noVerbMatch text being shown.
The timeMultiplier attribute in the movementMode definition is used here to change the default time cost when moving from one room to the next.

Specifying blockedText means the exit is blocked.

If no timeCost attribute is set the time elapsed will be zero.

Friend Rooms

A room definition can also include a 'friend room'. A friend room is another location somewhere else in the map that can be viewed from this room. e.g.

<friendRoom roomId="199" prefix="Far off you can see: " itemTag="viewable"/>

The roomId points to the definition of the room that can be seen. The prefix is used in the room description output text like the youPrefix in a normal definition, it's just used to make the text flow nicely.
The interesting bit is the itemTag="viewable". This controls what items in the remote room can be perceived from the current room.

In the game.xml file you will note the definition of the LOOK verb also includes a few adverb forms:

<adverb adverbs="AT" handler="ExamineHandler" itemTag="viewer">
  <rules>
    <!-- LOOK AT x THROUGH y --> 
    <rule name="CheckTargetObjectIsNull" override="ExamineHandler"/>
    <rule name="CheckTargetIsInFriendRoom" override="ItemActionListener" itemTag="viewable"/>
    <rule name="CheckTargetObjectIsLocal" override="ItemActionListener" itemTag="magnifiable"/>
    <rule name="NoMatch" override="DefaultHandler">You don't need :1 to do that.</rule>
  </rules>
</adverb>

This provides the other half of the equation - since the items are not in the current room LOOK AT x or EXAMINE x cannot work so this is where the CheckTargetIsInFriendRoomRule comes into play. This rules checks if what you are looking at is available in the friend room and allows you to see it. Again it uses the same 'viewable' tag so the verb LOOK can only be used to see remote objects with the right tag.

You will note that the adverb itself also has an itemTag attribute. This is used to restrict the type of item that can be used to view the remote item, i.e. it must be a 'viewer', e.g BINOCULARS. The actual item doesn't matter as long as it has that tag.

Item tags are described more fully in the next section and also see the section on Handler Selection Rules which shows you how to script what happens when the rule matches - you need to declare an event and hook it to the item you're viewing.
It also gives a full description of each rule and how the grammar rules work in general.

Do you want to draw attention to the sky in certain locations? You could define it as a friend room and add it to your standard room definition.

But if you want the SKY to be available everywhere that is tagged as 'outside' then you can use a default item.

Default Items

Each room can have a default set of items. This are often things like the floor and the walls for an inside room or the ground and the sky outside.
Since you don't really want to define the same thing for every room these items are defaulted by tag in the game.xml file:

<defaultItems>
  <itemSet itemIds="1000"/>
  <itemSet roomTag="outside" itemIds="1001"/>
</defaultItems>

The first itemSet defines a set of items that will get added to every single room but only if no other itemSet matches.
The second itemSet defines a set of items that will get added to every room that has the tag outside.

You may of course have as many itemsSets as you wish for different tags and itemIds accepts a | pipe delimited list of item ids.
The itemSet with no roomTag defined applies only if no other itemSet matches.

If there are duplicate items across different tags only one copy of the item will be added.

Default items can be overridden within the <room> definition by adding a <defaultItems> element containing the overridden items. So for example say we have item 1000 defining FLOOR as follows:

<item id="1000" name="FLOOR">
  <description>Nothing out of the ordinary.</description>
</item>

So FLOOR will be added to every room with the description 'Nothing out of the ordinary.' but if we then add the following override to a particular room definition:

<room id="1" ... > 
  ... The rest of the room definition ... 
  <defaultItems>
    <item id="1000">
      <description>The carpet is thin and threadbare.</description>
    </item>
  </defaultItems>
</room>

Then EXAMINE FLOOR will show 'The carpet is thin and threadbare.' instead in room 1 only.

All default items are independent of each other and can be manipulated by tasks like other items but it should be noted that they are restricted in other ways. They are always:

  • fixed (so they can't be picked up)
  • hidden (so they don't show up in the room item list).
  • virtual (which when combined with hidden means they can't be bought or sold)
  • they have no attributes except for a description and an onExamined event.

No other attributes means they can't be weapons, containers, consumable. They don't have subItems (essentially they are subItems that aren't attached to any parent object).
I am toying with the idea of allowing accepts items though, I think that could have its uses. I probably will allow that soon.

But being items they can be manipulated with a task, particularly the updateItemDescription consequence as a result of a player action, so

SPRAYPAINT WALL

could result in the wall description being updated to read 'Daubed with crude grafitti.' or something like that.

Events

Introduction to Tasks and Events

Aside from just exploring the map and picking things up, adventure games usually require the player to solve puzzles and things happen in the world – changes occur – when the puzzles are solved.

Other things may happen in the world either randomly or according to the time of day or other triggers. This gives your world more texture.

Tasks are reactions to something the Player has typed, whereas Events are a reaction to something that has happened in the world.

Both require a set of Conditions before they can run and both result in a set of Consequences when they do run.

Events and tasks both have conditions and consequences but difference lies in what triggers them.

When developing your own adventure you can create as many tasks and events as you like.

This section describes how to script events. After this we will be in a position to show you how you can script tasks which you can use to set up the core puzzles in your game.

Tasks are very similar to events and share a lot of common XML definition so let’s look first at events.

Event Definitions

As with other all data files, event definitions can be split across multiple .xml files each called events_xxx.xml so you can group them logically.

Events are things that occur in the game world and will happen whatever the players current situation is.
Events occur after any player turn but not necessarily as a consequence of that turn – although of course they may be related.

Events can be scripted to occur randomly or in a specific time interval or they can even be scheduled to happen at a point X number of game minutes in the future or at a specific time.

With both events and tasks there may be zero or more conditions that have to be satisfied before that event or task can run. Multiple conditions are grouped into a <conditions> block.

Yes, there can be zero conditions for an event to run. Imagine an onExamined event for example, the condition is already satisfied because the player typed EXAMINE x (whatever the item is).

Consequences are grouped into <onSuccess> and <onFailed> blocks that run only if all conditions are satisfied or any one condition fails respectively. In my experience tasks make more use of the <onFailed> block.

Types of Event

There are four main types of event:

UNIVERSAL events,
DAILY events,
ROOM events,
EVENT_TRIGGERED.

If you don't label your event or forget to it will be treated as though it's an EVENT_TRIGGERED event.

Universal events run after every player action, i.e. after every command the player types is processed. They will also run if the player is idle for a while and a time out occurs.

Daily events run at midnight but only if you have the game clock enabled.

Room events run, as you would imagine, when a player enters a specific location. Specifically these events are run after the room has been described.
If you want an event to happen before the description is output (so it may alter the description or the change the state of the NPCs in the room) then you can use an onEntered event defined on the room definition.

Triggered events are run from player actions, such as when a task is completed or when performing specific actions such as picking up an object or examining something (onTaken, onDropped and onExamined trigger an event - in fact they are defined with a list of events to run, | pipe separated as usual).

Events can also be scheduled to run in the future so a consequence of doing something may not be seen immediately.

Let's have look at a couple of UNIVERSAL events first off:

<event id="100000" name="Lights out (home)" type="UNIVERSAL">
  <conditions>
    <condition type="checkTime" startHour="22" endHour="7"/>
    <condition type="checkRoomHasTag" tags="home"/>
  </conditions>
  <onSuccess>
    <consequence type="message">
      All power everywhere is shut off except for the Telescreens. The volume on the Telescreens is lowered.
      There's nothing to do except for sleep until morning.
    </consequence>
    <consequence type="message">... Time passes ...</consequence>
    <consequence type="setTime" time="07:00"/>
  </onSuccess>
</event>
    
<event id="100001" name="Lights out" type="UNIVERSAL">
  <conditions>
    <condition type="checkTime" startHour="7" endHour="22"/>            
  </conditions>
  <onFailed>	
    <gateway>
      <condition type="checkRoomHasTag" tags="no-curfew" invert="true"/>
      <condition type="chance" occurs="1" probabilitySpace="5"/>
    </gateway>
    <consequence type="message">
       The nearest Telescreen screams at you: Citizen! It is past curfew, you should be at home.
    </consequence>
    <consequence type="points" key="thoughtPolice" amount="10"/>            
    <consequence type="fireEvent" eventIds="200000"/>
  </onFailed>
</event>

These are a pair of events defining lights out in our game world. Lights out occurs at 10pm and finishes at 7am.
You'll see there's two events that define what happens if you are at home and if not at home.
If you're at home time passes until morning.
If you're not at home you might get screamed at by a Telescreen but only if there's one available but there's only a 1 in 5 chance of that happening. If you do get screamed at you also accrue some thoughtPolice points. This event also fires a further event which checks how many points you've accrued: if you've accrued enough you will be arrested and it's game over.

The name attribute doesn't do anything, it's just somewhere that you can put a small description of what the event does. You could use a comment, probably should do if it's a lengthy description.

Here’s an example of a ROOM event that occurs randomly - Mrs Parson’s children fire a catapult at you. Notice there’s also a 1 in 5 chance of this happening and you have to be in one of two rooms (either room 6 or room 7). The checkGameState condition ensures that once it has happened it doesn’t happen again.

<event id="600" name="Mrs Parsons children fire catapult at you" roomIds="6|7">
  <conditions>
    <condition type=”chance” occurs=”1” probabilitySpace=”5”/>
    <condition type="checkGameState" key="hasCatapultBeenFired" invert=”true”/>
  </conditions>
  <onSuccess>
    <consequence type="message">
      There's a sudden stinging blow on the back of your neck.
      You spin round just in time to see one of Mrs Parsons children pocketing a catapult.
      "Goldstein!" he yells as Mrs Parsons drags him away to a bedroom.
    </consequence>
    <consequence type="setGameState" key="hasCatapultBeenFired" value="true"/>
  </onSuccess>
</event>

So we see there are two conditions, one is the chance, just 1 in 5 and the flag is not set. Only if both conditions pass will the <onSuccess> block run.
There’s no need for an <onFailed> block, if either condition fails nothing happens.

Conditions

Let's look further at conditions.

As mentioned above whether or not an event should run is determined by one or more conditions.
Conditions are declared in a <conditions></conditions> block.
Each condition is declared in a <condition></condition> element.

All conditions are evaluated in order. If any one condition fails then execution is short-circuited, no further conditions will execute. If there is an <onFailed> block of consequences execution passes to that.
Crucially no condition will change the state of the world in any way nor the context in which it was executed so there can be no hidden side effects of execution.

Be judicious with your use of conditions, if you find yourself writing more than a few then you're probably tying too much state into your event (or task) or you're checking things that don't need to be checked.

If there's no <conditions><conditions> block or <conditions> is empty then the event will always run (subject to whatever triggered it).

Here’s a list of all conditions you can currently use:

Condition

Attributes

1

Chance
- roll a dice

type="chance"
probabilitySpace: total number of outcomes
occurs: chance of success, e.g. for a 1 in 6 chance set:
occurs=“1” and probabilitySpace=“6”

2 Check game state
- has a certain state been set.

type=”checkGameState”
key: the state to check (basically any string is accepted as a key so it's a good idea to stick to some sort of naming convention)

Return true if the key is set to true.

See also the setGameState consequence in the next section.

3 Check a counter
– check if a counter has reached a certain level.

type=”checkCount”
key: counter to check (as with checkGameState any string is accepted as a key)
amount: the threshold to fire if exceeded

See also the points/setCounter consequence in the next section.

4 Check if player is carrying
– does the player possess a particular item?

type=”checkCarrying”
itemIds: | separated list of id’s of the items to check for. Any match returns true.
itemId can be used for a single item.
If you need to check multiple items use multiple conditions.
tags: | separated list of item tags to check the players inventory for. It will return true if the player is carrying at least one item with at least one matching tag.

Both itemIds and tags attributes can be used, any match will result in a true.

5

Check time
– check the time of day. Will the event only run at night say?

type=”checkTime”
startHour: ”HH” – start time (which should accord with your clock definition in game.xml, if you use a 12 hour clock keep the values in the range 1 - 12)
endHour: ”HH” - end time
The current world time is evaluated against the interval defined by startHour and endHour.
Note that for a 12 hour clock this will be true twice a day, am/pm is not currently checked.

6 Check an NPC is distracted
– Is this particular NPC distracted, can you perform the task without being seen?
One of the possible consequences is to mark an NPC as distracted.

type=”checkNpcRoom”
npcId: id of the NPC to check

roomId: the room to check the NPC should be in
7 Check NPC alive
– is the NPC still alive?
Damage HP is taken automatically during combat. If HP reduces below 0 then the NPC is marked as dead.

type=”checkAlive”
npcId: id of the NPC to check

8

Check the players balance
– does the player have enough money?
There are task and event consequences available that enable you to manipulate the players’ balance.

type=”checkBalance”
amount: minimum amount (floating point value allowed)

9

Check uses
– how many uses left on an item?
e.g. Guns can run out of bullets.

type=”checkUses”
itemId: the item to check.

10

Check item tag
– does the item have a particular tag?

type=”checkItemHasTag”
itemId the item to check.
tags : | pipe separated list of tags to check for, any one match will make the condition pass.

11

Check room tag
– does the room have the particular tag?

type=”checkRoomHasTag”
roomId the id of the room to check
tags : | pipe separated list of tags to check for, any one match will make the condition pass.

12

Check room has an item
– is an item in the room?
This doesn’t include carried items.

type=”checkRoomHasItem”
roomId: the id of the room to check
itemId or itemIds: | separated list of items to check, any one match will make the condition pass.

13

Check Noun

type=”checkNoun”
nouns: the set of nouns (pipe separated list) to check against the last type sentence. Any one match will pass.

This should NOT be used in an event, certainly a universal event anyway as you need the current player input for it to evaluate properly.

14

Check Adjective

type=”checkAdjective”
adjectives: the set of adjectives to check against the last sentence typed (pipe separated list). Any one match will pass.

This should NOT be used in an event, certainly not a universal event anyway as you need the current player input for it to evaluate properly.

All conditions (one or more) are tied together in a <conditions></conditions> block. All conditions in a block have to be true for the consequences to fire.

One final point to remember is any condition can be inverted by setting invert=”true” as an attribute.
This means you can change type=”checkCarrying” for example to a check that the player does NOT have the specific item. Or you can invert a checkGameState check so it would look for the key to be false instead of true or indeed a checkCount so instead of amount exceeds (or equal) it becomes amount (strictly) less than.

You could also check an item or room does not have a tag or is that NPC still alive? Anything if it makes sense to you.

Consequences

If all the conditions pass then the event happens or the task succeeds and there will inevitably be consequences.

There can be many consequences if an event occurs or a task is successfully accomplished. All consequences are of form:

<consequence type=”...” parameters... />

As stated briefly above there may be multiple consequences and all consequences are kept in an <onSuccess></onSuccess> block or an optional <onFailed></onFailed> block.
Which block is executed depends on whether or not all the conditions passed.

Further conditions may be placed within a <gateway></gateway> block within the <onSuccess> or <onFailed> blocks. These may be used to concatenate two different sets of conditions together to create different circumstance – so for example, if a <conditions> block fails we go to the <onFailed> block but we can then optionally prevent even that from running by imposing further more specific conditions at that point. The same goes for <onSuccess> of course.
I’ll give an example of this later.

When we do get to the <consequences> block all consequences are executed in the order presented.

There are many possible consequences that all alter the state of the game world in some way. Each requires a specific set of parameters specified as attributes. The following table summarises all the current possible consequences.

Consequence

Parameters

1 Add an Exit to a room

type=”addExit”
roomId: the id of the room to add the exit to
direction: the direction this new exit lies in; compass directions N, E, S, W will do or if you want to be explicit you can spell out NORTH, EAST, etc
toRoom: id of the room the exit leads to

2

Remove an Exit from a room

type=”removeExit”
roomId: the id of the room to remove the exit from.
direction: which exit to remove; use compass direction N, E, S, W, etc.

3 Add Items to an actors inventory, this may be either the player or an NPC.

type=”addItemsToInventory”
itemIds: | pipe separated list of ids of the new items
npcId: (optional) the NPC to add the items to, if not present thn they go to the player.

4

Remove items from an actors inventory.

By default this will be the player but you can specify an NPC.

type=”removeItemsFromInventory”
itemIds: | pipe separated list of ids of the items to remove

tags: | pipe separated list of tags. Remove all items with any of the tags specified.
toRoom: (optional) by default items removed do not reappear anywhere but if a toRoom room id is specified the items will be placed there.
npcId: (optional) the NPC to remove the items from. iI not present it will be the players inventory.

5 Drop items.
Remove item from an actors inventory and add them to the current room.
By default the player but you can specify an NPC.

type=”dropItems”
itemIds: | pipe separated list of IDs of the items to drop.
When dropped the items appear in the current room.
This is different from using removeItemsFromInventory and then addItemsToRoom in that if you’re not carrying some or all of the items, the items you’re not carrying won’t be added to the room.
npcId: (optional) the NPC you want to remove the items from. If not present it will assume the player.

6

Add new items to the room.

type=”addItemsToRoom”
itemIds: | pipe separated list of items IDs to add. All items are added.
roomId: optional, if not present the current room is assumed

7 Remove items from a room.

type=”removeRoomItems”
itemIds: | pipe separated list of items IDs to remove
roomId: optional, if not present the current room is assumed

8 Add tags to an item.

type=”addItemTags”
itemId: singular – the item to tag.
tags: | pipe separated list of tags to add

9

Remove tags from an item

type=”removeItemTags”
itemId: singular – the item to remove tags from.
tags: pipe separated list of tags to add

10 Add room tags.

type=”addRoomTags”
roomId: the room to tag (only one room can be specified)
tags: | pipe separated list of tags to add

11 Remove room tags.

type=”removeIRoomTags”
roomId: the room to tag (only one room can be specified)
tags: | pipe separated list of tags to add

12 Add items to container

type=”addItemsToContainer”
container: the container to put them in (can be anywhere, not necessarily the current room).
itemId or itemIds: the items to add

13 Remove items from container

type=”removeItemsToContainer”
container: the container to remove items from (can be anywhere, not necessarily the current room).
itemId or itemIds: the items to ad

14

Combine Items

As alluded to in the section on Holder Items. Used for when two objects are combined to make one so we keep a record of which two individual items were originally combined. 1

type=”combineItems”
container: the holder item
itemId or itemIds: the items to be subsumed

15

Separate Items

The opposite of combine items.

type=”separateItems”
container: the holder item
itemId or itemIds: the items to be reconstituted from the holder.

16 Message.
Output a message

type=”message”
The message itself is the CDATA in the tag rather than given as an attribute. Multiple messages can be specified separated by | pipe characters.
If there’s more than one a random message is chosen.2

17

Move an actor (player or NPC)

Move an NPC from its current location to a different location

type=”moveActor”
type=”movePlayer” or type=”moveNpc” also do the same thing.
npcId: (optional) id of the NPC to move if not present it moves the player.
roomId: the room to move them to

18 Make an NPC give items to another actor

type=”npcGiveItems”
npcId: the NPC who’s trading the items
toNpc: (optional) the NPC to receive them. If not specified then the player will receive them into their inventory.

19 Make an NPC take things from a room

type=”npcTakeItemsFromRoom”
tags: (optional) specifying the type of item you want them to take.
itemIds: (optional) specify specific items to take.
Both lists are optional but I suppose you ought to define one or the other at least.

It’s probably more useful to use tags to specify the ‘type’ off thing to take.

20 Set a game state flag.
e.g. homeDeskIsOpen = true or false

type=”setGameState”
key: the flag to set (any string)
value: true or false

21 Set a new time.
Unlike time cost below we can set a specific time of day.

type=”setNewTime”
time: Time string of the form HH:mm
HH must be appropriate to the number of hours in a day defined in game.xml.
(Note that minutes in an hour is currently always 60 but hours in a day can be anything, if you set 12 then am/pm will be used and the day will start at hour 12 otherwise there’s no suffix and the day starts at hour 0). am/pm can be appended to the time string but will only matter for a 12 hour clock.

22

Set an NPC state machine state.
Set the next state for an NPC. This is often used in conjunction with runNpcState

type=”setNpcState” also type=”setNextState”
npcId: the id of the Npc
nextState: the id of the state to set

23

Run an NPC state.
Invoke the state machine for an NPC for whatever state it’s currently in or set and run the state.

type=”runNpcState”
npcId: the id of the NPC to invoke
nextState: optional if not specified use the state set in the NPC’s current context otherwise set the state specified and run that. 3

24

Time cost.
There can be a time cost involved in performing this action or because of this event.
This will advance the world clock by a number of minutes.

type=”timeCost”
timeCost: the number of minutes to advance the clock.

25

Output an item description

type=”describeItem”
itemId: the ID of the item to describe

Output the description of an item according to the current room renderer. See the section on room renderers but basically this will usually be the normal item description but if the room is dark it might change to 'You can't see anything.'

26

Output a room description

type=”describeRoom”
roomId: the ID of the room to describe

Output the room description according to the current room renderer.

27

Update an item description

type=”updateItemDescription”
itemId: the item id of the item to update

The description itself is set as the CDATA in the tag rather than being an attribute.

28

Update a room description.

type=”updateRoomDescription”
roomId: the ID of the room to update the description for

The description itself is set as the CDATA in the tag rather than being an attribute.

29

Update balance.
Update the players’ balance.

type=”updateBalance”
amount: a floating point amount, may be negative.

30

Use an item
If an item has limited uses then deplete one use.

type=”useItem”
itemId: the id of the item to deplete

31 Fire an event.
Trigger an event to run.

type=”fireEvent”
eventId: a single specific event
eventIds: a pipe separated list of event IDs,
e.g. eventIds=”1|2|3|4”. If more than one event is given then which event to run is chosen at random.
timeout: If timeout is specified then the event will run timeout game minutes in the future.
time: A time string of the form HH:mm, the event will run at the specified time (or as that time passes within the game world).

32

Cycle through a list of events.

type=”cycleEvent”
eventIds: a pipe separated list of event IDs but this time instead of picking an event at random we cycle through each one every time the task is executed. Once the end of the list is reached it will round robin back to the start.

33

Points/Set a Counter

type=”points” or type="setCounter"
key: counter to update (any string)
amount: amount to increment the counter (if the counter hadn’t previously been defined it starts off at zero).

34

New game.
Start a new game. You should probably use this in conjunction with waitForKey below.

type=”newGame”
The game data is re-read and a new game started from scratch.
The player can SAVE at any point and LOAD a game back.

35

Pause

Insert a pause for dramatic purposes. Occasionally useful between two messages or when moving a player to a different location.

type=”pause”
amount: duration of the pause in seconds.

36

Wait for a key press

Specifically, since this is a console application it does have to Enter

type=”waitForKey”
A message can be output using the text in the tags. e.g. <consequence type=”waitForKey”>Press [Enter] key to continue…</consequence> tags.

37

Do Attack

Used as a hook from a task into the Attack verb.

See the section on combat for a full description.

type=”doAttack”
itemId: (optional) weapon to use
npcId: the NPC to attack

38

Apply Damage

Apply damage points to an actor, either the player or an NPC.

If the player is killed the players onDeath event will be fired.

If an NPC is killed their onDeath state will be set (if there is one).

type=”applyDamage”
amount: amount of hit points to deduct
npcId: (optional) the NPC to apply it to.

Using applyDamage with an NPC will also result in retaliation. See the section on NPCs and combat for a full description.

If npcId is not specified the damage is applied to the player.

39

Block Player Action

Block the current player action

type=”blockAction”

This will prevent the current player input from being processed. Clearly if we reach this point the current player input has normally already been processed. Hence this consequence only makes sense when used by an event that is run before the player input is processed.

See the section on Interceptors below for examples of how to use this feature.

The blockAction consequence only lasts for the remainder of the current turn so using it in a general event or task will usually have no effect at all.

40

Move Item

Move an item in a particular direction

type=”moveItem”
itemId: the id of the item to move

Move an item one room in the direction specified. Only items that are in the current room and aren't **fixed** can be moved.
This could be used as an event consequence but fits better as a task consequence, the result of PUSH x SOUTH for example.


  1. This is required only if it’s intended for the items to be pulled apart again. A “REMOVE BATTERIES FROM TORCH” task will not work without this. ↩︎

  2. - When using pipe separated messages some can be empty so you don’t have to have a message appear after every turn. To set this up you just need empty pipes like so: ‘message1| message2| | | | |‘ but you must keep a space between them otherwise they won’t be used. So in this example 4 times out of 6 there will be no message and 1/3 of the time you’ll see either message1 or message2. ↩︎

  3. - A little care should be taken using the runNpcState or setNpcState consequences in an event.

    You should probably NOT make an NPC jump to a state that attempts to interpret a player response as any player action response is unlikely to still be valid in the context of an event or task. Basically don’t jump to a state that contains a ‘response’ action (see section on NPCs).

    When using it as an action from within an NPC state this is obviously fine, and in fact expected.

    Also bear in mind this can be used on any NPC anywhere in your world, if the new state has any text output it will be shown even if the NPC is not present in the players location! ↩︎

Events and Gateways

Here’s an example of an event that makes use of a gateway condition:

<event id="100002" name="No telescreen" type="UNIVERSAL">
  <conditions>
    <condition type="checkRoomHasTag" tags="no-curfew|telescreen-hidden"/>
    <condition type="checkRoomHasTag" tags="dark" invert="true"/>
  </conditions>
  <onSuccess>
    <consequence type="message">You note that there's no telescreen here.</consequence>
  <onSuccess>
  <onFailed>
    <gateway>
      <condition type="checkRoomHasTag" tags="no-curfew|telescreen-hidden">
      <condition type="checkRoomHasTag" tags="dark">
      <condition type="checkCarrying" tags="light-source-active">
    </gateway>
    <consequence type="message">You note that there's no telescreen here.</consequence>
  </onFailed>
</event>

So the upshot of this event is either: 1, If the room has a no-telescreen or telescreen-hidden tag then by default the player sees the No telescreen here message unless it also has the tag ‘dark’ in which case we we fall through to the onFailed block.

Or:

2, We reach the onFailed section. We have to repeat the first check since the initial condition block can fail for one of two reasons. Now if the room is in darkness then the player won’t see the message unless they happen to be carrying an active light source, e.g. a switched on torch which overrides the darkness.

The event is marked as UNIVERSAL so it runs after every player action and therefore applies to any room with these tags.

Note that the actual tag, dark and no-telescreen used here are just part of the room definition. They don’t have any special meaning within the engine.

Item Events

Now I've properly discussed events, it seems like a good time to introduce item events.

The item tag can take four more attributes that hook directly into the event system.

First off are onTaken, onDropped and onExamined. These define a list of event ids which will be run when GET|TAKE, DROP or EXAMINE actions are performed. This is optional. No onTaken, onDropped or onExamined and nothing extra will happen.

So using onTaken=”1001” in the item definition to run event 1001 when this item is picked up.

Note these attributes used to fire a randomized event from a list but now will fire all events in order. To fire a randomized event you can just define a distributor event with no conditions and a single fireEvent consequenc, e.g <consequence type="fireEvent" eventIds="1|2|3|4">. The fireEvent consequence type will fire a random event if supplied with a list.

Items and Adverbs

The last attribute the item tag can take is called onAction.
This attribute works with adverb definitions within the game verb in game.xml as touched upon above.

Take for example switching on a torch.
The usual practice here is to swap an item for the ‘active’ version of it. Or for each state it can exist in. To deactivate an item you swap out the active item for its inactive version using the active item's onAction event.

So taking the torch example from earlier, now it has batteries it can be switched on or off. So we define two further versions of the torch in addition to the unpowered version:

<item id="20" name="TORCH" article="A" description="A battery powered waterproof torch." 
  tags="activatable"
  onAction="200100"/>

<item id="21" name="TORCH" article="A" 
  description="A battery powered waterproof torch. A bright beam shines from the lamp."
  tags="deactivatable|light-source-active" 
  onAction="200101"/>

In the game.xml file we have the following definition for the SWITCH verb.

<verb synonyms="SWITCH|TURN" handler="AdverbHandler">
  <help>
    SWITCH ON|OFF [adjective] &lt;noun&gt;; SWITCH an object ON or OFF
  </help>
  <adverbs>
    <adverb adverbs="ON" handler="ItemActionListener" itemTag="activatable" itemTagFailureText="Is it on already?"/>
    <adverb adverbs="OFF" handler="ItemActionListener" itemTag="deactivatable" itemTagFailureText="Is it currently off?"/>
  </adverbs>
</verb>    

The SWITCH ON and SWITCH OFF variants are mapped to the ItemActionListener.
The itemTag defined on each adverb is activatable or deactivatable and each version of the torch item is also tagged as activatable or deactivatable.

These tags don't mean anything to the system itself, they're just words, but they are the glue holding the two pieces together: the verb/adverb definition and the event that gets run when the player performs the specific actions.

Note the two different onAction events on the different versions of the item, these events define how to swap items 20 and 21 and back again.

So, typing SWITCH ON TORCH will run event 200100, SWITCH OFF TORCH will run event 200101 if the player is carrying the correct version of the torch (and so the tags match).

These are the associated events so you can see how they work:

<!-- fired from item.onAction - so the torch either already present or being carried -->
 <event id="200100" name="Switch on Torch" type="EVENT_TRIGGERED">
    <conditions/>
    <onSuccess>
      <consequence type="message">You switch on the torch. It's beam is broad and bright.</consequence>
      <!-- cater for when the torch is either carried or in the room --> 
      <consequence type="removeItemsFromInventory" itemIds="20"/> <!-- inactive torch -->
      <consequence type="removeItemsFromRoom" itemIds="20"/>
      <consequence type="addItemsToInventory" itemIds="21"/> <!-- active torch --> 
      <consequence type="describeRoom"/> <!-- redescribe now the torch is on --> 
    </onSuccess>
  </event>
  
  <event id="200101" name="Switch off Torch" type="EVENT_TRIGGERED">
  <conditions/>
  <onSuccess>
    <consequence type="message">You switch off the torch.</consequence>
    <consequence type="removeItemsFromInventory" itemIds="21"/>
    <consequence type="removeItemsFromRoom" itemIds="21"/>
    <consequence type="addItemsToInventory" itemIds="20"/>
    <consequence type="describeRoom"/>
  </onSuccess>
</event>

(Also note when the batteries are first put into the torch the unpowered torch is swapped for item 20, the switched off but powered torch).

The above is great for SWITCH ON and SWITCH OFF since the verb is the same for the action and opposite action. The onAction plus the adverb definition is all you need to swap one item for the other but what if the verbs are not symmetric?

What happens if you need a different verb to perform the reverse operation, for example we could tag an item as wearable and we would need a WEAR verb to put it on and REMOVE or TAKE OFF (adverb definition on TAKE) to take it off again.

Well, you can set up per verb <actionListeners> inside the item too:

<item id="2" name="VELVET CLOAK" tags="wearable" onTaken="202">  
  <description>
    A handsome cloak, of velvet trimmed with satin, and slightly spattered with raindrops. 
    Its blackness is so deep that it almost seems to suck light from the room.
  </description>
  <actionListeners>
    <actionListener verb="TAKE" onAction="200"/>
    <actionListener verb="WEAR" onAction="201"/>
  </actionListeners> 
</item>

<item id="3" name="VELVET CLOAK" tags="wearable"> 
  <description>
    You are wearing a handsome cloak of velvet trimmed with satin, and slightly spattered with raindrops. 
    Its blackness is so deep that it almost seems to suck light from the room.
  </description>
  <actionListeners>
    <actionListener verb="TAKE" onAction="200"/>
    <actionListener verb="WEAR" onAction="201"/>
  </actionListeners>   
</item>

Note here we've moved the onAction attribute to the actionListener.

So we've set up two versions of the item, not worn (item 2) and worn (item 3) and each one maps a different event to fire when the verb is TAKE or for when the verb is WEAR.
These are the same events for both items but it could have been four different ones.

Let's just go over the verb definitions in game.xml so you can see how the two are linked together.

<verb synonyms="TAKE" handler="AdverbHandler" acceptedPrepositions="OUT" itemTag="wearable">
  <help>
    TAKE 
    TAKE [adjective] &lt;noun&gt; OUT OF &lt;container&gt; 
    TAKE OFF [adjective] &lt;noun&gt;; TAKE OFF an item of clothing.
  </help>
  <adverbs defaultHandler="TakeHandler">
    <adverb adverbs="OFF" handler="ItemActionListener"/>
  </adverbs>
</verb>

<verb synonyms="WEAR" handler="ItemActionListener" itemTag="wearable">
  <help>
    WEAR [adjective] &lt;noun&gt;; WEAR an item of clothing.
  </help>
</verb>

TAKE and TAKE OUT (TAKE x OUT OF y) are both handled natively inside the TakeHandler but TAKE also defines an adverb for when TAKE OFF is used. TAKE on its own performs the default action of picking up an object, so TAKE is mapped to the AdverbHandler, the adverb OFF is mapped to the ItemActionListener and we default to the standard TakeHandler if no adverb is supplied.

WEAR maps the verb + adverb combination so it uses the ItemActionListener directly instead of needing a default handler.

Also note I've defined the itemTag="wearable" at the verb level rather than the adverb.
This is fine, if it's at the adverb level it will override the verb level if both happen to be defined but more usefully you can provide different tags if needed per adverb. One for ON and one for OFF as shown above for SWITCH.

If you don't need different tags per adverb then don't bother, just the verb level definition will do.

If you also define an onAction event in the item tag this event will be used a fallback if the verb form isn't explicitly defined.

Handler Selection Rules

Grammar parsers do not understand English (or any language you translate your game to) so they often need help understanding the shades of meaning different verbs can take on in different circumstances.

Luckily we can help the parser along by switching how a sentence is handled depending on what elements are available.

Here's an example - the various ways we can use the verb PUT:

<verb synonyms="PUT" handler="AdverbHandler" acceptedPrepositions="IN|INTO" onCompleted="OK">
  <help>
    PUT [adjective] &lt;noun&gt;; IN|INTO [adjective] &lt;container&gt;; PUT an item in or into a container such as a cupboard, etc.
    Or you can use it in the more abstract sense to PUT an item IN|INTO something that uses it, like 
    PUT BATTERIES IN TORCH or PUT PHOTO IN ALBUM
    PUT [adjective] &lt;noun&gt; ON [adjective] &lt;noun&gt;; PUT something ON something else. 
    see also: GET, TAKE    
  </help>
  <!-- default fall back to PUT x IN CUPBOARD using PutHandler -->
  <adverbs defaultHandler="PutHandler">
    <!-- PUT x ON y --> 
    <adverb adverbs="ON" handler="DoTaskHandler">
      <rules>
        <!-- if no target then it should be like WEAR x -->
        <rule name="CheckTargetObjectIsNull" override="ItemActionListener" itemTag="wearable|activatable"/>
      </rules>
    </adverb>
    <adverb adverbs="IN|INTO">
      <rules>
        <!-- PUT BATTERIES IN TORCH -->
        <rule name="CheckTargetObjectAcceptsItems" override="ItemAcceptsObjectHandler"/>
      </rules>
    </adverb>
  </adverbs>
</verb>

We can use some rules to differentiate all the ways PUT can be interpreted.

We start with assuming a default PUT x IN y where y is a cupboard or some sort of container,\ <adverbs defaultHandler="PutHandler">
But then we start overriding that interpretation according to first whether there's an adverb and if so then look at the properties of the objects in the sentence the player typed.

We first look at the adverb ON, and try the rule CheckTargetObjectIsNull - if there's only one object in the sentence then we must be trying to wear it (WEAR ARMOUR) or perhaps it could be interpreted as another synonym for SWITCH (SWITCH ON TV), either way we shunt it off to the ItemActionListener.

If there is more than one item in the sentence then we shunt it off to the DoTaskHandler as a default handler so there must be a task defined to handle PUT x ON y.

Next we look at the adverbs IN and INTO:
Using the CheckTargetAcceptItems rule we will override the default interpretation in a different way and tell the engine actually this is a put required item into another item type of operation, e.g. PUT BATTERIES IN TORCH. (TORCH can't be a container because we can't put any old thing in it - it has to be just the batteries).

If neither of these fit then it falls back to the standard PUT object IN container interpretation.

If there is more than one rule per adverb each rule is considered until a match is found.

Action and Target Objects

The grammar parser always tokenizes nouns by the order they're found in, the first noun I've called the action item and the second noun I've called the target.
This makes sense most of the time but not always. Consider the LOOK THROUGH and LOOK AT forms of the LOOK verb:

<verbs defaultPackage="org.happysoft.games.action.handler">
  <verb synonyms="LOOK|L" handler="AdverbHandler" acceptedPrepositions="AT|IN|WITH|USING|THROUGH">
  <help>
    LOOK; redescribe the current location
    LOOK UP [adjective] &lt;noun&gt; IN [adjective] &lt;noun&gt;; look something up in an index for example
    LOOK THROUGH [adjective] &lt;noun&gt; [AT [adjective] &lt;noun&gt;]; look through something at something else
    LOOK AT [adjective] &lt;noun&gt; WITH|USING [adjective] &lt;noun&gt;;
  </help>
  <adverbs defaultHandler="LookHandler">
    <adverb adverbs="AT" handler="ExamineHandler" itemTag="viewer">
      <rules>
        <!-- LOOK AT x THROUGH y --> 
        <rule name="CheckTargetObjectIsNull" override="ExamineHandler"/>
        <rule name="CheckTargetIsInFriendRoom" override="ItemActionListener" itemTag="viewable"/>
        <rule name="CheckTargetObjectIsLocal" override="ItemActionListener" itemTag="magnifiable"/>
        <rule name="NoMatch" override="DefaultHandler">You don't need :1 to do that.</rule>
      </rules>
    </adverb>
    <adverb adverbs="UP" handler="DoTaskHandler"/>
    <adverb adverbs="THROUGH" handler="ExamineHandler" itemTag="viewer">                               
      <rules>
        <!-- LOOK THROUGH x AT y --> 
        <rule name="CheckTargetObjectIsNull" override="ExamineHandler"/>
        <rule name="CheckTargetIsInFriendRoom" override="ItemActionListener" itemTag="viewable"/>
        <rule name="CheckTargetObjectIsLocal" override="ItemActionListener" itemTag="magnifiable"/>
        <rule name="NoMatch" override="DefaultHandler">You don't need :1 to do that.</rule>
      </rules>
    </adverb>
  </adverbs>
</verb>

LOOK THROUGH BINOCULARS AT x
LOOK AT x THROUGH BINOCULARS

You'll notice the rule names all refer to the target, i.e. the second noun found in the sentence.
In the first case the BINOCULARS is the first noun (the action) and in the second case it is the target. The object being looked at can also be in either position but really we need the object being looked at to be the action object - that's the object we wish to examine.

The adverb forms AT and WITH of LOOK (not the tokenizer) detect this order reversal by checking for a matching 'viewer' itemTag and swaps the two around if no match is found on the original action object.
Now further actions down the line that refer to the action item will behave correctly.
But note this check is also indiscrimate, the target object, even its presence is not considered, at least not yet. So don't apply the itemTag unless you really need it.

It's important to remember the swap only happens if the adverb and itemTag matches so there are no combinatorial effects of lists of rules.

Besides which, all this happens behind the scenes so you don't have to worry about it but you do need to know when and where to add the itemTag attributes. Basically only add them at the adverb level and only if you want the item reversal to happen.

Available Rules

All available rules are declared in the <handlerSelectRules> element in the game.xml file in the <handlerSelectionRules> element:

<handlerSelectionRules package="org.happysoft.games.action.handler.rules">
  <rule name="CheckTargetObjectIsNotNull" implementation="TargetObjectIsNotNullRule"/>
  <rule name="CheckTargetObjectIsNull" implementation="TargetObjectIsNullRule"/>
  <rule name="CheckTargetObjectAcceptsItems" implementation="TargetObjectAcceptsItemsRule"/>
  <rule name="CheckTargetObjectIsLocal" implementation="TargetObjectIsLocalRule"/>
  <rule name="CheckTargetIsInFriendRoom" implementation="TargetObjectIsInFriendRoomRule"/>
  <rule name="NoMatch" implementation="NoMatchRule"/>
</handlerSelectionRules>

There's no need to change this configuration unless either you wish to use a different name for whatever reason, or you add your own rules (I'll cover how to do this later when I've properly separated out a library from the main java archive).

You probably won't need to change the adverb forms already existing either but you may want to add adverbs extensions to other verbs.

Exercise for the reader, can you figure out how to extend EXAMINE to allow for
EXAM x WITH MAGNIFYING GLASS?

Tasks

Now we’ve covered events, we can have a look at tasks.

Tasks and Verbs

As mentioned above there are three categories of verb the engine understands. The third category is for performing specific tasks.
Multiple synonyms are supported for any verb here too.

Internally all tasks are handled by the specialised DoTaskHandler class – this is important to know if you wish to extend the language and add tasks supported by new verbs.

Tasks can only happen in a certain location or when interacting with a particular NPC so they all specify either a roomId or npcId. If neither is specified then the task is interpreted as being defined against an item.

Triggers, Conditions and Consequences

All tasks consist of three parts:

The first part is the trigger. The trigger is what the player needs to do to trigger the action. Basically this boils down to what do they need to type? Minimally a verb and noun are typed and perhaps the trigger will specify which room you have to be in or NPC you are interacting with.

You may need to specify what object you are directing the action to and which object you are acting with (an action object and a target object).

Optionally a task can be directed towards an NPC or specified in a direction. Imagine\ FIRE GUN AT GUARD or PUSH WOODEN CRATE SOUTH.\ These are both tasks and so require appropriate triggers being defined.

Which prepositions are accepted are defined by the verb. They are (currently) mandatory for the player to type.
The oresence of a preposition implies there will be two objects involved or an object and an NPC. So, you do something WITH something else, or do something WITH someone or TO someone.

Second and third there’s the conditions and consequences blocks. These are exactly the same as conditions and consequences that events have.

Being judicious with conditions applies to tasks even more than events:
For example to OPEN a DOOR it only needs to be unlocked, unlocking the door is another task so don't have conditions check you have the right key or anything, the only thing it needs to do is check the unlocked version of the door is present. Another task that defines UNLOCK DOOR WITH KEY can check you are carrying the right key.
If you find yourself writing half a dozen conditions in a block you are probably loading too much into one task.

A minor difference from events is some optional CDATA text may be included in each condition tag which will be used, if present, as an output message if that particular condition fails.

This feature makes sense for tasks but not so much for events.
Since events can run randomly and often run in the background unbeknownst to the player if you use condition messages for event conditions the game could well appear to show a message for no particular reason.

There’s nothing stopping you using this feature of course but I’d say be careful with it.

A First Task Example – Open The Caretakers Desk

Here’s a simple task, let’s OPEN the caretakers’ desk (the room with id=13 is where the Caretaker NPC is and more importantly for this task where a DESK object has been added.

<task id="1300" name="Open Caretakers Desk">
  <trigger action="OPEN" actionObject="DESK" actionAdjective="CARETAKERS" roomId="13"/>
  <conditions>
    <condition type="checkRoomHasItem" itemId="12">It's already open.</condition>
    <condition type="checkNpcRoom" npcId="1300" invert="true">The Caretaker barks at you, "Don't touch that!"</condition>
  </conditions>
  <onSuccess>
    <consequence type="message">You open the desk drawer.</consequence>
    <consequence type="addItemToRoom" itemId="13">
    <consequence type="removeItemFromRoom" itemId="12">
  </onSuccess>
</task>

The trigger specifies the action attribute which is the verb the player must type, the actionObject which is the item to interact with (noun) and the roomId where the interaction takes place. The actionAdjective is also specified but is optional in the player command.

So for this task the player must be in room 13 and type OPEN DESK or OPEN CARETAKERS DESK for the trigger to fire.

Before I start the explanation of what's going on here note that there are two Caretaker desk objects, one is the closed desk (itemId 12) and the other is the open desk (itemId 13).

The conditions block checks that the desk isn’t already open by checking the closed version of the desk (itemId 12) is present. It also ensures you can only open it and steal its contents if you’ve managed to distract the Caretaker first (checkNpcRoom with invert="true" checks the Caretaker is NOT in the current room).

The consequences addItemToRoom and removeItemFromRoom swaps the closed desk item for a the open version. So rather than having an isOpen flag on every item or having lots of item specific flags I've just define two items and swap them.

Task Types

There are several distinct task types which are identified in the trigger.

When you specify roomId the task is room specific.

If you specify npcId then the task will apply to the NPC specified (by id not name, so it doesn't matter what room the NPC is in - the name typed will be matched with any NPCs present).

If you specify useDirection="true" in the trigger then the task trigger requires a direction in the sentence.

The last case (so far at least) is when you don't specify roomId or npcId. This becomes an item specific task (this includes the directional version).

It's mostly common sense - use a room level task when you're expecting the player to interact with an item in a particular room. These items can be fairly generic, e.g OPEN DESK. There's likely to be more than one desk that can be opened so script this for a particular room and the system can distinguish the DESK being referred to from any others that are defined in other rooms.

Where it gets interesting is the item level tasks. When you don't specify either roomId nor npcId then the task becomes more general and the player can run it wherever they are.

Consider REMOVE BATTERIES FROM TORCH:

<task id="200104" name="Remove batteries from torch">
  <trigger action="TAKE|REMOVE" actionObject="BATTERIES" targetObject="TORCH"/>
  <conditions>
     <condition type="checkCombinedItem" container="23" itemId="24">The torch doesn't have batteries.</condition>
  </conditions>
  <onSuccess>
    <consequence type="fireEvent" eventIds="200104"/>
  </onSuccess>
</task>

Putting the batteries into the torch is handled differently because it's handled by the PUT verb and so has to be a special case. We need to define a grammar rule to special case PUT as described above (see the section on Handler Selection Rules).

Or how about PUSH CRATE SOUTH:

<task id="200104" name="Push Crate">
  <trigger action="PUSH" actionObject="CRATE" actionObjectAdjective="WOODEN" useDIrection="true"/>
  <conditions>
     <condition type="roomHasItem" itemId="29">The crate isn't here.</condition>
  </conditions>
  <onSuccess>
    <consequence type="moveItem" itemId="29"/>
  </onSuccess>
</task>

Notice the direction itself isn't built into the trigger so you can push the crate in any valid direction for the current location. The direction is pulled from the current context.
Also note that the removeItemFromRoom and addItemToRoom conseqences aren't used here, these would hardcode the action to a particular room. We use the specialised moveItem consequence type instead to figure out where to push the object.

Second Task Example – Throw A Rock

Here’s a task that requires you to specify both action and target objects, let’s throw a rock at the lamp by the bandstand and smash the glass thus distracting the guards:

<task id="10400" name="Distract patrols with rock">
  <trigger action="THROW" actionObject="ROCK|STONE" actionAdjective="LOOSE" targetObject="LAMP|LANTERN|LAMPPOST"
roomId="104"/>
  <conditions>
    <condition type="carrying" itemId="101">You need something to throw at the lamp.</condition>
    <condition type="roomHasItem" itemId="102">The glass is already broken.</condition>
  </conditions>
  <onSuccess>
    <consequence type="message">
      You hurl the rock at the lantern and the glass shatters loudly, echoing across the park.
      The patrols shout and rush toward the noise, leaving the southern path clear.
    </consequence>

    ...More consequences...
  </onSuccess>
</task>

Any synonyms defined for lamp are all understood in place of the canonical noun. You can also define these synonyms in the synonyms.xml file and they’ll be general synonyms but if defined here the local synonyms will be accepted.

The preposition AT is defined by the THROW verb so it will be expected.

The sentence the player needs to type in this case would be THROW ROCK AT LAMP – the adjective LOOSE is optional, specificity is only needed if there two or more objects with a matching noun, maybe two different keys or something.

More on Task Triggers

There are a few options in the trigger aside from verb/noun/adjective matching, you can also specify some quoted text but most importantly you need to specify either which room the task is completed in or with which NPC you are conversing with using roomId or npcId respectively.

Here’s a task that involves interacting with an NPC, note there are multiple options for the NPC name that is understood. At least one of the names should be the official NPC name as defined in an npc_xxx.xml file. Others can be shortened versions, anything natural that the player may type instead of spelling out the full name.

<task id="11000" name="Show flyer to prole">
  <trigger action="SHOW" actionObject="LEAFLET" npcId="11000"/>
  <conditions>
    <condition type="carrying" itemId="412">The prole tuts and says, "Don't waste my time, comrade."</condition>
  </conditions>
  <onSuccess>
    <consequence type="message">The prole says, "OK, wait a minute."/>
    <consequence type="message">
    You watch as he leaves by an alley beside the National Gallery North towards Charing Cross Road.

    ...A few minutes pass...

    There's a tap on your shoulder and your blood runs cold, not the Thought Police already?

    But a gaunt man with sharp eyes steps forward, "I'm Silas."
    </consequence>
    <consequence type="runNpcState" npcId="110" newState="8"/>
    <!-- Bring Silas out of limbo and trigger his first state -->
    <consequence type="moveNpc" npcId="111" roomId="110"/>
    <!-- Move the Victory Square Prole into limbo -->
    <consequence type="moveNpc" npcId="110" roomId="999"/>
    <!-- run Silas initial state --> 
    <consequence type="runNpcState" npcId="111" newState="0"/>
    <consequence type="timeCost" timeCost="10"/>
  </onSuccess>
</task>

The trigger for this task translates to the player typing
SHOW LEAFLET TO [PROLE|LOITERING PROLE|PROLE LOITERER]

So, the above task is not room specific but the NPC has to be present for the player to be able to trigger it.

Here’s a task where you say a password in a location to open up a new location:

<task id="32600" name="Say Harry sent me">
  <trigger action="SAY" quote="HARRY SENT ME" roomId="326"/>
  <conditions>
    <condition type="checkGameState" key="passwordHarrySet" value="true"\>Maybe a drink first? Check out the Victory Arms pub.
    </condition>
  </conditions>
  <onSuccess>
    <consequence type="message">
    Someone looks over the top of the gate and eyes your blue overalls suspiciously.

    He disappears for a minute or two but then returns and the gate is unlocked.
    </consequence>
    <consequence type="addExit" roomId="326" direction="NE" toRoom="355" timeCost="2"/>
  </onSuccess>
</task>

Quoted text must match exactly and is in quotes when the player types it – SAY “HARRY SENT ME” so it must be clear exactly what to type.

Triggers and Adjectives

Any trigger can specify the actionObjectAdjective and targetObjectAdjective but these are only really useful if there’s more than one item with a matching noun in the players inventory or in the current location.
Attributes aren't used in matching the task to what the player typed, instead they are checked during task execution and the adjective only matters when there's more than one matching item present.

You can however make the action item adjective non-optional by specifying a checkAdjective condition in the block of the trigger.
This also has the advantage of being able to provide specific feedback to the player if the adjective they typed doesn’t match:

<condition type=”checkAdjective” adjective=”BLUE”>
  You’ve cut the wrong wire! A countdown timer starts...
</condition>

Non-Player Characters (NPCs)

Non-Player Charaacters are all other characters that feature in your game. This could people, animals or beasts that attack or even inanimate objects that benefit from having a state machine. In the 1984 demo game, I model a lift as an NPC. Also see the Appendix for how the Quit Game function works.

NPCs in this system are technically known as Finite State Machines. They start life in one particular state and player actions or other events move them from that initial state to other states throughout your encounter. Each state comprises some actions.

NPCs can of course also be split among multiple XML definition files:

npc_*.xml

You can have as many NPCs as you like. Unless you're a masochist you'll probably want to keep all the definitions in separate files, just call the file ‘npc_[character name].xml’ and add it to your dev directory.

Each NPC has an id, a name, some optional local properties and a set of states. Each state consists of zero or more actions.

NPCs run whatever their current state is per turn after the player command has completed. If you need more than one state to run you can hook two or more states together using the runNpcState action.
The states start with the initialState from the configuration and continue from there.

Only NPCs in the current room are executed. You can update the states of other NPCs using the setNpcState or runNpcState actions.

You will often want to bring an NPC into play as a consequence of some other action (a task or event) so you can configure the NPC initial room to be a limbo room (a room definition on its own, not part of the world map) and then bring them into play using the moveNpc action to move them to a particular room. See the SHOW LEAFLET TO PROLE task example above.

The general structure is as follows (properties are optional):

<npcs>
  <npc id="40" name="Silas" altNames=”SILAS”>
    <configuration initialRoom="999" initialState="1"/>
    <properties>
      <property name="loop_exit" value="false"/>
    </properties>
    <state id="1" evaluateUnless="loop_exit">
      ... various actions ...
    </state>
      ...more states...

    <!-- idle state is empty -->
    <state id="7"/>
  </npc>
</npcs>

Every NPC definition starts off with the name and altNames attributes.
The name attribute is used as the display name for room descriptions, the altNames attribute is what the grammar parser recognizes as a name.
There can be multiple names specified in altName | separated as usual.

Each state can be optionally evaluated using the evaluateUnless attribute, if the local property named is set to true the state will be skipped. This is useful to stop an NPC repeating the same action every time you perform another action in the same location but haven’t yet done what you’re required to do.

Each state has a unique id but this is per NPC so state id="1" can be used again on a different NPC – it’d be a nightmare otherwise wouldn’t it?

Each state consists of a sequence of actions. All actions are run in order.

Tip: use an XML comment to keep track of what states do, e.g.

<!-- comment goes here -->

That’s a left angle bracket, exclamation mark and two dashes to start your comment and then two dashes and a right angle bracket to close it.

NPC Configuration

The NPC configuration sets up the initial values for an NPC.

Most important of these is the initial room where the NPC starts off and the initial state that they start in.

It's been mentioned a few times already but I’ve found it useful to define a limbo room which is not part of the main map.
This is somewhere you can place all NPCs that you don’t yet need and put NPCs that you’ve finished with. You summon them into existence or dismiss or banish them using the moveNpc action.

The <configuration> block is also where you can define if the NPC is a trader, combat parameters and patrol circuits but we'll get to that later.

NPC Actions

Actions are analogous to consequences for Tasks and Events.

Each <state><state> block can contain zero or more actions.
– yes, a state may be have no actions at all and thus the NPC will remain completely inert whilst in that state.

Each action is defined as follows:

<action type=”xxx” parameters...>(Optional message)</action>

within a <state></state> block.

There are several different types of action.
As with events and tasks each action has a specific set of attributes.

Listed below are the specific actions that only NPCs can use do but remember that any event consequence may also be used as an action. You still use <action type=”type”… > but type is the consequence type instead.

Any condition defined above may also be used as a branching action but you have to define both onSuccess and onFail parameters in addition to the existing parameters the condition already expects. These two parameters define the states to jump to should the condition pass or fail.

This does mean you can use the fireEvent consequence to run an EVENT_TRIGGERED event but there’s not much need as anything you can do there should more or less work directly as an action.
It might help with code reuse of course.

Remember that NPCs do not have a separate action language. They reuse the existing Task and Event Consequences and Conditions defined in the system. The only difference is that when used inside an NPC state, conditions require an onSuccess and onFail attribute to cleanly branch the NPC's state machine.
So every event/task consequence above can be used as an action, instead of writing:

<consequence type="xxx" ...> 

or 

<condition type="xxx" ...> 

You instead write:

<action type="xxx" ...>

or if you want a condition:

<action type="xxx" onSuccess="s1" onFail="s2"> 

Below is a list of all NPC specific actions - these are the actions that only NPCs can do rather than being a general task or event consequence from above.

Action Parameters
1 Choice – the NPC offers the player a choice.
Choices should be formatted as numbered options in the CDATA text.
When a choice is presented to the player the input prompt will change from ‘What next? ’ to ‘Choose an option: ‘.
The player cannot enter a normal verb/noun style command (well, they can type it in but it won’t be accepted).
type=”choice”
validResponses: a pipe separated list of accepted responses, e.g. “1|2|3” for three choices - but they're not limited to numeric choices.
prompt: The text to show before the choices are presented, by default it will be ‘Choose: ‘
2 Response – Interpret the response from a choice action.
– the player input to a choice is interpreted. Further states can be run according to that choice.
The same response state can be re-used for more than one input from the choice.
type=”response”
response: the response to match the player input
nextState: A pipe separated list of NPC states (this NPC only).
As usual, if more than one is provided then a random one will be picked so you can randomize outcomes.
3 Run NPC State – Run the whatever NPC state is currently set (so you need to set a different state first otherwise you could end up in an infinite loop).
This often goes hand in hand with the response handler action to auto-run the next state.
type=”runNpcState”
npcId: the id of which NPC you wish to run (optional if not set the current NPC is assumed, so this can be used to summon other NPCs and invoke them).
nextState: optional, the state to run – if not set then whatever is current in the context.
4

Set Next State.

Set the next state for any NPC.
You can set which state an NPC should move to at any point, not just after a response.

type=”setNextState”
npcId: (optional) the id of the NPC whose state you wish to update. If left out the NPC from the current context is inferred.
nextState: (optional) a | pipe separated list of NPC states. As usual, if more than one is provided then a random one is chosen.
If the attribute is not present whatever the current state (set by a previous action such as response or a checkXXX onSuccess/onFail) is run.
5 Display Offers
– an NPC can offer you something to buy or exchange for something else.
Once an item has been offered control returns to player to take up the offer with the BUY or SWAP verbs or indeed walk away.
If the NPC is a trader the player may also be able to sell items to them for cash.

type=”displayOffers”
The initial offer set is defined in the <configuration></configuration> block under <trading>

Further offers may be added from items the players sells or swaps.

6 Set a local property.
– set a local property for use with the evaluateUnless attribute.
type=”setProperty”
key: the key of the property to set
value: boolean true or false.
7 Set NPC Distracted

type=”setDistracted”
npcId: (optional) the Npc to set as distracted. If not present the current Npc from the context is inferred.
value: true or false

Use checkDistracted in an action, task or event to check if an NPC has been distracted.

8 Set NPC Status
Most NPCs will start their life in STATE_MODE which means they follow the usual state scripting but patrolling NPCs need to be AUTONOMOUS to continue their patrol.

A patrolling NPC will switch to STATE_MODE automatically on encountering the player. Your script should switch them back to AUTONOMOUS when the encounter is finished.

DEAD is mostly for use when an NPC is in combat mode and will be set automatically if their HP value falls to 0.

HOSTILE will be used when NPCs gain the ability to respond to orders.
type="setNpcStatus"
status: must be one of (with exact spelling and capitalization):
AUTONOMOUS,
DEAD,
HOSTILE,
STATE_MODE.

Mrs Parsons - A Full Example

<npc id="500" name="Mrs Parsons" altNames="PARSONS|MRS PARSONS" gender="she">     
        
  <configuration initialRoom="5" initialState="1">
    <proximityHints>You can hear Mrs Parsons whistling a tune :1.| | | |</proximityHints>
  </configuration>
        
  <properties>
    <property name="loop_exit" value="false"/>
  </properties>
        
  <state id="1" value="PASSIVE" evaluateUnless="loop_exit">
    <action type="message">Mrs Parsons says, "Sorry to bother you comrade but could you help me with my sink? It's all blocked up ain't it."
    </action>  
    <action type="choice" validResponses="1|2">1) Yes, 2) I'm sorry but I can't at the moment</action>
    <action type="setNextState" nextState="4"/>
  </state>
        
  <state id="2" value="TASK ACCEPTED">
    <action type="addExit" roomId="5" direction="S" toRoom="6" timeCost="0"/> 
    <action type="message">Mrs Parsons says, "It's through there in me kitchen."</action>
    <action type="moveActor" npcId="500" roomId="7"/> 
    <action type="setNextState" nextState="5"/>    
    <action type="timeCost" timeCost="1"/>
    <action type="runNpcState"/>
  </state>
               
  <state id="3" value="COMPLETE"> 
    <action type="message">Mrs Parsons says, "Thanks for unblocking the sink, comrade."</action>
  </state>
        
  <state id="4" value="WAITING FOR ACCEPT">
    <action type="response" response="1" nextState="2">Mrs Parsons says, "Thanks, comrade."</action>
    <action type="response" response="2" nextState="1">
      Mrs Parsons says, "I'll tell thems in the telescreen on you! Goldstein!"
    </action>
    <action type="setProperty" key="loop_exit" value="true"/>
    <action type="timeCost" timeCost="1"/>
    <action type="runNpcState"/>
  </state>
        
  <state id="5" value="WAITING IN KITCHEN"/>
</npc>   

So on encountering Mrs Parsons she will immediately ask you for help. This is the choice action defined.
Upon executing the choice action the game will show:

Choose: 1) Yes, 2) I’m sorry but I can’t at the moment

then jump to a state 4 to await and then interpret the player response. State 4 is not run until the player responds to the initial choice presented.

Control is returned to the player but the prompt changes to ‘Choose an option: ‘ (by default) and the player must enter 1 or 2. If the player enters anything else it is rejected and the ‘Choose an option: ‘ prompt is displayed again.

Once the player has entered a valid option state 4 is run to interpret it.
State 1 or 2 is chosen depending on which option the player chose and that state is jumped to and executed immediately because of the runNpcState action.

If Yes is chosen state 2 is run. State 2 dynamically adds a new exit from the hallway into Mrs Parsons flat - you can't just go in without being invited. We move Mrs Parsons to her kitchen (roomId="7") and set her state to waiting.

Note that the property ‘loop_exit’ is set before jumping so if state 1 is jumped to again it will actually be skipped this time so we don’t end up in a loop of being given the same choice again and again. The player can back out or do something else.

Remember that some states will only be invoked by a task or other event. Not every state needs to lead to another.

Trading

Trade is conducted through three main verbs, BUY, SELL and EXCHANGE|SWAP.

These verbs take the form:

BUY x FROM y, SELL x TO y and SWAP x FOR y.

You can also SHOW x TO y and if the NPC is a trader he will make you an offer.

Let's have a look at how you can configure a trader.
Start with a <trading> tag that lives inside the <configuration> block.
Inside the <trading> tag the block defines how your trader buys objects from the player.
Each tag is actually an auxiliary message with a few extra attributes that allow you to configure how the trader marks up items, what they will pay for an item, or if they will refuse to buy some things from you. Plus which state the state machine will run when the player buys. sell, swaps or shows an item with the trader.

You'll see <onTrade> defines three (up to four) attributes for onBuy, onSell, onSwap and onShow. These are simply the states to jump to after the player does any of these actions.

The <tag> elements beneath can override the <onTrade> default values.

Here's an example:

<trading onBuy="3" onSell="3" onSwap="4" defaultMarkup="1">
  <tag name="contraband" priceModifier="-2" markup="2" onBuy="3"
       selectorTag="plural"
       noMatch="It's risky but I'll give you :1 for it."
       match="It's risky but I'll give you :1 for them."/>
                    
  <tag name="rare" priceModifier="2" markup="2"
       selectorTag="plural"
       noMatch="Don't see many of these around. How's about :1?"
       match="Don't see many of these around. How's about :1?"/>
                    
  <tag name="damaged" priceModifier="-1" markup="1" 
       selectorTag="plural"
       noMatch="It's seen better days, I'll give you :1."
       match="They've seen better days, I'll give you :1 for them."/>

  <noPrice selectorTag="plural"
    noMatch="It's worthless to me guv. | Sorry mate, it's not worth anything."
    match="They're worthless to me guv. | Sorry mate, they're not worth anything."/>

  <default selectorTag="plural"
    noMatch="Yeah I'll take it. No more than :1 though."
    match="Yeah I'll take them. No more than :1 though."/>
                
  <offer itemId="430" price="8">
    You're a Party member, right? This'll be useful for your Telescreen, you can look right back at 'em! 
    The price is :1.
  </offer>
  
  <offer itemId="431" price="5">
    This was designed by the best engineers in the Party, they meant to use it for testing but it turns out you can do all sorts with it given the right chip.
      The price is :1.
  </offer>
</trading>

You can have as many <tag> elements as you like.
The <tag> elements define how the trader reacts to different items according to tags defined on the item itself. So if an item has the tag contrabandI the first tag will be applied, etc.

priceModifier changes the price the trader will buy an item for and markup changes the price thay will sell it on for.
The items' actual price is the base that these values are calculated from, so if an item has a price of 5 the priceModifier -1 means the trader will pay 4 for it and markup of 2 means they will sell it back to you for 7.

Also note the <offer> elements, which define the initial list of things the trader has for sale, how much they cost and the sales pitch that goes with it.

The banter for any item that you sell to the trader is defined in the game.xml file as as the TRADE type auxiliary message.

Once trading is enabled the player can BUY, SELL and SWAP both physical items and virtual items such as passwords and knowledge.

Remember the NPC specific <action type="displayOffers"> can be used to get an NPC to list their wares as defined in the list of <offer> elements.

Patrols

NPC can be made to patrol pre-defined routes.
Defining a patrol is simple:

<configuration initialRoom="999" initialState="1">
  <patrol initialRoom="501" startHour="19" endHour="7">                
    <rooms>501|502|503|504|505|504|503|502|510|511|521|511|510|502</rooms>
    <states>20</states>
  </patrol>
  ... more config ... 
</configuration>

The <rooms> element simply defines the circuit to patrol. The <states> element defines a set of states to run at each stop (one is usually sufficient). Below state 20 has the guard check the current room for anything contraband and take it.
If the NPC encounters the player the initialState as defined in the <configuration> tag is run as usual. In this case the state has the NPC check the player for contraband items and confiscates anything found and then ejects him from the building.

When patrolling the NPC's status is set to AUTONOMOUS so it will continue to patrol after each turn.
If the player is encountered the NPC drops out of AUTONOMOUS mode back to STATE_DRIVEN so the encounter can play out. It is therefore important to reset the NPC's status to AUTONOMOUS when the encounter is over as seen below in state 2.

<state id="1" value="MEETING">
  <action type="message">
    The guard steps forward, gun pointed. "What are you doing here?"
    He quickly and efficiently frisks you, looking for anything illicit, contraband.
  </action>
  <action type="checkCarrying" tags="contraband" onSuccess="2" onFail="3"/>
  <action type="runNpcState"/>
</state>
        
<state id="2">
  <action type="message">
    "This is contraband citizen! Where did you get it? This will be reported to level 4."
    You are summarily ejected from the building.
  </action>
  <action type="points" key="thoughtPolice" amount="15"/>
  <action type="removeItemsFromInventory" tags="contraband" toRoom="526"/>
  <action type="setNextState" nextState="20"/>
  <action type="setNpcStatus" status="PAUSED"/> 
  <action type="fireEvent" eventId="50100" time="07:00"/>
  <action type="waitForKey">...Press [Enter] to continue...</action>
  <action type="setNpcStatus" status="AUTONOMOUS"/> 
  <action type="moveActor" roomId="131"/>                       
</state>

<state id="20">
  <action type="removeItemsFromRoom" tags="contraband" toRoom="526"/>
  <action type="setNextState" nextState="1"/>
</state>

Valid statuses are:\

  • AUTONOMOUS
  • STATE_DRIVEN
  • PAUSED
  • DEAD

NPC Proximity Hints

You can warn the player of the upcoming danger from a patrol by defining a proximity hint.
A proximity hint message will be shown when the NPC is in an adjoining room. The :1 placeholder will be replaced some text like 'to the South' or 'upstairs' as appropriate.

<proximityHints>
  You notice the sweep of a flashlight :1; the night guard is near! | 
  You hear footsteps :1; somebody is nearby! | 
  You hear the jangle of keys :1; the night guard is nearby!
</proximityHints>

The direction messages are defined in the message_en_GB.properties file under the following keys:

DIRECTIONS_TO_THE = "to the :1"
DIRECTION_FROM_UPSTAIRS = "above"
DIRECTION_FROM_DOWNSTAIRS = "below"

Proximity hints can be used to signal the presence of any NPC - imagine the trader above hawking his wares along the road before you get to the market for example.

Combat

There a few different ways to implement combat, the simplest way is to script the entire thing in NPC states.
You can also instigate a combat round by attacking from the ATTACK verb and also remember any task can run any NPC state so you can, for example, enrage an NPC by doing something.

When scripting combat it's probably best to use the random state invocation feature so the outcomes aren't entirely formulaic:

  <action type="setNextState" nextState="101|101|102|102|103|103|104|105|106|106"/>

We can use a setup like this to branch to any of the states 101 to 106 in weighted random fashion.

Scripted Combat

Here's a full NPC implementation that shows a fight situation entirely run through choices.

<npc id="361" name="The Drunken Prole" altNames="PROLE|DRUNK PROLE">  
      
  <configuration initialRoom="361" initialState="1"/>

  <state id="1" value="PASSIVE">
    <action type="message">
      A ruddy-faced prole stares into his mug, then looks up at you blearily.  
      "Buy us a pint, guv?", he says, hopefully.
    </action>
    <action type="choice" validResponses="1|2">1) Buy him a beer. 2) Refuse.</action>
    <action type="setNextState" nextState="2"/>
  </state>

  <state id="2" value="CHOICE">
    <action type="response" response="1" nextState="6"/>
    <action type="response" response="2" nextState="100">
      He grumbles into his mug saying something about the bleedin' Party. You can see he's turning angry...
      Suddenly he lunges at you.
    </action>
    <action type="setProperty" key="beer_loop_exit" value="true"/>
    <action type="runNpcState"/>
  </state>

  <state id="3" value="HAPPY">            
    <action type="message">
      He drains the remainder of his drink greedily and pulls up the fresh one. 
      "You're all right, comrade. 'ere you heard about the other market?" 
      "You ever need proper goods, just go to the passage between the tenements, north of here and say 'Harry sent me'."
    </action>            
    <action type="setNextState" nextState="4"/>
    <action type="timeCost" timeCost="2"/>
    <action type="runNpcState"/>
  </state>

  <state id="4" value="DONE"/>
        
  <state id="5" value="DESPAIR">
    <action type="message">Nobody's got any bleedin' money these days. He drains the remainder of his beer and stomps out.</action>
    <action type="setNextState" nextState="4"/> 
    <action type="timeCost" timeCost="2"/>
    <action type="moveActor" npcId="361" roomId="999"/>
  </state>

  <state id="6">
    <action type="fireEvent" eventId="36100"/>         
  </state>
        
  <state id="100" value="FIGHT LOOP">
    <action type="message">The prole squares up to you and takes a swing.</action>
    <!-- Randomly branch into one of several outcomes -->
    <action type="setNextState" nextState="101|101|102|102|103|103|104|105|106|106"/>
    <action type="timeCost" timeCost="1"/>
    <action type="runNpcState"/>
  </state>

  <!-- Outcome: Player takes damage -->
  <state id="101" value="FIGHT OUTCOME">
    <action type="message">He lands a heavy blow! You stagger back.</action>
    <action type="choice" validResponses="1|2">1) Fight back. 2) Get out of there!</action>
    <action type="setNextState" nextState="120"/>
    <action type="runNpcState"/>
    <action type="timeCost" timeCost="1"/>
  </state>

  <!-- Outcome: Opponent misses -->
  <state id="102" value="FIGHT OUTCOME">
    <action type="message">He swings wildly but in his drunkenness misses you completely!</action>
    <action type="choice" validResponses="1|2">1) Counter-attack. 2) Slip away.</action>
    <action type="setNextState" nextState="120"/>
    <action type="runNpcState"/>
    <action type="timeCost" timeCost="1"/>
  </state>

  <!-- Outcome: Opponent stumbles -->
  <state id="103" value="FIGHT_OUTCOME">
    <action type="message">He stumbles drunkenly, leaving himself open.</action>
    <action type="choice" validResponses="1|2">1) Go for the win! 2) Escape while you can.</action>
    <action type="setNextState" nextState="120"/>
    <action type="runNpcState"/>
    <action type="timeCost" timeCost="1"/>
  </state>

  <!-- Outcome: Mutual struggle -->
  <state id="104">
    <action type="message">You lock arms in a desperate struggle!</action>
    <action type="choice" validResponses="1|2">1) Keep fighting 2) Try to flee.</action>
    <action type="setNextState" nextState="120"/>
    <action type="runNpcState"/>     
    <action type="timeCost" timeCost="1"/>     
  </state>
                
  <!-- Lose -->
  <state id="105" value="FIGHT LOSE">
    <action type="message">
      He beats you to the ground. Darkness closes in...
	
      ... Time passes ...
                
      Finally you wake up again, feeling whoozy. Your head aches. 
    </action>
    <action type="moveActor" roomId="391"/> <!-- hospital -->
    <action type="setNextState" nextState="1"/>
    <action type="timeCost" timeCost="60"/>
  </state>

  <!-- Win -->
  <state id="106" value="FIGHT WIN">
    <action type="message">With your return volley you manage to overpower him and knock him to the ground.</action>
    <action type="message">
       "Alright, alright. You put up a decent fight, comrade."
       He picks himself up and returns to the bar.
    </action>
    <action type="setNextState" nextState="3"/>
    <action type="runNpcState"/>
    <action type="timeCost" timeCost="1"/>
  </state>
        
  <!-- RUN -->
  <state id="110" value="FIGHT ESCAPE">
    <action type="message">You break away and flee the scene!</action>
    <action type="moveActor" roomId="360"/> <!-- outside pub -->
    <action type="setNextState" nextState="1"/>
    <action type="timeCost" timeCost="2"/>
  </state>
		
  <state id="120" value="INTERPRET FIGHT RESPONSE">
    <action type="response" response="1" nextState="100"/>
    <action type="response" response="2" nextState="110"/>
    <action type="runNpcState"/>
  </state>
</npc>

Here, all I've done is offer continual choices and randomize the outcome until you either give up and run, win or lose and end up in Hospital. Note that you can make it so the player or NPC take damage on each round and either one could potentially die.

Probably more interesting is the ATTACK verb and using weapons but the nice thing is these system aren't mutually exclusive so you can mix traditional combat with the choice based system.

Combat from the ATTACK Verb

The ATTACK verb (or any synonyms you define) accepts two forms:

ATTACK <npc>
ATTACK <npc> WITH|USING x

The first form defaults to combat using an item defined by the defaultCombatItem attribute in the player definition in your game.xml file.
The default combat item might just be your fists.

Consider the following XML:

<npc id="50000" name="The Security Guard" altNames="GUARD|SECURITY GUARD"> 
  <configuration initialRoom="500" initialState="1">
    <combat hp="100" onAttack="30|30|30|31" onMissed="50" onDeath="40"/>
  </configuration>
        
  <properties>
    <property name="loop_exit" value="false"/>
  </properties>
          
  <state id="1" value="PASSIVE" evaluateUnless="loop_exit">
    <action type="message">A guard steps forward, gun pointed. "Where's your pass?"</action>
    <action type="setNextState" nextState="1"/>         
  </state>
        
  <state id="2">
    <action type="message">&quot;OK, you can go through.&quot;</action>
    <action type="setNextState" nextState="9"/>   
    <action type="addExit" roomId="500" toRoom="501" direction="W" timeCost="5"/>
  </state>
  
  <state id="9" value="DONE"/>        
                    
  <state id="10">
    <action type="message">The guard inspects your pass closely.</action>
    <action type="checkCarrying" itemId="1" onFail="11" onSuccess="2"/>
  </state>
                                                
  <state id="11" value="Puts you in Hospital">
    <action type="message">
      No Minitrue pass? So what are you doing here?
                 
      The guard clubs you with the butt of his gun and savagely beats you to the the ground. You have no chance of fighting back. 
      Darkness closes in...
                
      ... Time passes ... 		
    </action>
    <action type="waitForKey">...Press [Enter] to continue...</action>                
    <action type="message">Finally you wake up again, feeling whoozy. Your head aches.</action>
    <action type="moveActor" roomId="391"/> <!-- hospital -->
    <action type="setNextState" nextState="1"/>
    <action type="timeCost" timeCost="90"/>
  </state>
       
  <state id="20" value="ARRESTED">
    <action type="message">
      More guards arrive even though you saw no sign of anyone being summoned. 
      You are roughly handcuffed and transported to the windowless Ministry of Love. 
    </action>
    <action type="waitForKey">...Press [Enter] to contine...</action>
    <action type="pause" amount="2.5"/>
    <action type="moveActor" roomId="900"/> <!-- Ministry of Love -->
    <action type="timeCost" timeCost="90"/>
  </state>
       
  <state id="30">
    <action type="message">
      The guard is angered by your attack and raises his iron baton to attack. |
      The guard retaliates and swings for you angrily. |
      The guard raises his baton and lunges at you.
    </action>
    <action type="chance" occurs="7" probabilitySpace="10" onSuccess="32" onFail="33"/>      
  </state>
       
  <state id="31">
    <action type="message">
      The guard levels at you, I'm going to report this Comrade. Desist or you'll be arrested immediately. 
    </action>
    <action type="points" key="thoughtPolice" amount="20"/>  
    <action type="setNextState" nextState="50"/>          
  </state>
       
  <state id="32">
    <action type="applyDamage" amount="25"/>
    <action type="message">
      His heavy baton smashes into your face; your nose might be broken, you stagger back your face swelling. | 
      The blow connects and you are pushed back violently with the force. Blood streams from your nose. 
    </action>
    <action type="setNextState" nextState="50"/>
  </state>
       
  <state id="33">
    <action type="message">
      In his angry haste he misses! | 
      You jump out of the way and the guard is thrown off balance by his swing.|
      You manage to dodge aside before his blow connects. 
    </action>
    <action type="setNpcState" nextState="50"/>
  </state>
       
  <state id="40">
    <action type="message">
      The Guard slumps to the floor.
      You look up at the Telescreen, you know you've crossed a line.
    </action>
    <action type="points" key="thoughtPolice" amount="101"/>
    <action type="setNextState" nextState="20"/>
  </state>
        
  <state id="50">
    <action type="message">
      The guard snarls. | 
      The guard looks at you angrily. | 
      The guard warns you. | 
      The guard taps his truncheon. | 
      The guard readies himself for your next attack.
    </action>
    <action type="setNextState" nextState="51"/>
  </state>
        
  <state id="51">
    <action type="setNextState" nextState="1"/>
  </state>
</npc>

The only real difference is the presence of the <combat> element in the <configuration> tag:

<combat hp="100" onAttack="30|30|30|31" onMissed="50" onDeath="40"/>  

We define hit points - so that the protagonist can suffer damage, and onAttack, onMissed and onDeath states. The onAttack state is a weighted random, so after an attack 3 out 4 times we'll jump to state 30 and 1 in 4 we jump to state 31.
Similarly the onMissed state can also be a weighted random but we're just using a single state here.\
These states deal the the Guards retaliation, either he attacks back or backs off and his reaction can be different depending on whether your attack was successful.

State 30 deals with with the guards retaliation attack on you and you'll notice an <action type="chance"> action.
This defines a 70% chance of a successful attack - we branch again to states 32 or 33 depending on if the chance comes up trumps.

In all cases we finish with setNextState to state 50 which defines a passive state that just prints randomized I'm still fighting type message.

Your own attack on the guard also has a chance of success which varies according to whatever weapon use (the weapon is just another item).
The player can either use the ATTACK verb ATTACK GUARD WITH or as an author you can map a task that uses the doAttack consequence to something like:
FIRE GUN AT GUARD or
THROW ACID AT GUARD.

It's up to you.

The other states are used for different interactions, state 1 is the initial state when you first enter ther room and the guard asks to see your pass. State 10 is invoked from the SHOW PASS TO GUARD task. It checks whether or not have the correct pass and the guard reacts accordingly.

Templated Tasks

A lot of attack scenarios are very similar so if you have multiple NPCs that need to react in the same way then you can template the attack task:

This is the task above that allows you to THROW ACID AT GUARD:

<task id="50000" name="Throw acid at guard" countable="false">
  <trigger action="THROW" actionObject="ACID" npcIds="50000|50001"/>
  <conditions>
    <condition type="carrying" itemId="409">
      The guard says, "Get out of here before I arrest you." He raises his his gun and points it at your head.
    </condition>
    <condition type="checkUses" itemId="409">The jar is empty.</condition>
  </conditions>
  <onSuccess>
    <consequence type="doAttack" itemId="409" npcId="#{npcId}"/>
  </onSuccess>
</task>

This template defines the same THROW ACID AT task for Npcs 50000 and 50001, two different guards.
The #{npcId} matches all the Npcs defined in the trigger npcIds="50000|50001" attribute.

Note that both Npcs definitions need a state 20 that defines their reaction to a failed attack:

The Quit Game NPC

The Quit Game verb is in fact handled as an NPC. The NPC is brought from the limbo room to the players current room and the initial state invoked. From there on the NPCs state machine handles the actual quit function. So even quit can be tailored to your game.

<?xml version="1.0" encoding="UTF-8"?>
<npcs>     
    <npc id="99999" name="Quit Game">  
        
        <configuration initialRoom="999" initialState="1"/>       
        
        <state id="1" value="PASSIVE">
            <action type="message">Really quit?</action>
            <action type="choice" validResponses="Y|N">Y) Yes N) No</action>
            <action type="setNextState" nextState="2"/>            
        </state>
        
        <state id="2">
            <action type="response" response="Y" nextState="4"/>   
            <action type="response" response="N" nextState="3"/>
            <action type="runNpcState" npcId="99999"/>
        </state>
        
        <state id="3">
            <action type="message">OK</action>
            <action type="setNextState" nextState="1"/>
            <action type="moveActor" npcId="99999" roomId="999"/>
        </state>
        
        <state id="4">
            <action type="message">
                 You look up to the telescreen and realise with sudden tears in your eyes, you love Big Brother!
            </action>
            <action type="setNextState" npcId="99999" nextState="1"/>
            <action type="moveActor" npcId="99999" roomId="999"/>
            <action type="pause" amount="2.5"/>
            <action type="waitForKey">...Press [Enter] to continue...</action>
            <action type="newGame"/>
        </state>       
    </npc>
</npcs>

The Classic ASK and TELL Verbs

These are now easy to implement for your game. You must first map ASK and/or TELL with their prepositions against the DoTaskHandler in game.xml All you need to implement these is a task against the either the ASK or TELL verb and the Npc you need to respond:

<task id="32600" name="ASK Gandalf about the Ring">
  <trigger action="ASK" npcId="50000">
  <conditions>
    <condition type="checkNoun" nouns=”RING”>
  </conditions>
  <onSuccess>
    <consequence type="runNpcState" npcId=”50000” nextState=”20”>
  </onSuccess>
</task>

Then the NPC state machine state 20 interprets what is asked:

<state id="20">
  <action type="checkNoun" nouns=”RING” onSuccess=”21” onFail=”22”>
</state>
<state id=”21”>
  <action type=”message”>Gandalf, urges you not to use it!</sction>
</state>
<state id=”22”>
  ... more actions....
</state>

You can add checks for other nouns in state 22 and cascade through to support knowledge of as many items as you like. Finish with the default ‘I don’t know what you’re talking about’ or whatever is appropriate.

Note that the nouns attribute is plural – it can take a pipe separated list of nouns to recognize so the Npc can respond to multiple different requests in the same way.

Each noun does have to be a known Item within the items.xml file but those items can be virtual so you can ask about a password or even ME.

Note that at the moment TELL can only be used to implement

TELL <npc> ABOUT <object>

Giving an order to an NPC is not yet possible - but is planned for a future release probably using the SAY verb, SAY TO <npc> "quoted text".

When specifying an adverb enhanced verb for use in a task you only need to specify the verb part in the trigger action, e.g. the following trigger specifies LOOK as a supported verb but it is only the LOOK UP adverb enhanced form that is actually supported:

<trigger 
  action="COMPARE|MATCH|LOOK" actionObject="FILE|FOLDER" 
  targetObject="CARD|INDEX" targetObjectAdjective="REFERENCE"
  roomId="546"/>

Here’s the verb definition in game.xml:

<verb synonyms="LOOK" implementation="AdverbHandler" acceptedPrepositions="IN">
  <help>
    LOOK: Re-describe the current location or 
    LOOK UP [adjective] <noun> IN [adjective] <noun>; do a comparison of one object with another, look something up in an index,
etc
  </help>
  <adverbs defaultHandler="LookHandler">
    <adverb adverbs="UP" handler="DoTaskHandler">
  </adverbs>
</verb>

The main handler is AdverbHandler which acts to delegate processing to a matching subsystem. The defaultHandler specified in the <adverbs> tag is what to do when there’s no adverb typed, i.e. a standard LOOK is performed and the current room is re-described.
The only adverb understood for LOOK is UP and when UP is added the action delegates to the task handling system using DoTaskHandler.

The prepositions specified in this case are only used in the augmented adverb form of the verb.

So you can use:
LOOK UP FILE IN INDEX instead of or as well as COMPARE FILE WITH INDEX or even COMPARE FILE AGAINST INDEX.
LOOK on its own will still re-describe the room.

Room Renderers

Classically in old school Text Adventures you would end up somewhere in darkness, this would mean you can’t see anything so the usual room description output wouldn’t appear. All the player sees is some text saying ‘It’s dark’ or something similar.

This can be achieved by selecting the dark room renderer instead of the default renderer. In practice this simply means adding a tag to the room and mapping the dark room renderer to that tag.

game.xml again provides the definitions for the renderers.

<renderers package="org.happysoft.games.renderers">
  <renderer type="DarkRoomRenderer" roomTags="dark" itemTagsNotPresent="light-source-active"/>
</renderers>

Then the room where this renderer applies would include a tag as follows:

<room id=”1234” name=”Underground Tunnel” tags="dark">...</room>
... more rooms ...

The DarkRoomRenderer and the default renderer are the only renderers available at the moment.

The DarkRoomRenderer is used on any room that has the tag ‘dark’ unless you are carrying an item or there is an item in the room that has the tag ‘light-source-active’.

These tags are configurable of course, you can use whatever you like.

Note that by using the swap items paradignm I've talked about before in conjuntion with having the light-source-active tag is on a carried item we also automtically solve the age old problem of what happens if I have a torch and put it in a box then close the box.
By swapping the box for the closed box the torch is no longer present and presto, your room goes dark again automatically.

Why not have the tag ‘light-source-active’ on the room I hear you ask? You can do it if you like, it’s up to you. You can also manage all of this manually if really want to and dynamically change the room description.
This approach is best if you have lots of rooms that need to be treated this way otherwise it’s a lot of scripting to keep everything up to date.
Also if the light source is portable there’s no especially easy way of noticing you’ve left a room so how do you update that it’s no longer lit?

At some point you’ll be able to add further renderers of your own devising. I can’t really think of many more that would be needed at the moment.

Maybe you could add some flavour renderers that add extra flavour to the default description at night or in bad weather or something?
You can do much of this via universal events already of course, I’ll provide an example in the appendix, but a renderer might be a cleaner solution as it is with ‘dark’.

Interceptors

Interceptors provide a way to interrupt the processing of a player command before it is executed.

Interceptors are also tag based but the tag can exist on a room or an item then the interceptor can run depending on the verb that they typed.

If an interceptor is found that matches the current sentence then an event will be triggered.

Let's have a look at some sample configuration and discuss how it can be used:

<interceptors>
  <interceptor actionHandler="DirectionHandler" roomTags="dark" itemTagsNotPresent="light-source-active" eventIds="20000"/>
  <interceptor verbs="GET|TAKE" itemTags="smelly|plural" eventIds="20001"/>
  <interceptor verbs="GET|TAKE" itemTags="smelly" eventIds="20002"/>
  <interceptor verbs="ATTACK" roomTags="holy" eventId="20003"/>
</interceptors>

The configuration lives in the game.xml file alongside the room renderers.

The first example defines an interceptor that allows you to block a players movement in the dark.
In the same way as Room Renderers roomTags="dark" can be cancelled by the itemTagsNotPresent attribute so if you're carrying an item that has the specified tag then the intercept won't occur.

You'll notice that I've defined actionHandler not the verb being typed. Either can be set but actionHandler is easier in this case as there's a lot of different directions you need to map.
Verbs is certainly more appropriate if you need to intercept a task, DoTaskHandler would be too general so you'll want to map a specific verb or verbs.

The second example shows a Verbs specific interceptor that intercepts anything defined to be 'smelly'.
Note there are two versions of the interceptor, one looks for a plural tag as well as the smelly tag, the second version just the smelly tag and they map to different events.
This allows you to output a pluralised message if need be.

Let's have a quick look at the events you could associate with these Interceptors:

<event id="20000" name="Move in Dark Room" type="EVENT_TRIGGERED">
  <conditions>
    <condition type="chance" occurs="1" probabilitySpace="4"/>
  </conditions>
  <onFailed>
    <consequence type="message">You stumble around but can't seem to find the exit again.</consequence>
    <consequence type="blockAction"/>
  </onFailed>
</event>
    
<event id="20001" name="Plural Smelly" type="EVENT_TRIGGERED">
  <onSuccess>
    <consequence type="message">They smell too much to go near them.</consequence>
    <consequence type="blockAction"/>
  </onSuccess>
</event>

<event id="20002" name="Singlular Smelly" type="EVENT_TRIGGERED">
  <onSuccess>
    <consequence type="message">It smells too much to go anywhere near it.</consequence>
    <consequence type="blockAction"/>
  </onSuccess>
</event>

<event id="20003" name="Attacking in a Shrine?" type="EVENT_TRIGGERED">
  <onSuccess>
    <consequence type="message">You feel an overwhelming compulsion to lower your weapon.</consequence>
    <consequence type="blockAction"/>
  </onSuccess>
</event>

The first event has you stumbling around and not being able to find the exit in the dark.
The second has no conditions at all - we know the action item has the tag else the interceptor wouldn't have fired.

The second and third interceptors lead to two events depending on whether there's an item tag or not.

So, all these are perfectly ordinary events, we just use the blockAction consequence if the event determines the action shouldn't go ahead.

Imagine now a task, SPRAY SOCKS WITH PERFUME and one of the consequences of this task is a

<consequence type="removeItemTags" itemId="[socks_item]" tags="smelly"/>

and now you're able to pick up the smelly item without hindrance - so this opens up another type of puzzle.

Appendix A - Releasing Your Game.

The resources you need are:

generate_resource_bundle.bat
build.properties

The build.properties file should contain a single entry:
release.dir=..\path_to_a_directory\

which is where all the final build file (gamedata.dat and the message bundles) will be copied to.

By default the run.bat and run.sh scripts look for either a folder called dev that contains all your XML scripts or a file called gamedata.dat. This is wher it will run your game from.

This is fine but a bit generic so we can improve on that.

First off generating your gamedata release file.
To do this you can use a simple utility script that is provided called generate_resource_bundle.bat (bash script equivalent pending).

This script if run with no parameters looks for the dev folder and generates an encrypted file called gamedata.dat from its contents.

It can take up to two parameters.
If just one parameter is given this will be used as the name of the final encrypted game data file.
So running "generate_resource_bundle.bat cloak.dat" will produce a file called cloak.dat from the XML stored in the dev folder.

If two parameters are given the first is interpreted as the folder to look for you game XML files in and the second is the name of the final output file.

So running "generate_resource_bundle.gat cloak_of_darkness cloak.dat" produces a cloak.dat file but this time derived from the contents of the cloak_of_darkness folder rather than the dev folder as before.

If the folder is specified and exists it and its contents will also be copied too your release directory.

And that's about it.

Appendix B - The game.xml file

Here’s an abridged version of the full game.xml definition file. The only thing missing is some verb definitions which you don’t really need all of, a few will do and any others are all the same.

Note the game tag has a debug attribute which if set to "true" allows you to see extra output which may be useful while you’re developing a game.

<?xml version="1.0" encoding="UTF-8"?>
<game debug="false">
  <welcome>*** Welcome to 1984: Eyes of the State****</welcome>

  <auxiliaryMessages>  
    <!-- 
      Auxiliary messages handle structural grammar logic that standard key-values can't.
      This can be translated directly.    
    -->
    <message type="BELONGS" selectorTag="plural" noMatch=":1 doesn't belong in :2." match=":1 don't belong n :2."/>            
  </auxiliaryMessages>
    
  <player inventory="1|-101" 
          startRoom="1" 
          timeout="5" 
          skiptime="10" 
          hp="100" 
          defaultCombatItem="-1" 
          onDeathEvent="500000" 
          quitGameNpc="99999"/>   

  <currency major="Dollars" minor="Cents" symbol="$" initialBalance="0"/>
  <gameClock type="24" startTime="13:00"/>
  
  <!--
    Uncomment this to enable 16 point compass directions. 
    You can add 32 point directions here too. You map the actual verbs
    below in the directions element.  
    These are extra directions you are asking the system to understand
    as opposed to the verbs that translate to those directions. 
    The standard N,E,S,W etc directions are already built in, you only 
    need to use this tag if you wish to add any further directions. 
    <canonicalDirections directions="NNE|ENE|SSE|ESE|SSW|WSW|WNW|NNW"/>
  -->
           
  <directions defaultHandler="org.happysoft.games.action.handler.DirectionHandler">
    <defaultHelp>
       Move the player in the compass direction specified or UP or DOWN. 
    </defaultHelp>
    <direction direction="N" canonicalDirection="NORTH" display="North"/>
    <direction direction="E" canonicalDirection="EAST" display="East"/>
    <direction direction="S" canonicalDirection="SOUTH" display="South"/>
    <direction direction="W" canonicalDirection="WEST" display="West"/>
    <direction direction="NORTH" canonicalDirection="NORTH" display="North"/>
    <direction direction="EAST" canonicalDirection="EAST" display="East"/>
    <direction direction="SOUTH" canonicalDirection="SOUTH" display="South"/>
    <direction direction="WEST" canonicalDirection="WEST" display="West"/>
    <direction direction="NE" canonicalDirection="NORTHEAST" display="NorthEast"/>
    <direction direction="NW" canonicalDirection="NORTHWEST" display="NorthWest"/>
    <direction direction="SE" canonicalDirection="SOUTHEAST" display="SouthEast"/>
    <direction direction="SW" canonicalDirection="SOUTHWEST" display="SouthWest"/>
    <direction direction="NORTHEAST" canonicalDirection="NORTHEAST" display="NorthEast"/>
    <direction direction="NORTHWEST" canonicalDirection="NORTHWEST" display="NorthWest"/>
    <direction direction="SOUTHEAST" canonicalDirection="SOUTHEAST" display="SouthEast"/>
    <direction direction="SOUTHWEST" canonicalDirection="SOUTHWEST" display="SouthWest"/>
    <direction direction="UP" canonicalDirection="UP" display="Up"/>
    <direction direction="DOWN" canonicalDirection="DOWN" display="Down"/>
    <direction direction="U" canonicalDirection="UP" display="Up"/>
    <direction direction="D" canonicalDirection="DOWN" display="Down"/>
    <!-- 
     <direction direction="NNW" canonicalDirection="NNW" display="North by NorthWest"/>
    -->
  </directions>

  <movementModes>
    <mode verb="CRAWL" timeMultiplier="2"/>
    <mode verb="RUN" timeMultiplier="0.5"/>
  </movementModes>
  
  <renderers package="org.happysoft.games.renderers">
    <renderer type="DarkRoomRenderer" roomTag="dark" itemTagsNotPresent="light-source-active"/>
  </renderers>

  <handlerSelectionRules package="org.happysoft.games.action.handler.rules">
    <rule name="CheckTargetObjectNotNull" implementation="TargetObjectNotNullRule"/>
    <rule name="CheckTargetAcceptsItems" implementation="TargetObjectAcceptsItemsRule"/>
  </handlerSelectionRules>
    
  <!-- These are usually articles, and will need changing per language --> 
  <ignoredWords>GO|THE|A|AN|SOME|OF|YOUR|ONE|TWO|FEW| | </ignoredWords>
  <pronouns>IT</pronouns>
  <again>A|AGAIN|REDO</again>

  <verbs defaultPackage="org.happysoft.games.action.handler">
    <verb synonyms="LOOK" handler="AdverbHandler" acceptedPrepositions="IN">
    <help>
      LOOK; Re-describe the current location
      LOOK UP [adjective] &lt;noun&gt; IN [adjective] &lt;noun&gt;;look something up in an index for example 
    </help>
    <adverbs defaultHandler="LookHandler">
      <adverb adverbs="UP" handler="DoTaskHandler"/>
      <adverb adverbs="AT" handler="ExamineHandler"/>
    </adverbs>
  </verb>
  ... All the other verbs ...  
 </verbs>
</game>

We now describe each of the elements that are valid in the game.xml file. There are two further element blocks that aren’t used but are valid which are <properties> and <counts>. These are usefult for testing and debugging puzzles whilst developing.\

The <welcome> Element

Pretty much what it says on the tin – just defines the welcome text that you see at the beginning of the game.

The <auxiliaryMessages> Element

Auxiliary messages provide an extension to the messages_.properties file. There are only a few places where the system uses them at the moment:

  • Where one item requires another to work or to activate etc
  • When a market trader offers a newly acquired item for sale
  • Also in trading when attempting to SELL an item to a trader,
  • When attacking an NPC with a weapon (in the weapon definition).

Basically they provide the ability to output a message with the correct auxiliary verb based on the presence of an item tag, e.g.
Them vs It in the case of plurality or possibly different messages based on gender.

<auxiliaryMessages>
  <message type="BELONGS" 
    tag="plural" 
    noMatch=":1 doesn't belong in :2." 
    match=":1 don't belong in :2."/>
  <message type="TRADE" 
    tag="plural" 
    noMatch="I've got :1 if you want, I'll do it for :2.|I've got :1 if you're interested. I'll do it for :2."
    match="I've got :1 if you like. I'll do them for :2."/>
</auxiliaryMessages>

For weapons the inner message element <message> is embedded into an item <weapon> definition disguised as the <hit> and <miss> elements.

The <player> Element

Defines the initial player conditions.

<player inventory="1" startRoom="1" timeout="5" skiptime="10" hp="100" onDeathEvent="500000" quitGameNpc="99999"/>
Attribute Meaning
inventory pipe | separated list of items the player is initially carrying.
startRoom the room to start the game in.
timeout amount of real world time that passes before a ...Time passes... message is output when you don’t type anything.
skipTime the amount of game time that passes when timeout occurs.
hp the players initial hit points.
defaultCombatItem a weapon item to be used when ATTACK does not specify a weapon. This would usually be hand-to-hand combat.
onDeathEvent should the player die in battle this event is fired.
quitGameNpc this is an NPC that the Quit Game Verb runs to handle the 'Do you really want to quit?' question. If it's not specified the player will just get the Press [Enter] to Continue message without any 'Are you sure? Y or N' confirmation.

The <currency> element

Definition of the currency for your world.

<currency major="Dollars" minor="Cents" symbol="$" initialBalance="0"/>

major – the main unit
minor – the minor unit
symbol – currency symbol, being a text adventure this is pretty well restricted to usual printable characters but UTF-8 should be OK to use.
InitialBalance – the players starting wallet. Decimals are supported but only two decimal places will be shown.

The <gameClock> Element

The type of clock to be used in your game and the initial time when the game first starts. Usually this will be a 12 or 24 hour clock but you can define any number of hours for your games’ day.
If you set hours as zero then the clock is disabled. If you set hours as 12 then an am/pm suffix is used and the hours run from 1 to 12. Otherwise hours run from 0 to hours-1.

Hours always have 60 minutes. I should make this configurable but I haven’t got around to it yet.
Negative hours don’t mean anything.

<gameClock type="24" startTime="13:00"/>

type – type of clock to use, 12 hour, 24 hour or any non zero number of hours for your day.
startTime – the time at the beginning of the game.

Note even though granularity is minutes, game events are timed only to the nearest hour, so you can only specify a startHour and endHour for an interval. But actions are timed in minutes.

The <directions> Element

See the section on Directional Verbs.

The <renderers> Element

See the section on Room Renderers.

The <interceptors> Element

See the section on Interceptors.

The <adverbSelectionRules> Element

Adverb selection rules.\

This is a list of defined selection rules that can alter the behaviour of a verb plus adverb combination.
There's currently only a few of these and their use is limited. But see the PUT and LOOK verb plus adverb definitions for an example of how they can be used.

The <ignoredWords> Element

These are words that have no particular semantic meaning to the parser but the player is likely to type.
These are more or less the same as the articles used for item names but include things like GO so that the player can type GO NORTH instead of NORTH or N and the parser won't grumble.

The <pronouns> Element

The words we can use for IT. This word basically takes on the value of the most recent action object typed in a sentence.

The <again> Element

The words we can use for AGAIN. AGAIN repeats the previous command.

The <properties> Element

A block level element defining any number of <property/> sub-elements, e.g.

<properties>
  <property key=”homeDeskUnlocked” value=”true”/>
</properties>

This can be used to pre-set some game states. Mainly useful for testing but you can use it to set any game state if you so need to.

The <counts> Element

Like properties but for game counters. It can contain any number of <count> sub-elements, e.g.

<counts>
  <count key=”thoughtPoliceSuspicion” count=”90”/>
</counts>

Again, certainly useful for testing but can be used to set any counts you use in advance.

The <verbs> Element

This contains all the verb definitions with their prepositions and adverb forms as discussed throughout the text.

Appendix C - Verb Handlers and Standard Verbs

Following is a list of verbs the engine currently understands and the handlers used to implement them.

Any handler may be reused for a new verb or with an adverb augmented verb. Just define it in game.xml and it will be available for your game.

Handler Class Verbs (or synonyms)
DirectionHandler NE|NW|SE|SW
NORTH|SOUTH|EAST|WEST
NORTHEAST|NORTHWEST
SOUTHEAST|SOUTHWEST
U|D
UP|DOWN

DirectionHandler moves the player to a new location in the given compass direction and increments the game clock by the amount of time indicated by the room definitions exit list.
Only the exits available are allowed.

LookHandler

LOOK|L

Performs a standard LOOK function to re-describe the current location.
There are adverb forms such as LOOK AT or LOOK THROUGH though so ordinarily LOOK is mapped to the AdverbHandler and gets routed back to the LookHandler if it's a plain LOOK request.

AttackHandler

ATTACK|KILL

AttackHandler instigates an attack on an NPC optionally with a weapon (if no weapon specified it is assumed you’re attacking with your bare hands).
For a full description see the section on combat.

ExamineHandler

EXAMINE|EXAM|X

ExamineHandler describes an object in more detail and may invoke an onExamined event if one is defined on the object.

InventoryHandler

INVENTORY|INV

InventoryHandler lists all items the player is carrying along with their value.

TakeHandler

GET|TAKE

Pick up an object and may invoke an onTaken event if one is defined on the item.
TAKE OFF may be supported via the AdverbHandler pointing to the DoTaskHandler.

DropHandler

DROP

Drop the given item if the player is carrying it. This handler will fire a onDropped event if one is defined on the item.

PutHandler

PUT

PutHandler specifically places an item in or on another item. The ‘target’ item must be a container.
Various adverb forms of PUT, PUT ON, PUT as an insert can also be supported via the AdverbHandler and the HandlerSelectionRules.

SellHandler

SELL

SellHandler initiates a sale with a trader NPC.

BuyHandler

BUY

BuyHandler initiates a transaction with a trader NPC.

SwapHandler SWAP|EXCHANGE|OFFER
Swap a carried item for something a trader is selling.
ShowHandler

SHOW

Show a carried item to an NPC. If the NPC is also a trader they will give you a price if they're willing to buy it from you. If they aren't a trader then it will pass this through to the DoTaskHandler to see if there's a task to handle a show event.

SayHandler

SAY
Say something out loud.
At some point I need to support SAY TO <npc> “quote”, where quote could be another Sentence that instructs the NPC to do something but currently that's not supported.
This can be used to say a password for example to get a past a guard or open a secret entrance.

The Hobbit did it back in 1983 so I should do it! e.g. SAY TO THORIN “CARRY ME” and Thorin picks you up so you can reach a Window.

WaitHandler

WAIT|WA

Wait for default period or specified amount of time.

TimeHandler

TIME

Shows the current time in game-land.

SaveHandler

SAVE

Save the current game to a file.

LoadHandler

LOAD|RESTORE

Restore or reload a game from a saved file.

HelpHandler

HELP

Shows the list of verbs and their expected syntax.

QuitHandler

QUIT

Give up and start over.

ScoreHandler

SCORE

Show your current score (based on tasks executed and percentage of the map explored).

DoTaskHandler

Many verbs including but not limited to:
ASK, ATTACH, DETACH, BOLT, UNBOLT, CALL, OPEN, CLOSE, GIVE, INSERT, SMASH, LOCK, UNLOCK, PAY, PLUG, UNPLUG, REMOVE, THROW

Various Verbs

This is a general handler which attempts to match what the player typed against a task. If a task is found then invokes it is invoked with all its associated conditions and consequences.
See the section on Tasks for details on how to script a task and its sentence trigger.

AdverbHandler Various verbs
This handler acts as a switcher for verbs depending on if an adverb is present, e.g:
PICK UP → TakeHandler
PICK → DoTaskHandler
SWITCH is an example of a verb that is mapped to AdverbHandler but delegates to the ItemActionListener
ItemActionListener Various Verbs
This handler acts as a switcher for a verb/adverb combination depending on if an item with a particular tag is present, e.g:
SWITCH ON → ItemActionListener (activatable)
SWITCH OFF → ItemActionListener (deactivatable)
SWITCH itself is mapped to the AdverbHandler.

Appendix D – Internationalisation

It is intended for the system to be fairly well internationalizable. The reality of this notion may well be different from what I hope of course, languages aren't really my strong point but I will show you how I think the problem can be approached.

The messages.properties File.

Internationalisation is built in mainly via the messages.properties file. You will notice the file is actually called message_en_GB.properties. You can define a messages_fr_FR.properties or an equivalent for any language and locale and the Java Runtime will automatically pick it up if the machine running it is set to that locale.

The naming of the properties follows the standard Java internationalisation rules. We start with:
messages.properties
then we can become language specific with:
messages_en.properties
and finally we can become country specific with:
messages_en_GB.properties

Hence locale specific languages may be supported, eg. messages_en_US.properties to supprt US English (usually just different spellings, but may be different phrasing etc).

This covers most of the system messages when an action is complete or has failed and some other default messages.

The system.properties File (item naming and general engine properties)

Items can be named as you like so using a French or Italian name makes no difference directly. However, the system needs to be told to expect adjectives to come after the noun for (say) French language translations.
Any author can use the article, name and adjective fields for each item and thus alleviate the need to look more closely but there is the name attribute too. If you use this then system needs to know whether or not adjectives come before or after the noun.
To this end there's one more important properties file - system.properties that needs to be altered.

There's not many entries in this file:
CAPS_ON = true
ADDITIONAL_SEPARATOR_CHARS =
ADJECTIVE_FIRST = true
DEFAULT_ARTICLE = THE

You may need to set ADDITIONAL_SEPARATOR_CHARS = ' (an apostraphe) in order for the system to recognize the article in words such L'ARMURE ROUILLEE or D'ARGENT COUVERT for example in French.
DEFAULT_ARTICLE can be set to provide an article in cases where none is given but where gender matters it's probably best to provide the right one.

When you create a resource bundle using the generate_resource_bundle utility the system.properties is saved along with everything else.
system.properties usually lives with all the other development files in the dev folder (or wherever you keep your game files) but it can also be placed in the root folder of your install.
The copy in the root folder can be used to override whatever values are in the game folder.

If neither is provided the default values above are used.

CAPS_ON = true turns on CAPS LOCK at the start of a game.
I think it adds to the old school feel of a text adventure when you type in your commands in capitals but there's always someone who disaproves so this property can off all caps.

Other Elements That Require Translation

Directions can be translated in the game.xml file by mapping a new direction declaration to a canonical 'system' direction in the <directions> element.

And the game.xml file also provides mappings for all the verbs, adverbs and prepositions that verbs can take so they ought to translatable directly in there.

Clearly you can define whatever messages you like within the task and event xml files too. So task output can be in whatever language you wish.
Don't forget to update the task trigger to match your new verb definitions.

The sentence parser itself doesn't care what order indiviual words come in but it does scan through for the verb first which then allows it to find particular verb-adverb combinations that it understands and check the required preposition is present.
Again the order here doesn't matter so the verb can come at the end of the sentence and nouns and adjectives throughout.

The only thing to bear in mind is when interpreting many verbs action object and target object matter and the order of these is the order presented in the sentence the player typed.
e.g THROW BOTTLE AT WALL - BOTTLE is the action object because it comes first and WALL is the target object.

Similarly any adjectives that go with them. THROW RED BALL AT BRICK WALL. So these can be translated directly but may not be interpreted correctly if the language you're aiming for expects a different order of action and target.
I'm not sure if this ever happens, it can be accounted for if it does.

Articles are always ignored, so that should be fine as long as they're defined so it knows to skip them.
Pronouns such as IT are defined in the game.xml file. IT is usually interpreted as the last action object typed. It's a best guess but it's not always correct.
Words other than articles that should be ignored are also defined in the ignored words list.

Current System Messages

This is the current set of system messages. It's highly likely this will be added to but these are the kind of thing that obviously need translating straight off.

DIRECTIONS_NONE = "None."
DIRECTIONS_TO = " to "

ITEM_PRICE = "It is worth :1."
ITEM_NO_PRICE = "It is of little value."
ITEM_NOT_WEAPON = "You can't use that as a weapon."

ITEMS_CARRYING = "You are carrying: "
ITEMS_NOTHING = "Nothing."
ITEMS_NOT_CARRYING = "You are not carrying the :1."
ITEMS_YOU_CANT_TAKE_THAT = "You can't take that!"
ITEMS_MAYBE_OPEN_IT_FIRST = "It needs to be opened first."
ITEMS_YOU_CANT_SEE_THAT_ITEM = "You can't see that item here."
ITEMS_YOU_CANT_SEE_ADJECTIVE_NOUN = "You can't see :1."
ITEMS_WHAT_DO_YOU_WANT_TO = "What do you want to :1?"
ITEMS_THATS_THE_WRONG = "That's the wrong :1."
ITEMS_SPECIFY_WHICH = "Specify which :1 to use."
ITEMS_YOU_DONT_HAVE_THE_CORRECT = "You don't have the correct :1."
ITEM_YOU_CANT_DO_THAT = "You can't do that with :1."

TRADE_ITEM_NOT_OFFERED = "The :1 :2 not offered for sale or trade."
TRADE_SPECIFY_WHAT_TO_TRADE = "You need to specify what you need and what you are willing to trade for it."
TRADE_WHAT_DO_YOU_WANT_TO_TRADE = "I'm not sure what it is you want to trade."
TRADE_INSUFFICIENT_FUNDS = "You don't have enough money to buy that."
TRADE_REJECTED = "Nah, it ain't worth it for that."
TRADE_ZERO_VALUE = "You kidding me? That's a worthless piece of junk."
TRADE_OFFER = ":1 offers you: :2."

NPCS_NPC_NOT_A_TRADER = ":1 is not interested in trading."
NPCS_NPC_NOT_HERE = ":1 is not here."
NPCS_NO_NPC_HERE = "There's nobody here."
NPCS_NO_TRADER_HERE = "There's no trader present."
NPCS_SPECIFY_WHO_YOU_ARE_INTERACTING_WITH = "Specify who you are interacting with."
NPCS_NPC_IS_DEAD = ":1 is dead."
NPCS_NPC_NO_COMBAT = "There's no point in attacking :1, they're not armed."
NPCS_PRESENT_DARK = "You can sense someone is here.|You think you can hear someone in the dark.|You can feel a presence, is there somebody nearby?"

USAGE = "Use: :1"
TIME_PASSES = "... Time passes ..."
GAME_SAVED = "Game saved."
SAVE_GAME_FAILED = "Save game failed: :1"
LOAD_GAME_FAILED = "Load game failed: :1"
I_DONT_UNDERSTAND = "I don't understand ':1'"
I_DONT_UNDERSTAND_USE = "I don't understand that use of :1."
THERES_NO_POINT_IN_DOING_THAT = "There's no point in doing that."
NOBODY_IS_INTERESTED_IN_WHAT_YOU_SAY = "Nobody is interested in what you say."
SPECIFY_AN_ACTION = "Specify an action with :1."
CLOCK_DISABLED = "Game clock is disabled."

YOU_CANT_GO_THAT_WAY = "You can't go that way!"
YOU_CAN_SEE = "You can see: "
IT_IS_DARK = "It is dark, you can't see anything."
YOU_ARE = "You are "
YOU_CAN_ALSO_SEE = "You can also see: "
EXITS_ARE = "Exits are: "
EXITS_PRESENT_DARK = "You can sense exits around but it is difficult to discern anything clearly.|There must be some exits but it's too dark to see."
MOVE_IN_DARK = "You grope your way :1.|You feel your way :1.|You cautiously edge your way to the :1."
YOUR_CURRENT_BALANCE = "Your current balance is :1"
CURRENT_TIME = "The current time is :1"

COMBAT_NO_WEAPON = "You attack :1."
COMBAT_WITH_WEAPON = "You attack :1 with :2."
COMBAT_WITH_WEAPON_MISS = "You attack :1 with :2 but they dodge."

PRESS_ANY_KEY = "Press [Enter] key to continue..."
WHAT_NEXT = "What next? "
CHOOSE_AN_OPTION = "Choose an option: "

⚠️ **GitHub.com Fallback** ⚠️