Table of Contents

Before you start…

…you should skim through the Adventure Script Player short manual. You probably should also try to play an example game, if you haven’t played any already.

The Basics

Learning Adventure Script isn’t hard and doesn’t require any knowledge whatsoever. In fact Adventure Script was designed to be easy. Believing is always the first step so repeat after me:

It’s easy.
I’m 100% capable of learning it.
I can do it.

Introducing Mary and Lucy

Let’s start from somewhere, look at the following line:

say "Mary looked at Lucy"

You can probably deduce that it will display the quoted text to the player. Now look at this line:

say mary "Lucy you monster! You seduced my mother's
sister's fifth child which is also somehow my brother's ex-wife!"

This time we specified who will say the quoted text – Mary. As the first example had no speaker it was treated as narration. But who is Mary? We need to introduce her:

object mary "Mary the Wicked"

Let’s also introduce Lucy:

object lucy "Lucy the Spiteful"

And let’s put them into a room:

location room "Palace living room"
object mary "Mary the Wicked"
object lucy "Lucy the Spiteful"

That’s a lot of things to explain but they all should be quite intuitive.

Objects

Let take a look at Mary. object informs that we are introducing a… well… object? Like a knife, unicorn anything else you can think off. Then comes the object’s identifier, in Mary’s case mary. Think of it as of a computer file’s name. It will be used to refer to Mary – like we did by writing say mary in one of the first examples. After the object’s identifier comes the object’s name written in quotes. This is how Mary will be displayed to the person playing the game.

Locations

That was easy, now what’s a location? A location is a well… you know… a location. In life locations usually consist of stuff (objects) in them. The same here! Easy right? Marvelous! Let’s move on. Locations just like objects have identifiers and names. How do we specify which objects are in a which locations? That’s where indentation comes in. There’s a tabulator before Mary and Lucy informing that they are in fact in the living room. You can make tabulators with the Tab key on your keyboard. Keep in mind that a tabulator is not the same thing as multiple Space! (but it looks the same)

Skipping stuff

Let’s take a quick look at the next example:

location cave
object "angry dwarf"
location "Quite magical Forest"
object elf
object knife "rusty knife"

First of all the dwarf is in a cave, the elf is in a forest and the knife is in no specific location whatsoever. But look, the object and location declarations look different! The cave doesn’t have a name and the dwarf doesn’t have a identifier! How can that be! Well, we can skip one of these elements, but not both. When we skip the name it becomes the same as the identifier. When we skip the identifier we can not refer to this location (or object) later on.

Our first game

Let’s go back to Lucy and Mary and write something that actually does something. To do so we need do learn how to write events. First of all we need an on create event that fires when the games starts. Let’s keep it simple:

on create
goto room
location room "Palace living room"
object mary "Mary the Wicked"
object lucy "Lucy the Spiteful"

And look! It’s a actually working game! You can see it in action here! If you feel courageous enough you can also open it in the editor. We will get to how to use it in the next chapter.

Making stuff do things

Let’s learn about events. Without them the game can’t really do anything. Every event starts with an on and then is followed by the event name. There’s lot of different events but for now let’s just introduce two:

See them in action in he following example:

on create
goto room
location room "Palace living room"
on prompt
say "Two angry women are arguing here. It's awfully loud."
object mary "Mary the Wicked"
on prompt
say mary "I'm busy shouting at Lucy, go away"
on use
say "You stab Mary in the heart. She dies. Lucy shuts up. She looks quite content."
hide mary
object lucy "Lucy the Spiteful"
on prompt
say lucy "Wanna taste ma fists? No? Then stop looking at me!"
on use
say "You try to stab Lucy. She grabs your hand in mid air."
say lucy "Oh, I will enjoy this..."
say "You get slowly punched to death."
goto end
location end "Game Over"
on prompt
say "You died. Welp, that's what you get for killing people."

You can (and should) play this game or open it in the editor.

So, as you can see, an event consists of actions in the same way that a location consists of objects. That means that actions need to be indented (with tabulators) to be included in an event. But what are these “actions”? For know let’s introduce some of them (listed below).

Basic actions

Actions are executed one-by-one, in the order they where written. goto is a special action as it ends the event after being executed. What does that mean? Well, let’s consult an example:

on create
goto room
say "Don't mess with Lucy!!"
location room "Palace living room"
on prompt say "Two angry women are arguing here. It's awfully loud."

“Don’t mess with Lucy!!” will never be displayed as the goto room action terminates the on create event. I hope that’s clear.

Skipping stuff

We’ve done one more thing in the last example. Look at the living room’s on prompt event. It looks different! If an event has only one action you can write it the same line without an indent! This makes the games much more compact and easier to read.

Commenting stuff

Comments are a useful thing – they are just portions of text that have no affect on the game. They are added to leave some information for the person reading the game’s code. Like side-notes on a draft of a book. Read the comments in the following example to understand how to write them:

# single line comments
 
#= and mutliple line comments
aka "block comments" =#
 
# comments can ignore
# indentation rules
# as they are ignored
 
object dwarf # comments can also end a line...
object #= ...and be inside a line =# dwarf

I will use comments to explain or highlight things directly inside the examples.

Conditioning stuff

You probably noticed that after Mary died the living’s room prompt still said “Two angry women are arguing here. It’s awfully loud.”. Let’s fix it:

on create goto room # a one-action event written in a single line
location room "Palace living room"
on prompt
if mary.hidden # this is new!
say "It got quiet. Mary is in a pool of blood on the floor. Lucy's looks at you cautiously"
else
say "Two angry women are arguing here. It's awfully loud."
object mary "Mary the Wicked"
on prompt say mary "I'm busy shouting at Lucy, go away"
on use # this event has two actions so it can't be written in a single line
say "You stab Mary in the heart. She dies. Lucy shuts up. She looks quite content."
hide mary
object lucy "Lucy the Spiteful"
on prompt say lucy "Wanna taste ma fists? No? Then stop looking at me!"
on use
say "You try to stab Lucy. She grabs your hand in mid air."
say lucy "Oh, I will enjoy this..."
say "You get slowly punched to death."
goto end
location end "Game Over"
on prompt say "You died. Welp, that's what you get for killing people."

You can play this game or open it in the editor.

Two things have changed. First, the one-action events where made compact. Second, the living’s room on prompt event changed, and look! A condition! Conditions allow to selectively preform actions, choosing them with regard to some kind of information (in our example the visibility of Mary). So how does one write a condition?

