Tasks

From ADRIFT 5 Manual Wiki
Revision as of 14:33, 21 December 2012 by Campbell (Talk | contribs) (Best Practice)

Jump to: navigation, search

Everything that happens within an ADRIFT adventure is the result of a task. Tasks do things. All tasks have a set of restrictions (conditions that must be met in order for the task to run) and a set of actions (things that will be carried out if the task runs).

There are three types of task in ADRIFT 51. The main differences between the types of task are how they are called. The task types are "General", "Specific" and "System".

Whenever you type something at the cursor in Runner, that command is "parsed". The way ADRIFT does this is by pattern matching the command against a set of known phrases. The way you define this command is to use a General task.

Specific tasks allow you to run special cases for General tasks, for example, if you wanted something different to happen when you used a particular object in a task.

System tasks are simply ones that are not triggered directly by what the user types on the command line.

Lets look at these in detail.

General Tasks

To create a new General task2, click on the Task button at the top of the screen, or right-click in a folder and select Add New > Task. This brings up the New Task form. This defaults to Specific tasks (more on these later) because that is the most common task type, so click on the General button to change the task type. This should bring up a screen like so:

NewGeneralTask.jpg


Here, you must specify the command that the player must type in order to match this command. A really simple case might just be something like:

dig

Then, whenever anyone types the command "dig" into Runner, this task will match. If a task matches the command, its restrictions will be checked, and if all restrictions are met, the task will run. So General Tasks essentially enable you to create new verbs that the parser understands.

More often than not, you might want to refer to an object or character in your task. So you might want to create a command such as:

drop the vase3

There are several problems with this. The first, is that the player might type something slightly differently in the game, but mean the same thing. This is commonly known as "guess the verb". For example, the player might be holding the vase, and type "put the vase down". Obviously this wouldn’t match the command you specified. To get around this there are three things you can do. Firstly, you can enter multiple commands. So, you could set the task up with the commands:

drop the vase
put down the vase
put the vase down

So now, we instantly have three ways we can match this command. In this example, having three commands isn’t too bad, but consider a slightly more complicated example of putting something inside something else. You could have:

put the flower in the vase
drop the flower in the vase
put the flower inside vase
drop the flower inside the vase
put flower into the vase

Etc etc. As you can see, the number of possibilities can rapidly increase the more complex the statement becomes. To get around this problem, ADRIFT understands "advanced command construction". This allows you to create multiple ways to define the command on a single line.

Advanced Command Construction

Advanced Command Construction, commonly abbreviated to ACC, allows you to define words within the command as being mandatory or optional, and to also give a choice between different words. You can create a choice between words by separating them with a forward slash "/". Words inside square brackets are mandatory, and words inside curly brackets are optional.

So going back to our earlier example, you could reduce this from three commands to two:

[drop/put down] {the} vase
put {the} vase down

ADRIFT now understands a total of six different ways of saying the same thing.

Similarly, the second example could be reduced from dozens of (36 in fact) individual command to the following:

[put/drop] {a/the} flower in{to/side} {the} vase

Wildcards

A third way of matching commands in ADRIFT is to make use of wildcards. This allows you to match anything a user types against part of your command. For example, you could create a command:

drop * in*		

(note the lack of space between in and *)

This would now match anything such as "drop the ball in the box", or "drop match into the large can of petrol".

A word of warning though; wildcards really are just that. They could end up matching on things that you really haven't considered when designing the game. For example, it would also match on "drop everything except the match into the petrol". This may end up being the exact opposite of what you intended. Therefore, it is recommended you use wildcards only when absolutely necessary.

References

In the examples above, we refer to an object "the vase". This object may have been defined as

[a] [large fragile] [vase]

Because of the articles "large" and "fragile", which may or may not be used when referring to the vase, we need each command to understand both the articles being there and also not being there. The object could also have been set up with alternative nouns (a cup could be a mug, a lamp a light, a box a carton etc), and we would have to cater for all of these4.

To make things easier, ADRIFT has the concept of References. There are several types of references. These are Objects, Characters, Directions, Number and Text. References are essentially placeholders within the task command that can match on any object, character etc. References are simply entered as a keyword between two percent symbols. So to recreate the earlier example, we would have:

[drop/put down] %object%
put %object% down

This greatly simplifies how you define the task commands, as you do not have to consider all the ways of writing object/character names. Also, if you later change the object name, you don't have to go back and change all your tasks. Simply put, General Tasks should never refer to object/character names unless absolutely necessary.

You can also have multiple references within the same command, for example:

put %object1% in{side/to} %object2%	

If you have multiple commands within the same task, each command must contain the same references. So in the first references example, both commands contain %object%. You couldn’t create another command that missed the reference out.

