Author Archives: textadventurescouk

How to fix a bug in Quest 5.0

Recently a bug was added to the Issue Tracker which sounded like a great one for somebody new to the project to dive into. The issue was that commands with upper-case characters didn’t work – you could type “take box” but not “TAKE BOX”. Unfortunately, nobody took the opportunity to fix it, so I’ve fixed it myself. But I thought it would be a good idea to take you through the process from the beginning, so you can see exactly what’s going on here. Hopefully by documenting this it will make it easier to join in with the project if you’re interested, as I realise all that code can be a bit daunting at first.

This blog post will give you an overview of how Quest 5.0 processes user commands, without prior knowledge of how the system works – I’ll try and guide you through the system assuming you’ve never seen the code before.

For this tutorial I’ll assume you have Visual Studio 2010 installed, and that you’ve checked out the Quest 5.0 source code on CodePlex. You should also read the Introduction for Developers – although the Technical Overview may make more sense after reading this tutorial, so don’t be put off just yet!

Note that I have not yet checked in my fix for the bug, so you can still see the bug in action and follow the steps below to fix it on your own machine. Update: The fix for this was checked in on 4th December 2010, so if you want to follow these instructions yourself, update to an earlier revision in SVN.

Reproducing the problem in the debugger

Fire up Visual Studio and open the solution file. Make sure that the “Quest” project is set as the StartUp project, then Run.

We could easily reproduce this issue in any game, and the SVN repository contains example ASLX game files under WorldModelWorldModelExamples-Public. To debug this I chose test.aslx.

Using this game, I did a bit of experimentation with a few different ways of writing the same command, and got this output:

> TAKE SOFA
I don't understand your command.

> Take sofa
I don't understand your command.

> take SOFA
You can't take it.

> take sofa
You can't take it.

This is interesting – it looks like Quest correctly handles different capitalisation for object names (it handled both “SOFA” and “sofa” in the final two commands, without telling us that it couldn’t see an object of that name), but it seems to be having trouble with “TAKE” vs “take”. So the problem is with capital letters in the first part of the command, rather than the object name.

What happens when we type a command

So, which part of the code handles commands? Let me take you on a tour…

First, we’re typing commands into a textbox at the bottom of the Quest window, but where does that textbox live in the code?

Screenshot

The Quest project has a form called Main.vb that contains everything – not just the game playing interface, but the game editor, and the game launcher that you see when you first start Quest. But it’s quite a thin wrapper – each of these components is implemented as a user control. The game playing interface is ctlPlayer, which is an instance of Player.vb in the Player project.

Go to Player.vb and you’ll see this contains:

  • a WebBrowser control, used for the game output
  • a Label control at the top, used to display the current location
  • two ElementList controls, defined in the same project. These are used for the “Inventory” and “Places and Objects” lists on the right of the screen.
  • a Compass control, also defined in the same project.
  • aha! A TextBox and Button, which is where we’re typing in our commands.

So we now know where the chain of execution begins.

Passing the command from the GUI into the game

If you look at the code behind the button (cmdGo_Click), you’ll see it simply calls the EnterText sub, which in turn calls RunCommand, which calls m_game.SendCommand(). The same thing gets called when you hit the Enter key inside the textbox (although it happens via a timer so that the KeyDown event code finishes before we send the command).

m_game is an instance of an object which implements the IASL interface. The idea of the interface is that, in future, we may well want to hook up different “engines” to the same Player interface. This would let the same Quest front-end handle games for potentially different systems entirely, or more likely just different versions of the Quest engine. So we never directly link the Player front-end to the WorldModel project, which in this case is the engine driving test.aslx – we only ever talk to it through the IASL interface.

The IASL interface is defined in the IASL project, and it defines a few methods and events but the really important ones are:

  • SendCommand(string) which is how we pass a command into the game
  • PrintText event which is how the game tells the GUI what text should be printed