Conditions

First comes an if, then an expression (which can be quite complex – we will get to that later on). In our example the expression is equal to mary.hidden. After the if and the expression we write indented actions that are to be executed only if the expression is true. Actions belong to conditions, just like actions belong to events or objects belong to locations. After we finish adding actions to the condition we can (but not have to) write else followed by another portion of indented actions. These actions will be executed only if the expression was false. In other words:

if expression
# to be executed only when 'expression' is true
action
action
...
# the condition can end here or we can add 'else' as shown below
else
# to be executed only when 'expression' is false
action
action
...

Skipping stuff

Again we can make things more compact. If a condition has only one action we can write it in a single line:

if mary.hidden say "It got quiet. Mary's in a pool of blood on the floor and Lucy's looks at you cautiously"
else say "Two angry women are arguing here. It's awfully loud."

or even (but it’s ugly so don’t do it too much):

if mary.hidden say "It got quiet. Mary's in a pool of blood on the floor and Lucy's looks at you cautiously" else say "Two angry women are arguing here. It's awfully loud."

side-note: because of a bug shortened conditions get colored incorrectly. In the examples above the say actions are white when they should be yellow. Unfortunately no good solution was found to resolve this issue.

Referring to stuff

But there’s still one thing unexplained. What does mary.hidden mean? We got to the hard part – mary.hidden is a variable. Remember how I told you that object and location identifiers are like file names? Well, there’s more to that.

Containers

In fact objects, locations and even events are more like folders. We will call them containers as they contain things. Let’s continue the file and folder analogy:

Variables

So what is a variable? If folders were an analogy to containers and files were an analogy to values then by saying “a variable” we mean a folder or a file. It’s anything in the game that we can somehow reference (refer to). So how do we refer to things? The easiest (but highly unpractical) way is to use full paths – for example the hidden value inside mary has a full path equal to root.room.mary.hidden (it’s just like a file path, but with dots instead of slashes). Paths can be shortened depending from the context they are used in. That may sound a bit cryptic but it’s really simple and intuitive. When inside the living room mary refers to Mary The Wicked. There could be other variables named mary somewhere else and to reference them we would need to use appropriate paths.

Contexts

To understand better what a context is take a look at the following example:

object knife
location cave
object knife
location meadow
object dwarf

Imagine that with each level of indentation you climb a tower. While on this tower you can look only directly below. When asked for an item you find the closest item matching the description in the range of your sight. In the example above while on the ground you see a knife, and two towers – the meadow and the cave. As you can’t look up, you don’t know whats on top of them. Once you climb a tower, let’s say the meadow tower, you find a dwarf. You can also look directly below to see the knife on the ground and the base of the cave tower, but you can’t look sideways to see what’s on top of it. If you climb the cave tower, you will see two knifes – one from the tower and one on the ground. But the knife on the tower is closer, so you prefer it. Also, while on the cave tower you can’t see the dwarf. He’s on the neighboring tower and you can’t look sideways.

To summarize let’s list all the different contexts in the example above and show how to refer to each variable from inside each of them:

The root context:

Full path Shortest path
root.knife knife
root.cave cave
root.cave.knife cave.knife
root.meadow meadow
root.meadow.dwarf meadow.dwarf

The cave context:

Full path Shortest path
root.knife root.knife
root.cave cave
root.cave.knife knife
root.meadow meadow
root.meadow.dwarf meadow.dwarf

The meadow context:

Full path Shortest path
root.knife knife
root.cave cave
root.cave.knife cave.knife
root.meadow meadow
root.meadow.dwarf dwarf

Skipping stuff

Yes, it’s this paragraph once again. The thing is that full paths can skip the root and start from a dot character. In other words .meadow.dwarf is a abbreviation of root.meadow.dwarf (but doesn’t have to be same thing as meadow.dwarf – there could be a meadow in the current context different from the meadow in the root context).

Combining stuff

Let’s take a break from variables and do something fun. It’s time to put the inventory into use. As it has been already said, objects can be put in and out the inventory using the equip and unequip actions. It has also been said in the Adventure Script Player manual that objects inside the inventory can be combined with each other and with objects inside the current location. So how do define what should happen when the players decides to combine something? Take a look at the following example game:

on create goto room
 
# 'equipped' is a object modifier. We will talk about them some time later.
# Thanks to it the knife will be in the inventory when the game starts
equipped object knife "Knife"
on prompt say "A blunt knife. Still good for stabbing"
on use
say "You stab yourself. You die. What have you been thinking?"
goto end
on combine bow
say "You stab a bow. It's stupid. The bow breaks."
unequip bow
on combine room.mary # notice that we can not simply write 'mary' -- we are not in the 'room' location
say "You stab Mary in the heart. She dies. Lucy shuts up. She looks quite content."
hide room.mary
on combine room.lucy
say "You try to stab Lucy. She grabs your hand in mid air."
say room.lucy "Oh, I will enjoy this..."
say "You get slowly punched to death."
goto end
# 'any' matches any object.
on combine any say "Unfortunately you can't stab that"
object bow "Toy bow"
on prompt say "Looks dangerous. It even came with a toy arrow."
 
location room "Palace living room"
on prompt
if mary.hidden
say "It got quite. Mary is in a pool of blood on the floor. Lucy's looks at you cautiously"
else say "Two angry women are arguing here. It's awfully loud."
object "Weapon stand"
on prompt say "There are some fine weapon here!"
on combine bow say "It won't do much damage to it"
on use
# [object].equipped is true if an object is inside the inventory
if bow.equipped say "Only toy swords left."
else
say "The bow looks useful."
equip bow
 
object mary "Mary the Wicked"
on prompt say mary "I'm busy shouting at Lucy, go away"
on use
say mary "You want to USE me? Right."
say "You get punched in the face."
on combine bow
say mary "Yes, I'm terrified. Show me that arrow, will you?"
say "You find yourself with an arrow in your eye. You die"
goto end
object lucy "Lucy the Spiteful"
on prompt say lucy "Wanna taste ma fists? No? Then stop looking at me!"
on use
say lucy "Of course you can use me!"
say "You get punched in the face."
say lucy "That was sarcasm."
say "You get punched in the face."
on combine bow
say mary "Is that a toy bow? You want to HURT me with that?"
say "You get disarmed and Mary breaks the bow in half."
unequip bow
location end "Game Over"
on prompt say "You died. Welp, that's what you get for messing with insane women."