Also, each reference must be unique within a command. So for example, if you wish to refer to more than one object, you must use %object1% and %object2%, rather than %object% and %object%.

A full list of references that ADRIFT understands is as follows:

%object1%, %object2%, %object3%, %object4%, %object5%, %objects%, 
%character1%, %character2%, %character3%, %character4%, %character5%, %characters%, 
%direction%, %number%, %text%, %location%

You will notice the references %objects% and %characters% above. These references are even more powerful than the other references, because they can match on multiple objects. So you could refer to, for example, "the red ball and the green ball", "all except the pink ball" or "all small balls".

As soon as you create a reference in your task, all the Restriction and Action dropdowns have extra options in them to allow you to test and manipulate whatever object or character the player refers to. So in our "drop" command above we can add a restriction that the referenced object must be held by the player. If so, our task will match and we run its actions, which we could define as moving the referenced object to the same location as the player.

Scope

Scope refers to where ADRIFT will look when you refer to an item. ADRIFT 5 has three levels of scope. These are Applicable, Visible, and Seen. Visible and Seen should be pretty obvious. Applicable means it must match any task restrictions on the task creating the reference.

When you create a task that references an object or character, ADRIFT will check the scope to see which one you are referring to. So, say you create a task

eat %object% 

You may add a restriction that the referenced object must have a property 'edible'.

So, say you create two objects, "a chocolate button" and "a large red button", and give the former the property "edible". If you then type "eat button", ADRIFT will first check to find all objects that match the applicable scope. There are two buttons, but only one of them is in applicable scope (because the Eat Object task has a restriction that objects must have the "edible" property), and so ADRIFT will automatically assume you mean the chocolate button. If the chocolate button didn’t have the edible property, neither buttons will match applicable scope, and so ADRIFT will look to see which ones are visible. If only one is visible, ADRIFT will assume that’s the button you are referring to. If neither are visible, ADRIFT will check to see which ones you have seen before. So if you have come across the red button in the game but not the chocolate button ADRIFT will assume you are referring to the red button. If, after all three levels of scope have been checked and there are still multiple possibilities, ADRIFT will prompt for disambiguation.


1 There are actually two types of tasks in ADRIFT 4. Those with # symbols at the start to prevent the user typing the command (i.e. System tasks in ADRIFT 5), and those without (i.e. General tasks in ADRIFT 5).

2 General Tasks are the equivalent of normal tasks in ADRIFT 4.

3 General tasks should not refer to individual objects unless absolutely necessary. See Best Practice section.

4 For those of you familiar with ADRIFT 4, this was one of the problems with the parser, because the task command may not cover all the possibilities of the built-in parser.

Message to display on completion

In the bottom half of the Description page is a text box that contains the message to be displayed if this task is matched to the user input and passes all of its restrictions.

As well as displaying text (which can include functions) a text box can also control the display of images and the playing of sounds at the same time as the text is output.

A text box can also use Alternate Descriptions to change the text that is output in different circumstances.

Task is Repeatable

At the bottom left corner of the task is a tickbox called "Task is Repeatable".

This almost always needs to be left ticked, the only time you would not tick it is if you have a task which is part of the story and which must only be able to execute its actions once. If this box is not ticked then, after this task has executed the first time, it will no longer take part in the matching of any future command. It will be as if this task no longer exists.

Note that you DONT need to do this to prevent the players score being incremented more than once by the same task, as ADRIFT contains special logic that prevents a particular task from changing the %score% variable more than once.

Specific Tasks

So say you want to create a task "drop the vase", and instead of the default action of moving the vase from being held by the player to being in the same location as the player, you wanted something specific to happen such as the vase breaking. The general ‘drop’ command we defined above will run the same on any object we refer to in the game unless restrictions are put on the task. A simple way of creating this special case is to create a Specific Task.

Specific Tasks allow you to override the default behaviour of any General Task. You should find that most tasks you create using ADRIFT are Specific Tasks. That's because most things that happen throughout the game are special cases of default responses.

In the following screenshot we can see an example of overriding the drop command.

DropTape.jpg

To override a General command, select it from the dropdown list. This will change the displayed command on the line underneath the dropdown. This is a 'sample' command that could be typed. In fact, as we have discussed earlier, the drop task has been defined with several different ways of saying the same thing.

  • Ensure that every general and specific task has a unique Task Name, otherwise the drop-down list will show two identical entries and you wont be able to tell which one is the one that you want.

Any references defined in the General Task are displayed in the command bar with a hyperlink. By clicking on the hyperlink, you can pick the specific object you want to create the special case for. In the case above, I didn't want the tape to just move back to the room, and instead it burns up and disappears. In the actions for this task I move the tape to 'Hidden'.