So let’s see what happens next. The WorldModel project has WorldModel.cs, which is our implementation of the IASL interface for Quest 5.0 games. If we go here and navigate to SendCommand, we can see that we print the command back, so the user knows what they just typed, and then we call RunProcedure and pass in various arguments.

RunProcedure("HandleCommand", new Parameters("command", command), false);

What’s happening here is that instead of using C# code to handle the command, we’re actually going into the ASLX file. WorldModel expects the ASLX file to provide a “HandleCommand” function, which will do all the work of processing what the user typed in. This is part of the design philosophy behind Quest 5.0 – a game author or Quest library author could define their own command parsing logic, or enhance the default logic, without having to make any changes to the Quest code itself.

So what we have here seems to be a bug in the Core library, in the HandleCommand function which is written in ASL, rather than a bug in the C# code.

Handling the command in the Core library

The default “HandleCommand” function appears in all ASLX games via Core.aslx, which is included in test.aslx (and probably will be in every Quest game) via the include tag:

<include ref="Core.aslx"/>

You can find Core.aslx under the Core folder in the WorldModel project. You’ll see that it includes various other files, as a way of splitting up the file into more manageable parts. You can use Visual Studio’s very handy “Find in Files” feature (Ctrl+Shift+F) to find where HandleCommand is defined – it’s in CoreParser.aslx.

The ASL should be fairly easy to read as it’s not too dissimilar to C#. All its script commands and functions are documented on the Quest wiki.

Let me talk you through how the function works. The parameter “command” is populated with what the player typed in, such as “take sofa”, and the first thing that happens is this:

candidates = NewObjectList()
foreach (cmd, ScopeCommands()) {
  if (IsRegexMatch(cmd.pattern, command)) {
    list add (candidates, cmd)
  }
}

All commands in Quest are objects, and they can either apply to the whole game or a specific room. In the snippet above, we find out what commands are available by calling ScopeCommands() – this will give us back a list of command objects (the function itself is defined in CoreParser.aslx, so take a look if you’re interested).

Each command object has a property called “pattern”, which defines a regular expression that the input must match to trigger the command. We loop through all available commands, see if the pattern matches our input, and then we have a list of candidates.

The rest of the function determines which candidate is the strongest match for the input. Then it populates variables and runs the command’s script.

The command objects themselves are all defined in CoreCommands.aslx, and the “take” command is right at the top. The command object specifies the pattern regex that must be matched to trigger the command:

<command name="take" pattern="[take]">

In this case the pattern is in square brackets. Anything in square brackets gets taken from the template. In this case the templates are defined in English.aslx, and if we search for “take” in this file we find three verb templates that match:

<verbtemplate name="take">take</verbtemplate>
<verbtemplate name="take">get</verbtemplate>
<verbtemplate name="take">pick up</verbtemplate>

Verb templates are a special kind of syntactic sugar to save us the hassle of repeatedly typing very similar (and very ugly) regular expressions. If you run the game and click the Tools menu, then Debugger, you’ll see what the effect is. Click the Commands tab and look at the “take” object.

Debugger screenshot

You’ll see that via the magic of these three verb templates, the “pattern” property of our “take” object becomes:

^take (?<object>.*)$|^get (?<object>.*)$|^pick up (?<object>.*)$

Now we see why both “take SOFA” and “take sofa” work – they both match this regular expression, with the named “object” group being “SOFA” or “sofa” respectively. But a command like “TAKE SOFA” will not be matched, as the regular expression expects the word “take” to be in lower case. This means that when we type “TAKE” in capitals, the “take” command won’t even be added to the “candidates” list in the ASL snippet above, hence the command fails.

How best to fix this?

The problem is with this line in the CoreParser.aslx snippet above:

if (IsRegexMatch(cmd.pattern, command)) {

We want to perform a case-insensitive comparison, so we have a couple of options:

  • lower-case the “command” string before passing in to the IsRegexMatch function
  • update the IsRegexMatch function to perform a case-insensitive comparison

The first option is quickest, and would be a simple matter of updating the line like this:

if (IsRegexMatch(cmd.pattern, LCase(command))) {

However, I can see two problems with this:

  • it requires all command patterns to be defined in lower-case
  • it might not work in all languages

This question on StackOverflow leads me to think that updating the IsRegexMatch function would be the best approach.

The IsRegexMatch function is defined in QuestFunctions.cs – so in fact we need to do a C# code change after all, and leave Core.aslx as it is!

[Update: This fix was checked in as part of other work which has moved the code that was in QuestFunctions.cs to a new file ExpressionOwner.cs]

Designing the fix

Here is the offending line in IsRegexMatch:

System.Text.RegularExpressions.Regex regex =
    new System.Text.RegularExpressions.Regex(regexPattern);

which we need to update to

System.Text.RegularExpressions.Regex regex =
    new System.Text.RegularExpressions.Regex(regexPattern,
        System.Text.RegularExpressions.RegexOptions.IgnoreCase);

Bear in mind this will affect all usages of the IsRegexMatch function – but a quick search through the code reveals that it’s only used in one place, and that is the HandleCommand function we’ve been looking at. So I think this is a safe code change to make for now, and it’s a reasonably safe assumption that anybody who wants to call this function in Quest is probably using it for command processing and therefore probably wants to do a case-insensitive search as well. But in the future it may be worth making an overload of this function so that we can specify a boolean to make it explicit whether we want a case-sensitive comparison or not. I won’t add this now as I don’t think there is much point in adding superfluous functions that may not be needed – it will be simple enough to add this later if anyone requires it.

Conclusion

So there we have it – a simple one-line change for a simple problem. It took quite a lot of explanation to get here, but hopefully now you have a feel for how things hang together. There is a lot more detail we could go into – just how does that ASL script get run, you may be wondering – and maybe I’ll cover these another time. But now you have an overview of how it works, the best thing may be to step through the code yourself and see exactly what’s happening at each level.

As I said above I have not yet checked in my fix for this, so for now you can still see the bug in action and step through the code yourself using the tutorial above. Update: You can still step through this code if you update to a revision prior to 4th December 2010, or you could still step through the current version – just bear in mind that the fixed code now appears in ExpressionOwner.cs.

I’m happy to answer any questions you may have, so please feel free to add comments to this blog or ask for help in the forum. If there is an entire area of the system that you feel needs some more explanation, please let me know and I’ll write another blog post to give you an overview.

Quest 5.0 is now open source

I believe Quest 5.0 has the potential to be a great system. I’ve put a lot of thought into the design and I think it’s shaping up to be a far more powerful, robust and flexible system than its predecessor.

But while it’s nice to have software that is good on a technical level, it doesn’t mean very much if it doesn’t have very many users.

The previous approach

Quest 4.x is sold on a “try before you buy” model, at least for people who want to create games. If you only want to play games, there is no need to pay – just download Quest and away you go. If you want to create your own games though, that costs money. Earlier versions had a 30-day trial of QDK, the game editor, although in v4.0 that restriction was removed in favour of a cut-down “lite” version that lets you create smallish games. So in the current system, if you want to create a bigger game, you have to pay.

While this approach is not entirely unsuccessful, I think it puts many people off. Even if they may never create a big game with Quest, the mere possibility that they might have to pay at some point probably puts some people off from even making a small game. So they go and take a look at other systems, even if they may have found that they would prefer Quest’s approach if they’d just given it a chance. Who knows, maybe the other systems don’t work out for them, and they abandon the idea of making a text adventure entirely?

Making it free

This wouldn’t bother me too much if the user base for Quest was huge anyway. But writing your own text adventure games is a niche hobby, and there are a number of excellent free alternatives to Quest, most notably Inform.

So, I’ve decided to unleash Quest from the shackles of directly trying to make money from its users. I would be so much happier to have created a free system with a large number of users, than to be in charge of a system with a small following that brings in only a small fraction of my overall income.

Becoming more open

Quest 5.0 was already designed with the idea of making its innards more open. Whereas previous versions hard-coded a lot of the standard game logic, in Quest 5.0 much more of the system is written using ASLX, the same format that the games themselves are written in.

Making Quest 5.0 fully open-source seems a logical progression, tying in nicely with both the free-of-charge aspect, and in making the system more open and customisable.

So, I’m pleased to announce that Quest 5.0 is now free open source software.

It is released under the Microsoft Public License (Ms-PL), which is similar to the MIT License. This means you are free to use the source code, even in commercial closed-source projects.

You can find the Quest 5.0 project at CodePlex: http://quest.codeplex.com

Contributing

I’m not expecting an overnight miracle, but in the longer term I hope that by being open source, people will join in with this project – the aim of which is to create a powerful, robust and flexible platform for the future of text adventure games/interactive fiction, which people can write games for easily, without having to know how to program.

So I’m looking for people to join in with me – we need C# and VB.NET developers, and also people to contribute to the Core.aslx library, which is written in Quest itself. We also need people to translate Quest into other languages.

If you think you can help, please join up on the CodePlex page. I’ve also added a page of Developer Guidelines to the wiki.

The beginning

I’m really excited about the new direction for Quest. I’ve not run an open source project before, so please don’t be afraid of joining in if this is new to you too. I believe that together we can achieve more, and turn Quest 5.0 into a totally awesome system. All questions and feedback are much appreciated!

Get the code from CodePlex: http://quest.codeplex.com

Documentation is on the wiki: http://quest5.net

Quest in other languages

Quest 4.1 supports languages other than English by creating an LDF file.

I have now added a Quest Translations page to the website containing LDF files contributed by users. Currently we have translations of Quest into German and Spanish.

If you’ve created an LDF file for Quest, I’d love to hear about it! Please email me at alex@axeuk.com if you would like to submit an LDF file to the site.

Games in Spanish

I came across this page of Quest games in Spanish:
http://wiki.caad.es/Categoría:Aventuras_Quest

If you know of any other pages of foreign language games (or indeed any other websites to do with Quest), please let me know and I’ll add a link from this site.

The HTML interface in Quest 5.0

Previous versions of Quest used a “rich text” control to display text. This is quite an old Windows control, which is fine for basic formatting but ultimately lacks flexibility. Quest 5.0 replaces this with an embedded web browser, which opens up a lot of new capabilities.

At a basic level, it makes it very easy to add something I have wanted to add to Quest for a long time – hyperlinks:

By default, objects and exits in a room description are hyperlinked, so the player can look at objects and move around the game by clicking the game text. I may add the option to display a short menu of verbs instead, so that the hyperlinks could potentially be used as a complete replacement for the object panes.

Of course, some game authors may not like this, just as some authors don’t like Quest’s default panes – but you will be able to turn these off. The links are put there as part of the room description code in Core.aslx, so you can override it, and there will be an option to turn it off.

Two-way interaction with JavaScript

The most exciting thing about using HTML for the interface is that you can completely customise it to look exactly as you want. You can specify your own HTML file for the interface by including an interface tag in your ASLX file. Within that HTML file you can call JavaScript just as in any standard webpage, and that JavaScript can interact with your ASLX file.

To call JavaScript from your game code, we can use a particular call to the request command. The request command’s first parameter is the request type, and a request type of “RunScript” lets you call any JavaScript function defined in your game interface.

You can see an example of this in the YouTube example included with the Quest 5.0 samples. In the example we use the following code:

request (RunScript, "AddYouTube; ZXZWepU7zC8")

This calls the AddYouTube function defined in YouTube.js, and passes in the parameter “ZXZWepU7zC8” which is just the YouTube id of a particular video.

The AddYouTube function simply creates the relevant HTML to embed the video and adds it to document.body.innerHTML. The video then appears in the Quest window.

You can also go the other way, making a JavaScript function call a function in your ASLX file. This way, we might get rid of the hard-coded panes altogether and have a purely HTML and JavaScript solution which can be customised however you want. It also opens up the possibility of support for “point and click” games in the style of Monkey Island, because you could trigger game behaviour when the user clicks on something in the HTML interface such as part of an image.

To trigger a Quest function from JavaScript, you can call the ASLEvent function defined in WebFunctions.js. This is included in the standard HTML interface (PlayerDefault.htm, which is the default interface used by Core.aslx), and takes two parameters – the name of the function, and one parameter. You can call any Quest function that takes one string parameter.

Types in Quest 5.0

“Types” let you share sets of properties between objects. They work in the same way as Quest 4.x, except slightly more efficiently in that instead of copying the properties to the object, the object just references the underlying the type if it doesn’t have its own override for a property.

You can view all the properties of an object using the Debugger, which is accessed via the Tools menu. Properties from an inherited type are shown in grey.

Types are defined using a <type> element, and properties are defined in the same way as for an object. Objects and types can both inherit from other types using an <inherit> tag.

  <type name="food">
    <health type="int">0</health>
    <eat>It looks tasty, but you're not hungry right now.</eat>
  </type>

  <type name="fruit">
    <inherit name="food"/>
    <health>10</health>
  </type>

Default behaviour

If the ASLX defines a type called “default”, then it is applied to all objects – there is no need to specifically inherit from this type. Core.aslx uses this to define the default behaviour for objects:

  • The displayverbs and inventoryverbs properties are defaulted to give the standard buttons on the panes on the right-hand side of the Quest screen (“Look at”, “Take” and “Speak to” for the objects list, and “Look at”, “Use” and “Drop” for the inventory list)
  • All objects are droppable by default
  • The neutral gender and article (“it”) are set
  • Default container properties are set – by default the object is not a container, cannot be opened or closed, etc. This is just for convenience really – if we didn’t set these in the default type, then properties such as “isopen” would default to null instead of false, which would make the container logic messier. (An enhancement might be to add special logic so that in an expression “null=false” would be true, but I’m not sure how good an idea this would be – I’m open to feedback on this)

"Undo" support in Quest 5.0

Over the years one of the most commonly requested features for Quest has been the ability for the player to be able to type “undo”. This would have been difficult to add to previous versions of Quest, as the game state was stored in a number of different ways, but in Quest 5.0 the entire game state is stored within object properties. The location of objects is a property, global variables are properties, and so on. This makes it much easier to enable support for “undo”, and from the start Quest 5.0 has been written with this feature in mind.

Every change to a property is internally logged, which makes it easy to go backwards and undo changes on a turn-by-turn basis.

Core.aslx defines the “undo” command, which simply calls the script command “undo”. This gives the player unlimited access to the “undo” command, but you could override this in your own games to set certain conditions for undoing. Perhaps you would disable undo in certain locations by setting a certain property in the player’s parent room, or maybe you would set a limit on the number of times the command can be called. Any of this is easily achievable by creating the appropriate script around the “undo” command.

Monitoring changes to properties

If you want some script to be triggered whenever the value of property
“X” changes, you can add a “changedX” script property.

For example, when the player moves, the value of their “parent” property changes. This means you can call some script when this happens by setting a “changedparent” script property for the player. This is what Core.aslx uses to trigger the printing of the room description:

  

This calls the “OnEnterRoom” function every time the player moves into a different room.

Another way this might be useful would be if you had a “health” property for the player – you could create a “changedhealth” script which would finish the game if the health value reached zero, and maybe also set a maximum value.

Expressions in Quest 5.0

Quest 5.0 handles expressions throughout all script commands. Whereas in previous versions, things like string variables had to be denoted using special characters, in Quest 5.0 you can use expressions everywhere, just as you can in ordinary programming languages.

Of course, many games will only ever need very simple expressions, and the visual editor will mean that many game authors may never need to write one directly. But, with Quest 5.0, the full power of expressions is available everywhere if you need it.

This means no more special characters are required to denote variables and functions, and also the “if” command gets the full power of expressions – you can use nested expressions with “and” and “or”, and compare expressions directly.

Here are some example script commands containing expressions:

foreach (obj, GetObjectsInScope("Visible")) {
  msg ("You can see: " + obj.name)
}

if ((a and b) or (c and d) or (somenumber * 3 > somethingelse)) { .... }

foreach (obj, somelist + anotherlist + SomeFunctionReturningAList(blah)) {
  ....
}

MyCustomFunction(a, b, c+d)

player.parent = GetRandomRoom(GetNearbyRooms(player.parent))

someobject.take => {
  msg ("Blah blah")
  someobject.counter = someobject.counter + someotherobject.someproperty
}

Quest 5.0 also supports local variables. This means you can reuse the same simple variable name inside different functions, if you don’t need to access that value outside the function. You don’t need to declare variables in advance – you can just use them by setting them.

Global variables are now just properties of the “game” object, which means the entire state of the game is always defined entirely by object properties.

Quest 5.0 Technical Preview now available

The first Quest 5.0 Technical Preview version is now available.

This is a very early release. Most importantly, it’s limited to hand-coding games (there’s no visual editor yet), and there’s no support for games for earlier versions of Quest. These features will be added over the coming months/years (it’s going to be quite a while even before the first proper beta versions).

You can download it from the new Quest 5.0 wiki at quest5.net

If you have any feedback or questions, please drop me an email or see the forums.

Enjoy!

Verbs, Commands and Templates in Quest 5.0

Note: this information is now out of date. Please see the updated article on the Quest 5 wiki

Quest 5.0 currently follows relatively similar principles to previous versions when it comes to processing player input. I say “currently” as this may change over the course of the technical previews and beta versions, and I say “relatively” as although based on the “old” system, there is a lot more flexibility and power in the new way of doing things. In a nutshell, we retain the concepts of verbs and commands.

Here is a simple command:

<command command="test">
  msg ("Hello")
</command>

This allows the user to type “test”, and in response prints “Hello”. So far, very similar to Quest 4.

Verbs let you add “doing” words, to let players interact with objects. For example:

<verb command="eat">You cannot eat that.</verb>

This would let the player type “eat crisps”, and provide a sensible response for when the player tries to eat other objects in the game.

Templates

Core.aslx defines the behaviour for standard verbs such as “look at”, “speak to” and so on, but the actual text for the verbs themselves comes from the language library (English.aslx). To have the behaviour in one place but the verb itself in another, we have templates, which look like this in English.aslx:

<template name="eat">eat</template>
<template name="cannot_eat">You cannot eat that.</template>

A French version might look like:

<template name="eat">mangez</template>
<template name="cannot_eat">Vous ne pouvez pas manger ça.</template>

We use square brackets in Core.aslx to dynamically replace text with the template. So Core.aslx might have a line like this to define the verb, which will behave in exactly the same way as the verb in the above example:

<verb command="[eat]">[cannot_eat]</verb>

As well as using square brackets, for <command> tags you can use command templates. These let you specify multiple ways of expressing the same command, which each resolve to the same template. For example, English.aslx might define an “inventory” command like this:

<commandtemplate name="inventory">i</commandtemplate>
<commandtemplate name="inventory">inv</commandtemplate>
<commandtemplate name="inventory">inventory</commandtemplate>

That way, “i”, “inv” and “inventory” all resolve to the same template “inventory”, and Core.aslx can define the behaviour of the command like this:

<command template="inventory"> ...

Matching objects in commands

For more complicated commands, such as “put apple on table”, you can match objects within a command. Quest 5 lets you use regular expressions for this:

<commandtemplate name="put"><![CDATA[
  put (?<object1>.*) (on|in) (?<object2>.*)
]]></commandtemplate>

This may look slightly frightening at first glance, but it’s pretty simple underneath the scary syntax. The “<![CDATA[” section is there because we need to use “<” and “>” characters for the named groups in the regular expression, but we will have an invalid XML file if we don’t use a CDATA section.

For any named group with a name starting with “object”, Quest tries to match it to an object in the current visible scope (e.g. the objects in the current room, plus the objects in the inventory – I’ll be discussing scopes in more detail in a future post). You can also have named groups starting with “exit” to match available exits.

When the script for the command runs, local variables “object1” and “object2” are set to the objects specified in the command, so you can access their properties directly using “object1.parent” etc.

It may be the case that this mechanism is refined as we go through the development process, as regular expressions are probably overkill. It might be nice to simplify the named group syntax so that you can write “put #object1# (on|in) #object2#” in a similar way to Quest 4.x.

Dynamic Templates

Templates are used for all the standard output from Core.aslx. This includes the standard error messages, such as “I don’t understand your command”.

A dynamic template is a template that can call functions and read properties. This is useful for dynamic responses such as when the player tries to take an untakeable object. Usually, a response of “You can’t take it” is sufficient, but what if the object is a female character? Dynamic templates to the rescue – they are essentially functions that return a string value, for example:

<dynamictemplate name="TakeUnsuccessful">
  "You can't take " + object.article + "."
</dynamictemplate>

A female character should have their “article” property set to “her”, so this will print “You can’t take her.”

To print this from a script, call the DynamicTemplate function, which takes two parameters:

msg (DynamicTemplate("TakeUnsuccessful", object))

Note: this information is now out of date. Please see the updated article on the Quest 5 wiki

The Quest 5.0 .aslx game file

Quest 5.0 uses a new XML-based file format, and files have an .aslx extension.

Here is a simple example:

<asl version="500">
  <include ref="English.aslx"/>
  <include ref="Core.aslx"/>

  <game name="Test ASLX Game"/>

  

    <exit name="east" to="hall"/>
  </object>

  

  

    <exit name="west" to="hall"/>
  </object>

</asl>

This example defines what in previous versions of Quest would have been three rooms – a lounge, a hall and a kitchen. In Quest 5.0 these are just objects, and they themselves contain the objects “sofa” and “sink”. By nesting <object> elements, you can define further objects inside objects.

Libraries

There are two libraries included in this example:

  • Core.aslx provides the default Quest functionality, including: showing room descriptions, implementing default verbs such as “take”, “drop” and “use”, opening and closing containers, and deciding which objects are currently available to the player.
  • English.aslx provides the English text for the built-in default responses, and the names of the verbs whose behaviour is defined in Core.aslx. This means Core.aslx is language-neutral – if you wanted to make a game in German or Spanish, just translate English.aslx and plug it in to your game.

Properties

Each object’s properties are defined in the XML. In previous versions of Quest, there were only two data types – “properties” were strings, and “actions” were scripts. To make things more confusing, the properties and actions for an object were separate from the tags specified in the ASL file, so you couldn’t always read all the information about an object from a script.

In Quest 5.0, everything has been unified into properties, and there are more data types available, with the XML “type” attribute used to specify the type. If no type is specified, the string type is assumed, as with the sink’s “look” property in the above example. An exception is if there is no data in the XML tag, in which case a boolean “true” is assumed instead – as in the “start” property for the lounge.

The available types are currently:

  • string
  • double
  • int
  • boolean
  • script
  • list (of strings)
  • list (of objects)
  • object
  • exit
  • null

The type of a property can determine the behaviour of an object. In the above example, the sofa’s “take” property is a script, so that will run when the player types “take sofa”. If the “take” property is a string, the object will be taken and the string will be printed. This behaviour is defined in Core.aslx.

Properties can change type while the game is running, by simply setting them to a new value.

Additional properties

When Quest loads the game, it will set the following additional properties on objects:

  • name – string, from the “name” attribute specified for the <object> tag
  • parent – reference to the containing object, or null if the object has no parent

The player object

The player is itself an object in Quest 5.0. Here, the lounge has the property “start”. Core.aslx defines the player object, and when the game starts it will move the player into the start room by setting the player’s “parent” property to the first object that has a “start” property set to “true”.