You can play this game or open it in the editor.

The on combine event

As you probably noticed the on combine event is a bit different from the events we’ve been using so far. After the usual on and the event’s name comes a third element – the target object. An on combine event is executed when the player combines the target object with the object that the event is defined in. It is also executed when the reversed situation occurs – an on combine bow event inside the knife could be rewritten as an on combine knife inside the bow and would still do the same thing.

Wildcard targets

A wildcard target is a special target that matches any object. We used it in the example above in the knife object. When two objects are combined and they don’t have an appropriate on combine event, then a event with a wildcard target is executed instead (if one is defined). To create an on combine event with a wildcard target we simply write any instead of the target object.

What if both objects have an on combine event with a wildcard target? When combining two objects the second one always have priority. Consider the player used the bow on the knife and they both have a event with a wildcard target. The knife’s on combine any event will be executed (but only if there was no on combine knife inside the bow and no on combine bow inside the knife). If it’s still unclear try playing the following example and combine the bow with the knife and then the knife with the bow (in the inventory).

on create goto test
equipped object knife
on combine any say "Knife wildcard"
equipped object bow
on combine any say "Bow wildcard"
location test

Like always, you can also open this example it the editor.

Talking with stuff

One more thing left in this chapter – writing dialogs. I won’t hide that creating complex dialog trees is quite tricky, as it requires understanding what trees are. That’s why for now I will only show you how to make really simple dialogs. Let’s start with a example:

on create goto meadow
 
object axe "Dwarf's Axe"
on prompt say "A beautiful example of dwarf craftsmanship."
 
location meadow "Meadow"
on prompt say "A boundless meadow, covered with a variety of spring flowers."
object dwarf "Sad looking dwarf"
on prompt say "A beardless, clean and cinnamon smelling dwarf."
on use goto foo
on combine axe
say dwarf "Oh my..."
say "You take a swing but the handle breaks and the blade falls on your head. You die."
goto end
dialog foo
on prompt say dwarf "Yes, stranger?"
option "Who are you?"
say dwarf "I am a dwarf!"
option "Why are you on a meadow?"
say dwarf "I love grass, I hate caves. I'm quite an outcast."
option axegive "Give me your axe"
say dwarf "It sounds reasonable. Here take it."
hide axegive
equip axe
option "I have to go"
say dwarf "See you later!"
goback
 
location end "Game over"
on prompt say "You died."

You can play this game or open it in the editor.

Two new elements appeared in this example: dialogs and contained in them options.

Dialogs

Dialogs are basically containers for options, but they can also contain events. When in a dialog, options are displayed to the player in a similar way that objects are displayed in a location.

To create a dialog write dialog followed by an identifier. Then add appropriately indented events and options. For now let’s consider only the on prompt event, executed each time the dialog is displayed to the player.

To enter a dialog use the goto action the same way you would enter a location. To exit a dialog use the goback action (described below) or enter a location with the goto action.

In the example above the dialog was placed inside an object (the dwarf). Notice that when the player is inside the dialog the header says “Dialog with Sad looking dwarf”. We can also place the dialog inside a location or in the root context but then the header will simply say “Dialog”.

Options

Options are something between events and objects. Just like objects they have identifiers and names but inside they contain actions like events. These actions are executed when the player clicks on a option inside a dialog.

Options can be hidden and shown using the hide and show actions just like objects. A hidden option will not be displayed to the player.

Inside options a special goback action is available. Use it to exit the current dialog. Keep in mind that that just like goto it terminates the current option after being executed.

To create an option write option followed by an identifier and a name. Then add any amount of appropriately indented actions.

A short interlude…

…is recommended for reading the Adventure Script Editor manual. You already know enough to create and modify simple games. After reading it try playing with examples in this document. Add some objects, write some events – it will help you understand things a hundred times faster. If you make a mistake the editor will display an error, which for now will probably seem like cryptic gibberish. Don’t worry, we will get to them some time later. For now all I have for you is a small tip – if you see enigmatic baloney like this:

stack trace:
[5] /runtime/game.as:rret:57
[4] /game/main.as:bow:5
[3] /runtime/runtime.as:safecall:87
[2] /runtime/game.as:rrot:117
[1] /game/main.as:root:4

then it means that you made a mistake somewhere near line 5 of the /game/main.as file it the bow object. Always look at the topmost line of such messages that has a file from your project in it. The number on it’s end will be the number of the line that caused the error to occur.

One more thing before we move further: there is an useful print command that can be used to print any variable / value / expression in the editor’s event log. Just like this.

Events

This chapter will focus on describing events in more detail. The last section contains a reference of all available events. Some sections of this chapter describe advanced features of Adventure Script. Beginners should skip them.

Object events

All object events have exactly the same functionality: when defined in an object they are displayed to the player in the object screen and executed when the player clicks on them. What’s more object events are user-defined, meaning you can create any object event you want, like stab or pickpocket.

There are three object events predefined inside the dafults.as file that is included to each new project. Let’s took a look at them right now:

defineevent "use" "use" "fa-gears"
defineevent "talk" "talk to" "fa-comments"
defineevent "pickup" "pick up" "receive"

An object event is added by writing defineevent followed by the event name in quotes. Then come three optional parameters also written in quotes: the display name, icon and background color. For example to define an on stab event with red background and dagger icon we would write:

defineevent "stab" "Backstab" "curved-dagger" "tomato"
on create goto Rome
location Rome
object Cesar
on stab say "Ouch!"

You can play this game or open it in the editor.

Object events need to be introduced before they are used for the first time. In the example above writing the defineevent after the Cesar object would result in the following error:

RUNTIME_ERROR: unknown event stab

System events

System events are executed on various occasions and unlike object events are hard-coded (no new system events can be added). Different types of these events can be defined inside different elements of the game. For example the on create event can only be defined in the root namespace (context), while the on prompt event can be defined in locations, objects and dialogs. A full list of different events with their desccirpion can be found in the event reference.

Template events

This section describes a feature that may prove to be harder to understand. Feel free to skip it and come back to it later.

A template event is an event defined outside of its normal context. For example an on equip event defined inside a location. All elements inside a context with a template event will inherit this event unless they define their own event of the same type overriding the template event. The following example demonstrates an on use template event:

on create goto meadow
on use say "Hello from the root context!" # template event
 
location meadow
on prompt say "Trying using the dwarf and the elf."
on use say "Hello from the meadow context!" # template event,
# overrides the template event in the root context
object dwarf
on prompt say "Use me."
on use say "Hello from the dwarf context!" # normal event,
# overrides the template event in the meadow context
object elf
on prompt say "Use me."
# no 'on use' event, the template event in the meadow context will be inherited
object "passage to the cave"
on trigger goto cave
 
location cave
on prompt say "Trying using the knife and the bow."
object knife
on prompt say "Use me." # normal event,
# overrides the template event in the root context
on use say "Hello from the knife context!"
object bow
on prompt say "Use me."
# no 'on use' event, the template event in the root context will be inherited
object "passage to the meadow"
on trigger goto meadow

You can play this game or open it in the editor.

Predefined template events

The defaults.as file comes with the following template events predefined:

Feel free to change them to further customize your games.

Limitations

Not all events can have template events. Consult the event reference for further information on this matter.

Accessing the caller context

A template event’s context it equal to the context it has been defined in (just like normal events). This makes it impossible to determine in which context the event was called (executed) in – for example a template on equip event has been called. But what object was equipped?

To solve this issue a special variable context was made accessible inside all events. This variable points to the context that the event was called on. For example the on equip template event inside defaults.as has the following definition:

on equip say "Equipped \name{$context}."

Inside non-template events context is equal to parent.

Canceling events

All events can be canceled. Canceling an event causes it to immediately terminate and usually causes some special effect. These effects have been described in the event reference.

To cancel an event simply write return true in it’s body. The following example demonstrates cancelling an on inventory event:

on create goto test
location test
on prompt say "Try opening the inventory."
on inventory
say "This can not be done!"
return true

You can play this game or open it in the editor.

To terminate an event without triggering the special effect use return false or simply return.

Disabling events

This section describes an advanced feature of Adventure Script.

Events can be disabled. Disabled events are ignored as if they were not defined. Following functions (actions) are used to disable an event:

And similarly to enable an disabled event:

Container should be a namespace / location / object / dialog containing the event to be disabled. The event name needs to be written in quotes. Writing disable container "combine" will disable all combine events inside the chosen container. To disable a specific combine event the target object has to be specified. To disable the wildcard combine event .rt.game.wildcardobject has to be used as the target object. An event can be also disabled by adding the disabled modifier to it’s declaration.

An example demonstrating how disabling and enabling events works is shown below.

on create goto test
on trigger say "Hello from root!"
location test "disable demo"
on prompt say "
.ontrigger.disabled = $.ontrigger.disabled\br
.test.ontrigger.disabled = $.test.ontrigger.disabled\br
.test.run.ontrigger.disabled = $.test.run.ontrigger.disabled\br
"
on trigger say "Hello from test!"
object run
on trigger say "Hello from run!"
on prompt
say "All trigger events disabled"
goto test
object 'disable root "trigger"'
on trigger disable root "trigger"
object 'disable test "trigger"'
on trigger disable test "trigger"
object 'disable run "trigger"'
on trigger disable run "trigger"
object 'enable root "trigger"'
on trigger enable root "trigger"
object 'enable test "trigger"'
on trigger enable test "trigger"
object 'enable run "trigger"'
on trigger enable run "trigger"

You can play this game or open it in the editor.

Manually calling events

This section describes an advanced feature of Adventure Script.

Events can be called (executed) manually using the do function with a syntax similar to the enable / disable functions:

Container should be a namespace / location / object / dialog containing the event to be called. The event name needs to written in quotes. If the container does not have the specified event, then a appropriate template event is executed (if present).

If no event or template event is found the function returns none. In other cases it returns the value returned by the event it executed.

Event reference

This section may make use of concepts not yet explained, like namespaces or string interpolation. For now ignore fragments you don’t understand and come back to them later.

Complete Adventure Script event reference:

on create

This event is executed once the game start. Is should set the initial location of the game. Can not be canceled.

Can be defined in:

on prompt

Executed upon displaying a location / object / dialog screen. Used primary to set the prompt. Canceling this event has no special effect.

Can be defined in:

on enter

In locations this event is executed when the player enters the location this event is defined in. The player’s location needs to change for this event to be executed – using goto to the current location will not execute this event. Canceling this event prevents the location change – the players stays in the location he was trying to leave.

In dialogs this event is executed when the player changes or moves down in a dialog sub-tree. This is explained in more detail in the dialogs chapter. Canceling this event prevents the dialog change.

Can be defined in:

on leave

In locations this event is executed when the player leaves the location this event is defined in. The player’s location needs to change for this event to be executed – using goto to the current location will not execute this event. Canceling this event prevents the location change – the players stays in the location he was trying to leave.

In dialogs this event is executed when the player changes or moves up in a dialog sub-tree. This is explained in more detail in the dialogs chapter. Canceling this event prevents the dialog change.

Can be defined in:

on inventory

Executed before the inventory opens. Used primary to set the inventory prompt. Canceling this event will prevent the inventory from opening. This allows restricting the player access to the inventory when needed. The following on inventory event is predefined in the defaults.as file:

on inventory say "Inventory contents"

Can be defined in:

on trigger

Executed when the player selects an object from the location screen, just before the execution of the on prompt event. This event causes an automatic return to the location screen upon finish – the object screen doesn’t get displayed and the on prompt event doesn’t get executed. Canceling this event resumes the normal flow – the object screen gets displayed normally after executing the on prompt event.

Simple example:

on create goto Meadow
location Meadow
on prompt say "Dwarfs on a meadow!"
object "Normal dwarf"
on prompt say "This is the normal dwarf"
object "Trigger dwarf"
on trigger say "This is the trigger dwarf"

You can play this game or open it in the editor.

Can be defined in:

on equip

This event is executed when an object is added to the inventory. Canceling this event causes the object to not be added to the inventory. The following on equip event is predefined in the defaults.as file:

on equip say "Equipped \name{$context}."

Can be defined in:

on unequip

This event is executed when an object is removed from the inventory. Canceling this event causes the object to not be removed from the inventory. The following on unequip event is predefined in the defaults.as file:

on unequip say "Unequipped \name{$context}."

Can be defined in:

on show