Because Specific Tasks only override General tasks that run, you don't need to repeat the restrictions of the General task. I.e. because the General drop task already checks that the player is holding the object to begin with, you don't need to add that check to the specific task. You would add additional restrictions if you only wanted the Specific task to run under special circumstances.

You can also make a specific task which is specific to a particular room or circumstances, but which is not specific to a particular object. Just leave the command bar hyperlink set to object, character or direction instead of changing it to a specific object, then use the Restrictions of the specific task to determine when it should override the general task.

Overriding

There are three different ways that a Specific task can override a General task. These are

  • Run before – This means the Specific task will run before the general task (but after its restrictions are checked). If you select this option you can select whether the parent/general task message is displayed, and also whether the parent/general actions are run.
  • Override – This means the Specific task completely overrides the General task. Neither the General message will be displayed, nor the actions run, although its restrictions must still pass.
  • Run after – This means the Specific task will run after the General task completes. The General message will be output and actions run, then the Specific actions will be run and message output (if either are defined).

In the example above, the specific case for dropping the tape runs after General drop command. So when the player types "drop tape", the default message for dropping the tape will be displayed, e.g. "You drop the tape." and the tape will move from the player’s hands to the room the player is in. Then the above message will be output and the tape will disappear.

Note that the restrictions on the general task must all pass before any of the specific tasks can override it.

If a general task in the standard library contains a restriction that prevents your specific task from running when it should, then you will need to create a new general task that overrides it.

The commands for this task must be identical to the original. You can make an exact copy of it by right clicking and selecting "copy", then right click on the folder you want it in and select "paste". Open the new task and rename it to something appropriate, then go to the advanced tab and ensure it has a higher priority (lower number) than the original. Remove the unwanted restriction and add new restrictions so that this task only overrides the original when it should.

Best Practice

So do you really need to create a General Task plus a Specific Task every time you want to do something new with a specific object? Well, yes. The reason for doing this is so if a verb is understood in one part of the adventure, it will be understood throughout.

Consider a trampoline. You might think to add a general task "jump on {the} trampoline". Then when the player types "jump on trampoline" your task runs. But what if they came across a box in the game. They might try "jump on box". And because the jump verb worked earlier, they would expect it to work here. But because you only created the general verb for the trampoline, Runner would respond with a "do not understand" message.

So the verb should be set up with a general task "jump on %object%". You can then create a Specfic task for the trampoline. The general task (if not overridden by a specific task) could then give a default response for jumping on objects you don't want jumped on, for example "Jumping on %object%.Name isn't a very good idea."

Parent/Child buttons

To the right hand side of the task name are two buttons. These are the Parent and Child buttons. Every Specific task is the child of either a General task, or another Specific task. Clicking on the first button (Edit Parent task) will open up the task the current task is overriding.

Clicking on the second button (Edit Child task) will display a list of all tasks that override the current General (or Specific) task. Selecting one of these will open up the child task.

If the buttons are greyed out, this means the task does not override or is not overridden by another task.

System Tasks

System Tasks are just the same as any other tasks except they are not triggered directly by what the player types at the command line. In most cases, they are just called by other task actions, or by events. However, there are other ways of triggering them also. The options for triggering a System task are:

  • Only if called by event/task - This task will never run unless explicitly called.
  • Immediately - This task will run at the start of the game.
  • Player enters location - This task will run when the player enters a particular location.

The first option here is the default. Basically this means that the task is never triggered automatically. If you select one of the other options, you can still call the task from an event or other task.

The second option is useful for initialising things at the start of the game. For example, you may want to set variables to random values, place characters randomly within a location group, or ask the player to enter their name, gender and age.

The third option is useful, because it triggers whenever the player enters a particular location. You could override the 'Player Movement' task, but if the location had several entrances then you would need to override each entrance. This task ignores which entrance you came in, and will trigger as soon as you arrive at the specified location.

System tasks dont use references. If you want to call a task and pass references to it as parameters, then create a general task but use "#" as the first character of the command. Then just list the references it needs to use for its restrictions or actions.

Restrictions and Actions

The restrictions page of a task contains a Restrictions list which determines whether a task will be executed. When the command template on a general task matches the user input, or an attempt is made to execute a system task, Adrift checks these restrictions before deciding to execute the task. If the boolean relation of the Restrictions in this list evaluates to true, then the task executes:

  • The "Message to display on completion" is shown.
  • The Actions listed on the Actions page are executed.

If the boolean relation evaluates to false then the first restriction test that failed will display its failure message to the player.

Hints

Hints are not yet functional in ADRIFT 5.

Advanced