This event is executed when an object is set visible via the show action. This event will not be executed if the object was already visible. Canceling this event causes the object’s visibility state to stay unchanged.

on hide

This event is executed when an object is hidden via the hide action. This event will not be executed if the object was already hidden. Canceling this event causes the object’s visibility state to stay unchanged.

on combine

Combine events are executed when two objects are combined by the player. They’ve been described in more detail in the previous chapter. Canceling these event has no special effect. The following wildcard on combine event is predefined in the defaults.as file:

on combine any say "This can not be done."

Combine events also expose a special target variable in their body allowing referring to the target object when the wildcard target is used. Short demonstration of this feature:

on create goto test
location test
on prompt say "Try combining objects in your inventory"
on combine any
say "context: $context"
say "target: $target"
hidden equipped object knife
hidden equipped object bow
hidden equipped object arrow

You can play this game or open it in the editor.

object events

Events displayed to the player in the object screen. Executed upon selection by the player. Canceling these events has no special effect. Read more about object events here.

Can be defined in:

Variables

The first chapter introduced variables, but did not specify how to modify their values or how to create new ones. This chapter will return to this subject and explain it in much more detail.

Why do I need variables?

Let’s start by answering the question from this section’s header. I’ll do it with a short example:

defineevent 'ignite'
on create goto cave
 
location cave
on prompt
if torch.lit say "IT'S THE SPANISH INQUISITION!"
else say "It's too dark to see anything."
object torch
on prompt
if torch.lit say "It's ignited."
else say "It's not ignited."
on ignite
if torch.lit
say "It's already ignited"
else
set torch.lit
say "You ignite the torch."

You can play this game or open it in the editor.

Of course similar functionality could be achieved by defining an ignited torch and an unignited torch then hiding the first one and showing the second one. Variables are there to make things simpler. If you don’t want to use them you don’t have to. But do use them.

Special variables

They are four special variables that are available in every context:

It is very important to understand what self refers to. Take a short look a the following code:

object example
on use
hide self # error!

The on use event will fail with an error saying that we can’t hide an event. That shouldn’t be a surprise as self in the on use refers to the event itself, not to the object example. To hide this object we should write hide parent or hide example. Notice that thanks to parent we can write events that manipulate objects without identifiers:

object "I'm an object without an identifier"
on use
hide parent # it works!

The set command

To modify and create variables use the set command. Writing set path will set the variable referred by path to true. Writing unset path will set it to false. Other values, like numbers or strings can be set by writing set path expression where expression is any valid expression.

The set command can be used anywhere in the game’s code – not only in events. Commands outside events will be executed before the game starts.

Setting a variables value to none deletes it.

Some variables may be locked meaning that only the game itself can modify their value.

Invalid paths

Consider that you want to save a file on your computer. You are asked for a file path. If you provide a path to an existing file, this file will be overwritten. If you provide a path to an nonexistent file but all the folders on the way to it exist, this file will be created. If you provide a path with a nonexistent folder an error will be reported.

The same rule applies to variable paths in Adventure Script. A path is valid as long as all path elements excluding the last exist. Otherwise a NULL_REFERENCE error is reported.

A valid path to a nonexistent variable will always be resolved as a special none value. In conditions none is treated them same way as false.

Creating variables

To create a variable simply use the set command with a valid path to a nonexistent variable. There is but one limitation – the path needs to explicitly specify in which container to create the variable (in layman’s terms it has to have at least one dot in it). This is shown on the example below:

set foo # invalid
set root.foo # valid
object cave
set boo # invalid
set self.boo # valid
set cave.boo # also valid

System variable reference

Many elements of the game have variables automatically created in them by the game itself. Like hidden inside objects or disable inside events. These variables can be accessed and modified like any other variable in the game. This section will show what system variables are available and what is their meaning.

text (string)

The text variable is present in location, objects and options and is equal to their name. Changing it will alter the way they are displayed. Example:

on create goto cave
location cave
on prompt say "Is this realy a cave?"
object dwarf
on trigger
say dwarf "The cave is a LIE!"
set cave.text "The Great Meadow" # change the cave name

You can play this game or open it in the editor.

hidden (boolean)

The hidden variable is present in objects and options. It is set by the show and hide functions (actions). Manually changing it’s value will change the object’s visibility state but will not trigger the on hide and on show events.

equipped (boolean)

The equipped variable is present in objects. It is set by the equip and unequip functions (actions). This variable is locked and can not be changed manually.

disabled (boolean)

The disabled variable is present in events. It is set by the disable and enable functions (actions). Manually changing it’s value has the exact same event as using the disable and enable functions.

icon (string)

The icon variable is present in objects and options. Changing it’s value will change the the displayed icon. Example:

on create goto meadow
location meadow
on prompt say "Look at the paw!"
object dwarf
set self.icon "fa-paw"

You can play this game or open it in the editor.

bgcolor (string)

The bgcolor variable is present in objects and options. Changing it’s value will change the the displayed background color. Example:

on create goto meadow
location meadow
on prompt say "It's not pink, it's salmon!"
object dwarf
set self.bgcolor "pink"

You can play this game or open it in the editor.

.data.location (location)

This variable holds the current location. It is locked and can not be changed manually.

.data.inventory (array)

This variable holds the inventory in form of an array of objects. It is locked and can not be changed manually.

Modifiers

Modifiers can be added to definitions of game elements. There are three basic modifiers:

Modifiers need to be specified as the first element of a definition. A single definitions can have more then one modifier, for example to define a hidden and equipped object knife one can simply write:

hidden equipped object knife

The order of modifiers doesn’t matter.

Defining new modifiers

Understanding how to add new types of modifiers requires basic knowledge about functions and namespaces.

A new type of modifier can be added to the game by defining a one argument function in the .data.modifiers namespace. The function’s name will become the name of the new modifier. Upon creating a game element preceded by this modifier the function will be called with the element passed in the argument. An example custom doorway modifier is defined in the defaults.as file:

function data.modifiers.doorway o::object
set o.icon 'entrance'

This modifier sets the icons of the objects preceded by it to the ‘entrance’ icon. Note that the argument’s type has been set to object, allowing this modifiers to be used only on objects.

Strings

Text values written in quotes are called strings. This chapter will describe them in detail. The probably most interesting part of this chapter will be about patterns which are used to format the text displayed to the player.

String syntax

Don’t read this section if you don’t know squat about programing.

There are two types of strings – single quoted (') and double quoted (") strings. There is a slight difference between them.

Double quoted strings are interpolated and can use patterns. They also ignore white spaces used inside them (just like paragraphs in HTML). The $, ~, " and / symbols inside them need to be escaped with the / escape character.

Single quoted strings are literal strings, only the ' and / need to be escaped inside them (also by the / escape character).

Both type of strings can be multi-line, what has already been shown for example in this section’s example on prompt event.

HTML entitles inside strings are automatically escaped during compilation. This feature can be disabled by writing #!unescaped_strings in the begin of a source file. Doing so allows usage of raw HTML inside such file. Be warned that every tag that’s not a span or br gets stripped by the Adventure Script Player.

String interpolation

Don’t read this section if you don’t know squat about programing.

Double quoted strings support string interpolation with the use of the $ character:

Short example:

print "variables inside strings: $.data.location"
print "expressions inside strings: $(16+32)"
print "function calls inside strings: ${math.pow 2 5}"

Patterns

Patterns are a useful feature of Adventure Script that among other things allow formatting the text displayed to the user. Using predefined patterns i very easy but creating new ones can be tricky and requires much more knowledge.

Formatting of headers and prompts in the Adventure Script Player’s screens is realized by patterns defined in the defaults.as. Feel free to modify them to further customize your games.

Each pattern has a name. For example the pattern bold can be used to make a portion of text bold. To use this pattern inside a string write a \ followed by the pattern name (bold) and the text to be made bold surrounded in curly brackets ({ and }). Just like this:

say "The word \bold{meadow} is made bold."

bold is a one-argument pattern, as you only specify the text to be made bold. Some patterns can have more arguments, for example to use the color pattern you have to specify the color and the text. To make a portion of text red one would write:

say "The word \color{red}{meadow} is made red."

In this example the first argument is ‘red’ (the color) and the second is ‘meadow’ (the text). Arguments are written one after another, each one surrounded in curly brackets.

Patterns can be mixed together, for example:

say "\bold{This text is in bold. \color{red}{This text is bold and red}}"

All available patterns are listed in the pattern reference.

Creating patterns

This section describes an advanced feature of Adventure Script.

Patterns can be defined in two different ways: as template strings or pattern functions.

Template string patterns

A pattern can be defined by writing pattern followed by a name and template string. A template string is a string with placeholder variables. Placeholder variables are numbered from zero, each number corresponding to subsequent arguments of a pattern. For example the color pattern is defined in the following way:

pattern color "<span style=\"color:$0\">$1</span>"

Function patterns

A pattern can be defined by writing pattern followed by a name and a function body. Arguments of the pattern are created automatically and are called _n where n is the argument number (starting from zero). The function body should return the result string. For example the nbsp pattern is defined in the following way:

pattern nbsp
if {istype _0 'string'}
set _0 {atof _0}
local out ''
while _0 > 0
set out out+'&#160;'
set _0 _0-1
return out

Pattern reference

Adventure Script predefined pattern reference:

Example usage of all of these patterns has been shown in the code below:

on create goto test
location test "Patterns demo"
on prompt say "\span{font-style:normal}{
\bold{bold text}\br
\emph{italic text}\br
\color{red}{colored text}\br
\bgcolor{red}{coloted background}\br
multiple\nbsp{4}spaces\br
~~multiple~~~~spaces~~\br
\span{font-family:'Comic Sans MS'}{styled span}\br
\name{$test}
}"

You can play this game or open it in the editor.

\bold{text}

Makes text bold.

Arguments:

\emph{text}

Makes text italic.

Arguments:

\color{color}{text}

Set text’s color.

Arguments:

\bgcolor{color}{text}

Set text’s background color.

Arguments:

\nbsp{number}

Inserts multiple non-breaking spaces. Writing a ~ inside a string is a shortcut for \nbsp{1}.

Arguments:

\br

Inserts a line break.

No arguments.

\span{style}{text}

Inserts a styled HTML span element. Only the following CSS properties are allowed:

Arguments:

\name{variable}

Inserts the name of a game element.

Arguments:

\ignore{argument}

Does nothing with a pattern argument.

Arguments:

Dialogs

This chapter is sh*t. I’ll write a better one someday.

A dialog tree is created by defining dialogs inside dialogs. The position of a dialog in a dialog tree effects the way on enter and on leave events are executed. There are two special actions that can be used inside dialog options:

Play the following example and observe how the on enter and on on leave are executed:

on create goto demo
 
dialog main
on enter say "I entered the main dialog"
on leave say "I left the main dialog"
on prompt say "Hello from the main dialog"
option "enter first child" goto firstchild
option "enter second child" goto secondchild
option "enter inner child" goto firstchild.innerchild
option "exit" quit
option "goback" goback
dialog firstchild
on enter say "I entered the first child dialog"
on leave say "I left the first child dialog"
on prompt say "Hello from the first child dialog"
option "enter main" goto main
option "enter second child" goto secondchild
option "enter inner child" goto innerchild
option "exit" quit
option "goback" goback
dialog innerchild
on enter say "I entered the inner child dialog"
on leave say "I left the inner child dialog"
on prompt say "Hello from the inner child dialog"
option "enter main" goto main
option "enter first child" goto firstchild
option "enter second child" goto secondchild
option "exit" quit
option "goback" goback
dialog secondchild
on enter say "I entered the second child dialog"
on leave say "I left the second child dialog"
on prompt say "Hello from the second child dialog"
option "enter main" goto main
option "enter first child" goto firstchild
option "enter inner child" goto firstchild.innerchild
option "exit" quit
option "goback" goback
 
location demo
on prompt say "Open the dialog and observe how events are executed."
object "start dialog"
on trigger goto main

You can play this game or open it in the editor.

The on enter event is executed when the player moves up in the dialog tree (for example from firstchild to innerchild). The on leave event is executed when the player moves down in the dialog tree (for example from innerchild to firstchild). When the player moves sideways both events are executed (for example from firstchild to secondchild).

Expressions

Ugh, this chapter came out to be unreadable for people without basic programing skills.

A expressions is a mix of values, variables and operators.

Values

Adventure Script has the following scalar types:

Operators

Operators in Adventure Script in the order of their precedence:

Operator Description Argument types Example Result
||, or logical or any false or 2 2
&&, and logical and any false and 2 false
| bitwise or numeric 1 | 3 3
^ bitwise xor numeric 1 ^ 3 2
& bitwise and numeric 1 & 3 1
== equal to any 1 == 1 true
=== typed equal to any 0 === false false
!= not equal to any 1 != 1 false
!== typed not equal to any 0 !== false true
< greater then numeric 2 < 1 true
<= greater equal numeric 2 <= 2 true
> greater then numeric 2 > 1 false
>= greater equal numeric 2 >= 2 true
<< left shift numeric 1 << 3 8
>> right shift numeric 8 >> 3 1
- minus numeric 2 - 1 1
+ add string, numeric 2 + 1 3
* multiplication numeric 2 * 1 3
/ division numeric 2 / 1 2
% modulus numeric 2 % 1 0
!,not logical negation any !true false
~ bitwise negation numeric ~1 -2
@ reference extraction @variable reference
() grouping operator (1+2)*3 9
[] array literal [1 2 3] array
{} function call {math.pow 2 3} 8
c?a:b ternary operator true?'a':'b' ‘a’

Notes:

Type system

Complete type hierarchy in Adventure Script:

Notes:

Namespaces

A namespace is the base type of dialogs, locations and objects. Namespaces have two main functionalities:

The special root variable points to a predefined topmost namespace called root with the parent variable equal to none.

Creating namespaces

Namespaces can be created to scope your code, for example to define a group of locations in a chapter1 namespace for convince. To create a namespace write namespace followed by a identifier. For example this is how the data.modifiers namespace is defined inside Adventure Script run-time:

namespace data.modifiers
function equipped obj::object
equip obj false
function hidden obj::container
hide obj false
function disabled obj::event
disable obj

Extending namespaces

Remember that dialogs, locations and objects are namespaces. Everything that can be done with namespaces can also be done with them.

A already created namespace can be extended with additional elements outside of it’s block. This can be done in the following two ways.

Extend keyword

Write the extend keyword followed by a namespace you want to extend, then open a block. Everything in this block will be executed it that namespace’s context.

Every Adventure Script source file extends the root namespace this way. This is done automatically but could be written as:

extend root
# source file contents

Path as identifier

Another way to extend a namespace is to use a path instead of an identifier in a element defection. For example this is done in the defaults file to define a custom modifier:

function data.modifiers.doorway o::object
set o.icon 'entrance'

This feature is quite useful when writing dialog trees. It can keep the indention level reasonably low by defining all inner dialogs on the same indention level.

Functions

This chapter assumes you have basic programing skills.

To call a function in Adventure Script one simply writes the function name (or a expression that resolves to a function) followed by a white-space separated list of arguments if form of expressions. So for example say lucy "hello" calls the function say with lucy and "hello" as the arguments. In fact every “action” presented in this manual (say, goto, equip, …) was a function. But not set and unset, they are keywords.

Function calls can also be part of expressions. The syntax is exactly the same, but the call needs be surrounded by curly brackets ({ ... }).

Here is a example of a complex function call taken from the Adventure Script run-time:

{index {index {index stack -2} 'options'} input}

It is equivalent to the following line written in a C-like language:

(index(index(index(stack,-2),'options'),input))()

Fun fact: functions, as well as everything else in the game can be named like a keyword as long as the name is enclosed in back-quotes (so you can define a function `function`).

Arguments

Function arguments are specified after the function name in form of a white-space separated list of names. Arguments can be typed and untyped and can be passed by value or reference. A argument type is specified by writing ::type after it’s name (for example x::number). By default every argument is untyped and passed by value. To pass an argument by reference add the reference extraction operator (@) before the argument name. The argument may still specify a type. A good example of a function using untyped arguments passed by reference is the swap function:

function swap @a @b
local c a
set a b
set b c

More about references and the reference extraction operator in the references section below.

When a value of an invalid type is passed to a function with a typed argument a TYPE_ERROR error is raised. All sub-types of the specified type are considered valid (for example specifying ::any is equivalent to an untyped argument).

When a function is called with a different amount of arguments then specified in the definition a INVALID_ARRITY error is raised.

Variadic functions

Variadic functions can be defined by adding the variadic modifier to a function definition. The arguments can be accessed by calling the arguments function, which will return them in form of an array. Named arguments may still be specified. The amount of named arguments determines the minimal arrity – calling the function with less arguments then the amount of the named arguments will result in a INVALID_ARRITY error. The concat function is a example of a variadic function without named arguments:

variadic function concat
local arr {arguments}
local i 0
local str ''
while i < {length arr}
local e {index arr i}
set str str+{istype e 'string'}?e:{tostring e}
set i i+1
return str

Locals

Adventure Script supports classical block-scoped locals. To define a local use the local keyword followed by a name and a optional initial value. If the initial value is not specified none will be used. Look at the the concat function in the section above for a example.

While and elseif

The only loop supported in Adventure Script is the while loop with the following syntax:

while expression
commands

Inside the while loop break and continue can be used.

Adventure Script also supports any number of elseif blocks inside conditions:

if expression
commands
elseif expression
commands
else
commands

References

Adventure Script supports PHP style references. References are created by the reference extraction operator (@). A newly created reference is unbounded and after it gets assigned to any variable it becomes bounded. Accessing a bounded references accesses the value of the referenced variable. Ugh, you know what? Just look at the example:

local a 5
local b @a
local c b
local d @b
set a a+1
print a # 6
print b # 6
print c # 5
print d # 6

Using the reference extraction operator on a reference makes an unbounded copy of it.

Warning: references don’t get serialized – they can’t be a part of save-games. Leaving a reference hanging somewhere in a global variable will crash the save process. So don’t do that.

Multiple dispatch

Multiple dispatch is implemented via dispatchers. The syntax is sadly pure crap. Here is the definition of the tostring dispatcher and some of it’s member functions:

dispatcher tostring
function tostring_container value::container extends tostring
return "${path value}::${typeof value}"
function tostring_numeric value::numeric extends tostring
return value+''
function tostring_string value::string extends tostring
return '"'+value+'"'
function tostring_any value::any extends tostring
return '::'+{typeof value}
function tostring_none value::undefined extends tostring
return 'none'

A dispatcher is created by writing the dispatcher keyword followed by a name. Any function can be added to the dispatcher by writing extends after it’s argument list, followed by a path to the target dispatcher. Alternatively the push function can be used with the first argument equal to the target dispatcher and the second to the function to be added.