On the Advanced tab are a series of settings that allow you to tweek how the task behaves and how it interacts with other tasks that also match the player input.

AdvancedMode.jpg The ADRIFT developer must be in Advanced mode for this tab-page to be available.

TaskAdvanced.jpg

The task priority determines which task Adrift should execute if more than one matches the players' input. The one with the lowest number in this field has the highest priority and will be executed first. The tasks in the Standard Library always have very large priority numbers, while the tasks that you create will initially be numbered in order of creation starting at 1. This means that any task you create will execute before any Standard Library task by default. You will only need to alter this field if you have two tasks which are both able to match the same player input and pass their restrictions at the same time, and you wish to change the order in which they are executed.

The "Auto-fill priority" is only available on General Tasks and is responsible for the auto-completion feature whereby the player only has to type part of a command or object name and the rest of the word will be filled in automatically. Normally a player will expect common commands such as "north" or "examine" to be chosen by this feature, but if you create a new command such as "exit" or "nobble" then you may need to change the value in this field to stop them being selected.

Setting the auto-fill priority to zero will prevent this general task's commands from ever being displayed by the auto-fill.

If "Prevent this task from being inherited" is selected on a general task then it will not be possible to create a specific task for it.

The default behaviour is for tasks that pass restrictions to override higher priority tasks that do not, even when the failing higher priority task has output. To change this behaviour, you need to check the "This task can be overridden by other task restriction failures" checkbox on the lower priority task.

Next is a drop-down list of 4 options that controls what happens after a high priority task executes and there are lower priority tasks that also match.

TaskControl.jpg

  • Do not continue matching if this one matches.
    • No lower priority task will be executed.
  • Continue to execute matching tasks with lower priority if this task matches but doesn't pass
    • If the Restrictions list for this task failed then execute next task in priority order.
    • If this task passed restrictions then dont try any other tasks
  • Continue to execute matching tasks with lower priority if there is no text output from this task.
    • If task passed but its text box was blank then execute next task.
    • If task failed restrictions but the restriction that failed did not contain any text, then execute next task.
    • If either the main text box or a restriction output some text then dont continue.
  • Always continue to execute matching tasks with lower priority.
    • The next task in priority order is executed following this one, regardless of whether it passed or failed.


The drop-down list "Display completion message before/after executing actions" controls the order in which the task executes.

  • Before: The contents of the tasks' text box is displayed first, then the Actions of the Actions tab are executed.
  • After: The actions are executed first and then the text is displayed.

This is only important if:

  • An action alters a variable which is then displayed as part of the text output.
  • An action alters something which is used to determine if a restriction passes on an alternate description in the text box.

Finally, the text box at the bottom allows a special message to be displayed, instead of the usual restriction failure message, if the player entered "All" instead of a specific object in the command.

An Example

In Jacaranda Jim, I needed to create a "chop" verb. So, as with any new verb, this needs to be set up as a General Task. The task is defined with a very simple command:

ChopObjectWithObject.jpg

The default response for chopping an object with another object is simply an error, saying you can’t chop the first object with the second one. Because, for example, if the player tries to chop a door with a torch, I need to tell them that's not a good idea, but they still need to know that chop is a valid action. For an explanation of the functions used in this response, see the Functions section.

I added a few restrictions to the task as follows:

ChopRestrictions.jpg

Most General tasks will have restrictions that any objects referred to must exist, that they have been seen by the player (because if they haven't, they may as well not exist as far as the player is concerned), and that the object doing the chopping (Referenced Object 2) must be held. I also need to ensure that the object the player is trying to chop is visible, otherwise I give an error saying "You can't see that."

There are no actions for the default 'chop' command, because it is generic and I don't want anything to happen when the user tries it on an incorrect object.

Now, if the player tries to chop something with an axe, I don't want a generic "You can't do that" sort of response. So I can create a Specific task for the axe by selecting the axe from the second object hyperlink, like so:

ChopObjectWithAxe.jpg

I can then give a sensible response to this action when the player tries chopping random objects with the axe. This task is a sort of cross between a General task and a Specific one, because one reference has been left general, and one has been specified.

Clearly, many objects could be changed drastically with an action such as this, so the real purpose of this task is to prevent us having to create a response for every single object the player tries to chop. There are no restrictions (because it obviously passed all the General task restrictions) and no actions (because it is again a generic response) on this task.

There will be certain objects that when chopped, you want to give a specific response to, or do actions. In my case, I want something specific to happen when the player tries to chop through a door. So I create a new Specific task which overrides the General/Specific task defined above, like so:

ChopDoorWithAxe.jpg

In the actions for this task, I increase the score. I also have a restriction on the movement from one of the rooms that depends on this task being completed.