Inheritance

OOP means something to you? No? Then you probably won’t understand a thing.

Locations and objects support inheritance in form of something similar to a prototype chain. The problem is that Adventure Script does not have prototypes or classes, only instances. Personally I think the resulting instance-to-instance inheritance chain is weird and confusing. And I wrote it!

To make A inherit from B write extends B at the end of the A definition (for example object A extend B). The identifier can be skipped – is such case it will be taken form to element we inherit from (in other words we can write object extend B to create a object B in the current context that inherits from the original B object… that didn’t help, didn’t it)?

Assume we write A.something:

To create / access a variable something inside A regardless if it’s in B:

To create / access a variable something inside B regardless if it’s in A:

Of course events get inherited just like everything else.

Inheritance has been used in the example game. Open it and take a look at the object steve and how it’s added to the home location.

Understanding errors

There are three types of errors:

Parse errors

The thing is nobody taught me how to write a compiler with nice error routines so I didn’t write them at all. Yup, that means that parse errors suck and they do it big time. Don’t even bother reading them. Just check the line number.

This code (missing say before "Hello!")

on prompt "Hello!"

will result in something like this: Expecting 'NL', 'VARNAME', 'IF', 'WHILE', 'INDT', '{', 'CONTINUE', 'YIELD', 'BREAK', 'RETURN', 'THROW', 'LOCAL', 'SET', 'UNSET', got 'STRING_START'. Beautiful isn’t it?

VM errors

There are four VM errors you are likely to see:

Each VM error includes a stack trace that allows localizing the error in the code.

Runtime errors

Here are some common runtime errors:

Each VM error includes a stack trace that allows localizing the error in the code.

Stack traces

A stack trace shows what the virtual machine was doing in the moment the error occurred. Let’s take a look at an example stack trace and explain what information if holds:

stack trace:
[5] /runtime/game.as:rret:57
[4] /game/main.as:bow:5
[3] /runtime/runtime.as:safecall:87
[2] /runtime/game.as:rrot:117
[1] /game/main.as:root:4

The error occurred on line 57 of the file /runtime/game.as during executing the rret function. This is unhelpful as this file is part of the Adventure Script standard library and not your code. Let’s look at the line below to see where the rret function was executed – on line 5 of the /game/main.as file. This is the last line of your code executed before the error happened and most likely the localization of the error.

Runtime function reference

This chapter lists all functions available to the user.

All run-time functions are defined in the rt namespace and exported to the global context (root namespace). You can freely overwrite these exports.

General functions

index ::array ::number

returns an array array element with the given index in form of a bounded reference (see example below). Negative numbers can be used to index from the end.

local T [1 2 3 4 5]
print {index T 2} # 3
print {index T -2} # 4
set {index T 2} 8 # sets T[2] to 8
local v {index T 2} # v holds the VALUE 8
local r @{index T 2} # r holds a reference to T[2]
set v 9 # T[2] is still 8
set r 9 # T[2] is now 9

index ::string ::number

returns a character with the given position. Negative numbers can be used to index from the end.

index ::container ::string

returns a container’s member in form of a bounded reference. index a b is equivalent to resolve 'self.'+b a.

length ::array

returns the length of a array

length ::string

returns the length of a string

push ::array [::any…]

adds elements to the end of an array

push ::dispatcher ::function

adds a function to a dispatcher

slice ::array ::number [::number]

see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/slice

slice ::string ::number [::number]

see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/slice

tostring ::any

returns the passed value converted to a string

find ::array ::any [::number]

see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf

find ::string ::any [::number]

see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf

export ::container

copies all elements from a container to the root namespace

export ::container ::string [::string…]

copies specified elements from a container to the root namespace

resolve ::string ::container

evaluates a path in a given context without searching through the given context’s parents. The result is returned in form of a bounded reference.

fullresolve ::string ::container

evaluates a path in a given context. The result is returned in form of a bounded reference.

exists::string ::container

checks if a path is valid in a given context. Returns a boolean value.

lock @::any

locks a variable

islocked @::any

checks if a variable is locked. Returns a boolean value.

istype @::any ::string

checks if a variable is of a given type (or it’s sub-type). Returns a boolean value.

typeof @::any

returns variable’s type as string

nameof ::container

returns container’s identifier as string

print [::any…]

prints values on the console / IDE event log

apply ::function ::array

calls a function with the argument list equal to the given array

arguments

returns current function’s argument list in form of an array

members ::container

returns all member names of a container in form of an array of strings

path ::container

returns a containers full-path in form of a string

atof ::string

converts a string to a number and returns it

concat [::any…]

converts all arguments to strings and returns a single joined string

swap @::any @::any

swaps two variables in-place

Math functions

see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math

Note that Adventure Script functions raise errors on Infinity and NaN.

Array functions

array.create

returns an empty array

array.wrap [::any…]

returns an array created from the passed arguments (does the same thing as the [ ... ] operator)

array.pop ::array

removes and returns an element from the top

array.shift ::array

removes and returns an element from the beginning

array.unshift ::array ::any

adds element to the beginning

array.clear ::array

clears an array

Game functions

say ::string

displays narration

say ::object ::string

displays dialog line said by an object

show ::object [::boolean=true]

shows an object. If second argument is false doesn’t execute on show.

show ::option

shows an option

hide ::object [::boolean=true]

hides an object. If second argument is false doesn execute on hide.

hide ::option

hides an option

equip ::object [::boolean=true]

equips an object. If second argument is false doesn’t execute on equip.

unequip ::object [::boolean=true]

unequips an object. If second argument is false doesn’t execute on unequip.

enable ::event

enables an event

enable ::namespace ::string [::object]

enables an event in the specified namespace. Third argument is the target object for combine events.

disable ::event

disables an event

disable ::namespace ::string [::object]

disables an event in the specified namespace. Third argument is the target object for combine events.

defineevent ::string [::string [::string [::string] ] ]

defines an object event with the specified name, text, icon and background color

do ::namespace ::string

executes an event in the specified namespace

dialogowner ::dialog

returns the object owning the specified dialog

goto ::any

goes to location / dialog / object screen. This function preforms a long jump.

goback

goes one level up in the dialog tree. This function preforms a long jump.

quit

quits the dialog tree. This function preforms a long jump.