Uploaded by Robin Johnson

Gruescript Text Adventure Game Creation Guide

advertisement
Creating Text Adventure Games
on Your Computer With Gruescript
Robin Johnson
This work is licenced under the Creative Commons
Attribution 4.0 International License. To view a copy
of this license, visit
http://creativecommons.org/licenses/by/4.0/
or send a letter to Creative Commons, PO Box 1866,
Mountain View, CA 94042, USA.
Contents
Foreword.......................................................................................................................1
Blocks............................................................................................................................4
The game block.....................................................................................................6
Comments..............................................................................................................8
Rooms............................................................................................................................9
Room verbs..........................................................................................................10
Tags.......................................................................................................................10
Properties.............................................................................................................11
Special properties...............................................................................................12
Things..........................................................................................................................13
Special tags..........................................................................................................15
Special properties...............................................................................................17
Instructions................................................................................................................20
Commands...........................................................................................................21
Listers.............................................................................................................27
Assertions............................................................................................................28
Referencing variables........................................................................................32
Referencing properties......................................................................................32
Referencing connected rooms.........................................................................33
Braced expressions.............................................................................................33
Capitalisation in references.............................................................................36
Iterators................................................................................................................37
Changing the order of iteration...............................................................39
Verbs............................................................................................................................41
Verbs with directions.........................................................................................42
Setverbs................................................................................................................44
Conversation..............................................................................................................46
Procedures and rules................................................................................................50
Procedures...........................................................................................................50
Arguments.....................................................................................................51
Rules......................................................................................................................52
Special variables........................................................................................................54
Visible tags...........................................................................................................55
Appendix I: Visual configuration..........................................................................57
Appendix II: Cloak of Darkness............................................................................59
Foreword
I was trying to play Pirate Adventure on my phone when I came up with
the format of the games that Gruescript would create.
Pirate Adventure is the second of the Adventure International titles by Scott
and Alexis Adams. In the late 1970s, when Adventure and Zork could only
be played at university campuses, the Adamses brought interactive fiction
to the first generation of home microcomputers. The tiny memories of
those machines put severe constraints on the games’ writing. The result
was a subgenre of parser games with terse, efficient prose – singlesentence room descriptions, making resourceful use of tropes and stock
characters so that the player’s imaginations could do the work of
visualisation – backed up by ingenious puzzle design. Inform creator
Graham Nelson wrote in The Craft of Adventure that the Adamses’ games
invoke “the feeling of holding a well-made miniature, a Chinese puzzlebox with exactly-cut pieces.”
Modern parser games are no longer limited by memory, of course, but I
feel that there’s still a place, a purpose, and an audience for games in that
‘puzzlebox’ style. Writing under constraints can be an enjoyable and
challenging sort of creativity in itself, like composing a haiku. And the
terse prose of these games would make them perfect for a phone or tablet
screen – if it weren’t for the need for the player to type.
In the last decade or so, hobbyist and indie interactive fiction has seen an
explosion in form*, with systems like Twine, ChoiceScript and Inkle
making web and mobile IF more accessible and democratised for players
and authors alike. Most games made in these systems are story-centric
rather than puzzle-centric: that’s what web and mobile interfaces are best
for delivering, and it’s what the development systems are best for creating.
The development systems, the interfaces available, and the feel of the
games produced are intricately related.
*
I want to make one thing extremely clear: this is awesome. All kinds of IF, from
all kinds of creator, are valid, are welcome, and enrich the genre.
1
For parser IF, the barrier to that sort of immediate accessibility is the
interface. I don’t just mean that mobile devices don’t have keyboards. The
golden age of parser games happened when the standard way of
interacting with a computer was by typing at a prompt. Command
prompts were intuitive to players at the time, just as links and buttons are
intuitive now.
So, how do we revive the puzzlebox feel for mobile-friendly games? If all
the player’s possible choices must be visible on the screen all the time,
how can we pose a puzzle without immediately giving the solution away?
I first tried to solve this problem in 2016, with a game called Draculaland.
Using JavaScript running in a simple, client-side web page, I created a
world model of interconnected rooms containing objects that can be
arbitrarily picked up and moved around – the basic structure that’s taken
for granted in parser games, but which choice systems don’t tend to
bother with. (Some authors, like Astrid Dalmady and Josh Labelle, have
implemented this sort of world model impressively in Twine games, but
Twine didn’t make it easy for them.) I added buttons for movement
between the rooms, and gave each object an associated list of ‘active
verbs’ that change depending on the game state. For example, any portable
item has the ‘take’ verb active when it’s lying on the floor, or ‘drop’ if it’s
being carried by the player. Special actions can then be made possible at
certain points in the game – for example, if the player is standing in the
graveyard while carrying the shovel, the verb ‘dig’ activates. This is a
simple example, but it’s essentially a parser-game puzzle: the player has to
make the mental connection between the shovel and the grave, then
navigate back to the right spot, through a generalised interface that
doesn’t give the secrets of the game away, to try out their idea.
The second game I made with that JavaScript engine, Detectiveland, won
that year’s Interactive Fiction Competition. It was the first non-parser
game to do so. I’ve made several games with the same engine since, and
had enquiries from authors asking whether they could use it to write their
own games. Usually I told them I planned to package it up neatly one day,
but for now they were free to grab the source and modify it. Nobody did. I
2
could have published the engine as a sort of library, which people would
use to write their own games in JavaScript – but judging by various
attempts to make parser game libraries in JavaScript and other generalpurpose languages over the years, those don’t really take off: if an author
is willing to use a general-purpose language, they’re probably the sort of
author who’ll just write their own engine.
But the game data itself didn’t have to be JavaScript. The components of
the games themselves were defined as relatively simple objects: ‘rooms’,
‘things’, ‘verbs’ and ‘rules’ – which could easily be imported from a text
file using a simple(ish) script syntax. I modelled the syntax on the
assembler-type language used in the Adventure International games,
available to modern developers as ‘ScottKit’, because the JavaScript games
were very similar in structure – the only extra information needed was a
way to tell the game which verbs to activate, for which things, under what
circumstances.
Two of the hobbyist game development systems that I find most
interesting are Adam Le Doux’s Bitsy and increpare’s Puzzlescript. Bitsy
creates tiny, pixel-art style games with very little support for puzzles. It’s
used to create short-form narrative games, often telling highly personal
stories from authors in marginalised groups. Puzzlescript makes 2d
graphical puzzle games like Sokoban, again with a retro pixel-art aesthetic.
Both have web-based development environments: authors work in an
editor running in the Bitsy or Puzzlescript web page, then eventually
download their game as an HTML document that they can share on their
own itch.io page or elsewhere. Both systems are accessible and cute, and
they’ve both gained strong followings, with regular game jams and
popular fan-made mods.
That sort of web-based development environment seemed like the ideal
model for a tool to create keyboardless puzzlebox text adventure games,
which, like Bitsy and Puzzlescript games, will run in web pages
themselves. I called it Gruescript, because I’d just done a game about
grues, and I’m obsessive like that.
3
Blocks
The basic units of Gruescript code are blocks of one or more lines. The
first line of each block begins with one of the nine ‘block type’ keywords –
that’s how Gruescript knows where a new block starts. The block types
are:
game
Contains the game title and metadata, and any
instructions to be run when the game begins. There
must be exactly one game block in your Gruescript
code.
room
A location in the game
thing
Anything that physically exists in the game world,
except rooms and the player character. This includes
portable and non-portable items, scenery, and nonplayer characters.
proc
A procedure: a list of instructions that is remembered
by its name, so it can easily be run from anywhere
else in the code. More than one procedure block can
have the same name (they will be run in turn until one
succeeds.)
rule
A rule is like a procedure, but it does not have a name
and cannot be run from other code. All rules are run
automatically, after every turn during gameplay.
4
verb
A procedure that is run whenever the player performs
a particular verb. This can be declared for a particular
verb being applied to a particular thing (specific
verbs), or for a general definition of a verb (general
verbs). There can be several verb blocks for the same
verb, or the same pair of verb and thing.
setverb
Setverbs determine whether a given verb is active.
Like verb blocks, setverb blocks can be thing-specific
or general, and there can be multiple setverb blocks
for the same verb and/or thing. Setverbs run more
often than rules – as well as every turn, they also run
when the player changes the inventory item they are
‘holding’.
var
A variable, which can be a number or a string.
Variables do not have to be declared to be used;
Gruescript understands no difference between an
undeclared variable and a variable with a numeric
value of zero. Variable blocks always have exactly one
line.
tagdesc
A ‘visible’ tag. Tags are keywords associated with
rooms and things. Some tags, such as lightsource
or wearable, have special meanings to Gruescript;
others can be arbitrarily made up by the author to use
in rules and verbs. Generally, tags do not have to be
declared, but any tag declared with tagdesc
becomes ‘visible’, meaning it has a description that
will be printed alongside any thing that has that tag.
These blocks always have exactly one line.
5
The game block
Gruescript code should contain exactly one game block, normally at the
very beginning of the Gruescript file. The block must contain at least the
game title, and usually contains further metadata and any instructions
(usually say commands) to be run at the beginning of the game. Here’s an
example:
game Spaceships Versus Kitten
id SVK
author Brian Snodbury
version 1.0.0
person 2
examine on
wait on
say You were minding your own business and
playing with a ball of wool one day when an
alien spaceship crashlanded right next to your
cat tree!
say
# Released under the Foobar Licence
<http://foobar.madeupurl/licence-terms>
Let’s go through each of these lines in turn.
game Spaceships vs Kittens
The title of the game.
id SVK
An identity code for the game. This is used in local storage (cookies) to
identify saved games and options. If you host more than one Gruescript
game on one site, they must all have different ids.
author Brian Snodsbury
The author’s name (or authors’ names). If present, this will be displayed
with the game title at the beginning of play.
person 2
6
The number after person can be 1 or 2, determining whether the game
will be in the first person (“I am in...”) or second person (“You are in...”)
This game will be in second person. This only affects the display and
default messages – your room descriptions and so on will have to be
written with the right person in mind. If there is no person line, the
game will default to second person.
examine on
If this line is present, every ‘thing’ in the game will be displayed as a
button which the player can click to examine that thing. examine is a
‘native verb’, meaning every Gruescript game will know the verb without
the author having to define it. If the game block contains examine off
instead (or no examine line at all), the ‘examine’ verb will still exist, but
will only be available as an ordinary verb button activated by a setverb.
wait on
This means that the native verb ‘wait’ will be available throughout the
game, shown as a button below the room contents. If this line is
“wait off”, the button will not be present (but the native verb will still
exist, and can be made available using an intransitive setverb – see the
chapter on verbs.) Unlike examine, Gruescript’s default behaviour if this
line is omitted is to consider wait ‘on’.
say You were minding your own business and
playing with a ball of wool one day when an
alien spaceship crashlanded right next to your
cat tree!
say
These are instructions that will be run when the game starts, before the
title and author are printed. Only one kind of instruction is used, the
command say, which prints the rest of the text on the line. The second
say instruction, as it has no text after it, will print a blank line.
7
Additionally, the game block may contain colour (or color) lines,
which configure the game’s colour palette. These are explained in
Appendix I.
Comments
The hash character (#) denotes comments; these are for authors to keep
notes and annotate code, and are completely ignored by Gruescript. The
hash can come at the beginning of a line, in which case the whole line is
ignored, or partway along a line, in which case anything after it is ignored
(If you want to output a ‘#’ character in your game, as part of a message,
room description, or anything else, use the HTML entity ‘#’.)
Our example game block contains the comment:
# Released under the Foobar Licence
<http://foobar.madeupurl/licence-terms>
While entirely meaningless to Gruescript, it is a good idea to put any
licence information in comments in your script near the top of the code.
Gruescript itself is released under the MIT License. When you export your
game from Gruescript to an HTML page, the engine code itself will be
marked with that licence, but you are free to apply whatever licence you
wish to your script.
8
Rooms
The locations in your game world are called rooms; a game will not work
at all without at least one room. Of course, a room doesn’t have to
correspond to a literal room – it might be a corridor, a garden, or one end
of a large ballroom. Rooms are defined using room blocks. Here’s a simple
example. The first line begins the declaration and contains the room’s
name (which will be used internally by Gruescript) and description (which
will be seen by the player.) The rest of the lines can come in any order, and
define the room’s properties:
room by_fountain You're in a walled garden by a
fountain.
north summer_house
east potting_shed
tags outdoors garden
prop wall_colour red
This room’s internal name is by_fountain. This name can consist of
letters, numbers and underscores, is case sensitive (like everything else in
Gruescript), and must be unique – no other rooms or things can be named
by_fountain. The rest of the first line is the description of the room
that the player will see when they are in that room.
The second and third lines in our example are directions. These tell
Gruescript where the player can move to from the fountain room: north to
summer_house or east to potting_shed (both of which must be
defined in their own room blocks elsewhere.) The directions Gruescript
understands in this way are:
•
the cardinal and secondary compass directions: north,
northeast, east, southeast, south, southwest, west,
and northwest
•
up, down, in and out
9
•
the shipboard directions fore, aft, port and starboard
A connection between two rooms has to be declared from both of them –
that is, the room declaration of summer_house will need to contain a
line south by_fountain, or the connection will be one-way.
If you want to use unconventional directions that aren’t listed above, use
dir lines in your room block:
room brass_bridge You’re on the Brass Bridge.
dir widdershins patricians_palace
dir turnwise broad_way
Room verbs
Rooms may have a verbs line:
room dance_floor
verbs tapdance robot limbo
The verbs listed on this line will become the room’s ‘permanent verbs’,
available to the player whenever they are in the room. They are listed in
an ‘Actions’ line just below the room description (but above the listed
room contents.) Attaching verbs to rooms is intended to be the exception
rather than the norm. Most verbs will be attached to things rather than
rooms (see the next chapter.)
Tags
Rooms may optionally have any number of arbitrary ‘tags’, added in the
block with lines beginning tags – there can be any number of tags lines
in a room block, and each tags line can contain any number of tags. A tag
can be whatever you like, as long as it is a string of letters, numbers and
underscores. Our fountain room has the tags outdoors and garden.
Tags are usually things that you make up yourself to use in the logic of
your game’s verbs and rules – for example, we might later write a rule that
gives the player messages about the weather if they are outside, or certain
verbs might have different effects in ‘garden’ rooms.
10
Some tags for rooms have special meanings in Gruescript:
•
start means the player starts the game in this room. No more
than one room should have this tag. If there is none, the player
starts in the first room declared in your Gruescript.
•
dark means the room is dark, and the player will not be able to
see the room description or objects in it unless a light source (i.e.
a thing with the tag lightsource) is present, either in the
room or carried by the player. (They will be able to see the
available directions. If you want to make an exit from a room that
a player can only use if they can see, either use a non-portable
thing such as a ladder with a climb verb, or use open and
close commands in rules – see the chapters on instructions and
rules.)
Properties
prop wall_colour red
Things may have any number of properties, set by the author. A property
is something like a tag, but instead of just being there or not there, it has a
value which can be a number or a string or one or more words. In this
case, the room’s property wall_colour has the value red. This could
be used for just about anything – perhaps there is a bull roaming the game
world whose behaviour depends on the colours of the walls around them.
The property value can be referred to from an instruction by something
like by_fountain.wall_colour, or $room.wall_colour – we’ll
explain more about this in the chapter on instructions.
Like variables, properties don’t have to be declared to be used by code
later. If a property is referenced without having been declared, it is treated
as though its value is zero.
11
Special properties
Only one property of rooms is special in Gruescript: desc, which
contains its description – usually the same text that is supplied after the
room name in the first line of its room block. This:
room stable You’re in a shed smelling of horses.
does exactly the same as:
room stable
prop desc You’re in a shed smelling of horses.
The point of the description being accessible as a property is to make it
possible to modify that description during the game – perhaps spraying an
air freshener gets rid of the smell, which would be done with an
instruction like “write stable.desc You’re in a shed that
smells lovely.” – see the chapter on instructions for more about
this.
12
Things
A thing is any physical object in your game world – portable and nonportable items, scenery, non-player characters, and anything else. They are
defined in thing blocks, like this:
thing top_hat blue top hat
name hat
desc A tall stovepipe hat in royal blue velvet.
loc bedroom
tags portable wearable posh
prop material velvet
Going through this example line by line:
thing top_hat blue top hat
The beginning of the thing block: this thing has the internal name
top_hat, and the short description ‘blue top hat’, which is how it
appears in a room or player inventory during gameplay.
name hat
This is the ‘screen name’ of the hat, the one that is used in certain places
such as the Gruescript prompt – if the player clicks wear next to the hat,
this means that they will see the prompt ‘>wear hat’. (If this is omitted,
Gruescript will use the internal name and replace underscores with spaces,
in this case making the reasonable guess ‘top hat’.) It is often useful to
create two or more similar items with the same screen name, so that they
can be swapped without the player noticing – for a classic example, a lit
lamp and an unlit one.
desc A tall stovepipe hat in royal blue velvet.
desc gives the long description of the thing, that the player will see when
they examine it. In a game with examine on, these should be present
for all, or nearly all, things. There can be several desc lines in the same
thing block, in which case they all run together into a single description
13
(with a space between each line, but not a line break – if you want a line
break in your description, use the HTML ‘<br>’.)
loc bedroom
The location of the thing, specified by the (internal) name of a room. If
there is no loc line in the thing block, the thing will start ‘offstage’
(unless it is carried) until it is placed somewhere by a verb or rule.
tags portable wearable posh
Things can be given tags in exactly the same way as rooms. Several tags
have special meanings to Gruescript; the most useful of these is
portable, which means the thing can be carried by the player – a
portable item will always have the native verb drop activated when it is
in the player’s inventory, and take when it is not. Our top hat also has
the special tag wearable, meaning the player can wear and remove it
(like take and drop, these are both native verbs and will be activated
and de-activated by Gruescript), and the author-defined tag posh.
prop material velvet
Like rooms, things may have any number of properties, set with prop
lines. This hat has the property material with the value velvet.
Two of the most important lines in thing blocks, which were not in our
top hat example, are verbs and cverbs. These give the thing its usual
set of active verbs – verbs specifies the thing’s ‘permanent verbs’, which
will always be active for the thing (they cannot be de-activated, even by a
setverb), and cverbs specifies ‘carried verbs’ that will be active
whenever the thing is in the player’s inventory (they cannot be deactivated while the thing is carried, but they can be activated by a setverb
while it is not carried.) Either of these, like tags, they can be declared over
multiple lines if necessary. Any thing block can contain verbs lines,
cverbs lines, or both, but it is more usual for portable things to have
14
carried verbs and non-portable things to have permanent verbs. For
example, it makes sense that a warning sign on the wall of a room
thing sign Warning sign on wall
verbs read
can be read whenever the player can see it, whereas a booklet
thing booklet
cverbs read
can only be read if the player is carrying it.
If a thing block contains a line with the single word
carried
it will start the game in the player’s inventory.
Special tags
The following tags have special meanings for things in Gruescript:
portable
This item can be taken, carried around in the
player’s inventory, and dropped. Gruescript will
handle the activation and de-activation of these
verbs. (You can use setverbs to activate take or
drop when they would not normally be active,
but not to de-activate them when they would not;
if you want to mess with this logic, use a nonportable item.)
wearable
This thing is an item of clothing. When it is in the
player’s inventory, the native verb wear will be
activated; while it is worn, it will have the tag
worn, and the verb remove will be activated.
worn
This thing is currently being worn
15
alive
This thing is a living creature. This affects the
order that nouns are displayed in – alive things
are usually listed first in room contents.
lightsource
This thing provides light; if it is present in a dark
room (whether or not the player is carrying it),
that room and its contents will be visible.
plural
The name of the thing is plural, and should be
treated as such with respect to pronouns and
other grammar. This should be set if the thing’s
screen name (i.e. the name given in its thing
block) is plural, rather than its internal name or
short description. For example,
thing flowers bouquet of flowers
tags plural
is correct (as its screen name will be flowers,
plural), but
thing flowers bouquet of flowers
name bouquet
should not have plural, or it may get referred to
as some bouquet.
16
mass_noun
The name of the thing is a mass noun, like ‘salt’ or
‘mud’ – not plural, but not a discrete singular
item. By default, Gruescript will use ‘some’
instead of ‘a/a’ when referring to this thing in the
indefinite case. The indefinite form is based on the
thing’s short description, not its screen name, so
thing sugar bag of sugar should not
have this tag (“a bag of sugar”), but thing
grass tall grass should have it (“some tall
grass”).
male
female
nonbinary
This thing has gendered pronouns: he/him for
male, she/her for female, or they/them for
nonbinary. If a thing has none of these tags, its
pronoun will be ‘it’, or ‘they/them’ if it is plural.
list_last
Things with this tag will always be listed last in
the room window (and scroller, if the ‘list objects
in scroller’ option is enabled), regardless of
whether they are portable or alive.
quiet
Things with this tag will not be listed at all in the
scrolling window, regardless of the display
options; this does not affect their listing in the
room window. It’s intended to be used for things
that are duplicated in the room description, so the
player won’t see something like “You are
next to a church. You can also see
a church.”
Special properties
The following properties of things have special meaning to Gruescript.
17
name
The screen name of the thing (same as beginning
a line in the thing block with name, as described
above)
display
The short description of the thing (same as the
text that comes after the thing’s internal name in
the first line of the thing block)
desc
The long description of the thing, used by the
examine verb (same as using desc at the
beginning of a line in the thing block)
loc
The current location of the thing. This property
should be treated as read-only. If you want to
change the location of a thing, use the command
put (see the chapter on instructions)
def
How the thing should be referred to by the
definite article (“the”). If this property does not
exist, Gruescript will simply prefix the screen
name of the thing with the word “the” (unless it
has the proper_name tag.) If you don’t want
your thing to be referred to this way, you might
set it to something like “Ford’s towel” or
“door number 2”.
indef
How the thing should be referred to by the
indefinite article (‘a’ or ‘an’). By default,
Gruescript will prepend the thing’s short
description with ‘a’, ‘an’ if it begins with a vowel
(which won’t always be right!), ‘some’ if it is
plural or a mass_noun, or omit the article if it
is a proper_name. Examples: “a unicorn”,
“lots of beer”.
18
Note that some of these, such as name and desc, overlap in purpose with
lines in the thing block that have already been explained. This is mainly
for convenience – many or most things will have screen names and
descriptions, so you need not use prop every time. name giraffe in a
thing block does exactly the same as prop name giraffe. The fact
that they also exist as properties allows them to be read and modified
during gameplay – for example, you might want to change the giraffe’s
screen name to Jeffrey after it introduces itself to the player, with
“assign giraffe.name Jeffrey” (don’t forget to change its
display property too.) There will be more on this in the chapter on
instructions.
19
Instructions
With your knowledge of rooms and things, you are now able to create a
rudimentary game world: interconnected rooms, containing things, some
of which are portable and the player can pick up, carry around, and drop
in other rooms.
While I’ve no doubt that some people would be able to make impressive
games without using any other features of Gruescript, any complex
interactions or puzzles will need to be added using verbs, setverbs,
procedures and rules. Before we can get to those, we need to introduce
something they all depend on: instructions.
Instructions are lines of code that print messages, manipulate objects,
compare variables, and so on. They will be familiar (and relatively simple)
to you if you’ve used any sort of programming language. Blocks for verbs,
setverbs and rules – which we’ll look at in depth in the following chapters
– are mostly made up of lines of instructions.
There are three kinds of instructions:
•
Commands tell Gruescript to do something, like print a message
or move a thing to a room
•
Assertions test a condition, like whether the player is carrying a
particular thing. An assertion is said to ‘pass’ if its condition is
true, or to ‘fail’ if it is false. In any series of instructions belonging
to a verb, setverb or rule block, Gruescript will start at the
beginning and run the instructions in order until an assertion
fails, then print that assertion’s message (if it has one) and stop.
•
Iterators tell Gruescript to repeat the rest of the instructions in
their block, subject to certain conditions. These are also a sort of
assertion, as they can succeed or fail.
If an assertion inside a block fails, that block itself – the verb, setverb, rule
or conditional exit – is also considered to have failed (there can be
20
exceptions to this if the block contains iterators, but we’ll get to those
later.) Conversely, if all the instructions in the block run without any failed
assertions, the block is considered to have succeeded. A block with no
instructions, or only commands, will always succeed. This will become
important in the later chapters on verbs, procedures and rules.
Most instructions have one or more ‘arguments’ – input values that are
sent to the instruction when it is called. These can be numbers (integers
only), names of things or rooms (use the internal names), variable names,
or strings (of words). An instruction’s arguments are supplied after the
instruction name itself, separated by spaces. Strings always come last, so
there is no need for quotemarks or other delimeters. (Whitespace in
strings is always normalised – that is, any leading or trailing spaces are
removed, and any contiguous spaces are reduced to a single space – there
is no distinction between “foo bar” and “ foo bar
”.)
Commands
A simple command line might look like:
bring football: A football smashes through the
ceiling and lands at your feet!
This starts with the keyword for the command that is being used (bring),
then supplies that command with its argument (in this case, a single
‘thing’, the football). Optionally, after a colon (:), comes a printable
message.
The Gruescript commands, shown with their arguments in italics, are:
bring thing
Move a thing to the room that the player is in.
If the player is carrying or holding the thing,
it will be removed from their inventory and
placed ‘on the floor’
21
hide thing
Set a thing’s ‘location’ to nothing, so that it is
effectively removed from the game, regardless
of where it is now (if anywhere), or whether it
is carried
give thing
Put a thing into the player’s inventory – they
will be ‘holding’ the new thing, and the thing
they were previously holding (if any) will be
returned to their main inventory
carry thing
This is identical to give, except that the
player will not be holding the thing; it will be
placed in their main inventory. The thing they
were holding, if any, will be unchanged.
unhold
Set the player's ‘holding’ slot to empty. If the
player was holding a thing, it will be returned
to their main inventory.
wear thing
Make the thing be worn by the player. If the
thing is portable and was not currently in the
player's inventory, it will be ‘given’ to them
first. If it is not portable and was not in the
player's room, it will be moved there.
unwear thing
Make the thing not worn by the player. If it is
portable, it will be returned to the player's
main inventory, but it will not become ‘held’.
put thing room
Move a thing to particular room. If the player
was holding or carrying the thing, it will be
removed from their inventory.
22
putnear thing
thing
Move the first thing to the location of the
second thing. If the first thing is being held or
carried, it will be removed from the player’s
inventory. If the second thing is being held or
carried, the first thing will be put into the
room that the player is in.
goto room
Move the player to a room
swap thing
thing
Swap the locations of two things. This treats
‘held’ and ‘carried’ as if they were locations,
so if the player was holding/carrying one
thing, they will now be holding/carrying the
other.
tag thing/room
tag
Add a tag to a thing or room’s tag list. If it
already had this tag, there is no effect.
untag
thing/room tag
Remove a tag from a thing or room’s tag list.
If it did not already have this tag, there is no
effect.
tagroom tag
Add a tag to the tag list of the room the player
is in. If the room already had this tag, there is
no effect.
untagroom tag
Remove a tag from the tag list of the room the
player is in. If the room did not already have
this tag, there is no effect.
clear tag
Remove this tag from all things and rooms
that have it
assign variable
value
Set a variable to a value, which must be a
number or a single word.
23
write variable
string
Set a variable to a string, which can be any
number of words and may include braced
expressions (see below)
add variable
number
Add a number to the value of a numeric
variable. Like all numbers in Gruescript, the
number must be an integer. If you need to
subtract a number, add a negative value.
random variable
number
Set the value of a variable to a random integer
from 1 to the specified number (inclusive) –
the equivalent of rolling a single n-sided die
freeze variable
This evaluates any braced expressions (see
below) in a string variable and then re-assigns
the result to the variable, effectively ‘freezing’
the value of the valuable so that it will no
longer be affected if the values of the
variables in the expressions change
say string
Print a message, in a single paragraph. The
string is output as HTML, so it can contain
markup (but not colons! Use CSS classes rather
than inline style.) It can also include braced
expressions (see below).
sayat room
string
Print a message only if the player is in the
specified room.
24
die string
End the game, printing the string between
triple-asterisks *** like this ***. If
the string is omitted, the message will be “I
am dead” or “You are dead”, depending
on whether the game is in the first or second
person. (This doesn’t have to represent the
actual death of the player character in the
game universe; for a notable counterexample,
this will usually be the command you use to
tell the player when they win the game.)
open room
direction room
Add a new exit to the first room, in the
specified direction, leading to the second
room. The direction will usually be one of the
‘regular’ compass directions, but it can be
anything. If the room already has an exit in
that direction, the room that it leads to is
changed to the one specified here (if
different).
close room
direction
Remove the exit from the specified room in
the specified direction. If the room does not
have an exit in that direction, this has no
effect.
25
status string
Sets the contents of the status bar at the top of
the game window. If this contains a vertical
line character (‘|’), the content to the left of
the vertical line will be displayed on the left of
the status bar, and the content to the right of
the bar (if any) will be displayed on the right
of the status bar. If there is no vertical bar, the
whole text will be displayed on the right. The
string may include braced expressions, in
which case the status bar will keep updating
to reflect any relevant variable changes. (If
you want to print a vertical line in the status
bar, use the HTML entity ‘|’.)
pick variable
lister
A lister is a kind of keyword that generates
lists from its own arguments. These will be
explained below.
This command picks one of the values in the
list and assigns that value to the variable.
count variable
lister
Count the values in the list and assign that
numeric value to the variable
run procedure
values...
Run the specified procedure (which must be
defined elswhere by at least one proc block.)
The values (if any) given after the procedure
name will be passed to the procedure as its
arguments (if it has them). It does not matter
whether the procedure succeeds or fails.
26
log words...
Print the words (there can be any number of
them) to the Gruescript console. This is
intended as a debugging aid and has no help
during gameplay. In an exported game, the
words will be logged to the JavaScript
browser console. Note that the argument is
not a string, so it cannot contain braced
expressions, but any or all of the words may
be variable or property references (see below.)
If, after a command on the same line, there is a colon (‘:’) followed by a
message, that message will be printed after the command is run. (You
cannot use a ‘raw’ colon in a string supplied to a command, such as say –
if you want Gruescript to output a colon, use the HTML entity
‘:’.) The message is always printed, regardless of whether the
command had any effect. Like other strings, it can contain arbitrary HTML
(avoiding colons!) and braced expressions, which we will get to later in
this chapter.
Listers
The listers are:
carried
Every item that the player is carrying
things
Every thing in the game
rooms
Every room in the game
tagged tag
Every thing or room with the specified tag
here
Every thing in the player’s current room (not
counting things that are carried by the player)
inscope
Every thing in scope (i.e. in the player’s room
or carried by the player)
27
in room
Every thing in the specified room
these value...
Any number of values can be specified. The
iteration list contains each of the specified
values (you can include the same value more
than once, if you like.)
numbers number
number
The iteration list will consist of consecutive
numbers, starting from the first specified
number and ending at the second (inclusive),
counting either up or down depending on
whether the second number is greater than or
less than the first. (If the two numbers are
equal, the iteration list will contain only one
number.) So numbers 1 5 will produce the
iteration list 1, 2, 3, 4, 5 in that order, and
numbers 6 3 will produce 6, 5, 4, 3.
So, for some examples of commands using listers:
pick beatle these john paul george ringo
will assign one of those names (they might be things, or room names, or
just words) to the variable beatle.
count inventory_weight carried
will assign the number of things the player is carrying to
inventory_weight.
Assertions
The Gruescript assertions, with their arguments, are:
carried thing
The thing is in the player’s inventory (held or
not)
28
held thing
The player is holding the thing
here thing
The thing is in the same room as the player
(but not carried)
inscope thing
The thing is ‘in scope’ – that is, either in the
same room as the player, or the player is
carrying it
visible thing
The thing is in scope, as above, and the player
can see (i.e. the special variable cantsee is
zero)
at room
The player is in the specified room
thingat thing
room
The specified thing is in the specified room,
regardless of whether it is carried
near thing
thing
The two specified things are in the same
room, regardless of whether either or both of
them are carried
has thing/room
tag
The specified thing or room has the specified
tag in its tag list
hasany
thing/room
tag...
(tag... means that any number of tags may
be listed.) The specified thing or room has at
least one of the listed tags
hasall
thing/room
tag...
The specified thing or room has all of the
specified tags
taghere tag
The room that the player is in has the
specified tag
29
cansee
The player can see; that is, the value of the
special variable cantsee is zero. (Remember
that this is the same as that variable having
never been set.) This is not related to whether
the room the player is in is dark.
litroom room
The specified room is currently lit. If the room
does not have the dark tag, this assertion will
always succeed. If it does have the dark tag,
this assertion will succeed if any thing in the
room is a lightsource.
is variable
string
The value of the specified variable is equal to
the specified string
contains value
lister
The list includes the value. This uses the same
listers, with the same arguments, as the pick
and count commands (above).
chance number
number
This succeeds on a random chance of the first
number ‘in’ the second number. For example,
chance 1 4 will succeed one time in four,
or chance 2 3 will succeed two thirds of
the time. (If the first number is equal to or
greater than the second number, it will always
succeed.)
eq value value
The two values are equal. This assertion, like
its friends gt and lt, is only useful if one of
the values is supplied by referencing a
variable with $ (see below).
gt number
number
The first number is greater than the second
number
30
lt number
number
The first number is less than the second
number
isthing value
The value is the internal name of a thing
isroom value
The value is the internal name of a room
continue
This assertion always ‘fails’. The point is that
you can use this in a verb block to ensure that
Gruescript ‘continues’ to the next matching
block – see the ‘Verbs’ chapter.
try procedure
values...
Run the specified procedure and see if it
succeeds. The values (if any) given after the
procedure name will be passed to the
procedure as its arguments (if it has them).
This is like the command run except that it is
an assertion. It succeeds if the procedure
succeeds, or fails if the procedure fails.
js string
Evaluate and run the string as JavaScript.
Convert its return value to a boolean, and
pass the assertion if the boolean is true.
This is cheating. Please do not use it.
Any assertion can be prefixed with an exclamation mark (‘!’) to make it
the opposite assertion. For example,
!here magnet
passes if the magnet is not in the same room as the player.
Like commands, assertions can optionally be followed by a colon (‘:’) and
a message. The message is only printed if the assertion fails.
After commands and assertions, the third group of commands is the
iterators. Before we get to those, it will be usful to know how to reference
31
variables and properties, so we’ll come back to iterators later in this
chapter.
Referencing variables
Any argument given to an instruction may be a reference to a variable
(except string arguments; to supply variables as strings you need to use a
braced expression – see below.) In this case the value of that variable is
supplied as the argument. This is done by using the variable name,
prefixed with a dollar sign (‘$’). So
gt $temperature 20: It’s too cold!
passes if the value of the variable temperature is greater than 20
(otherwise, it fails and prints the message.)
Note that instructions with arguments that are variables, like assign or
is, take the name of the variable without the $. If you try something like
assign $foo 10 # DO NOT DO THIS
This will store the value 10 in a variable whose name is the current value of
the variable foo, which is perverse but not illegal.
Referencing properties
Properties of things or rooms can be referenced, similarly to variables. The
reference is made using two words connected with a single dot (‘.’) (and
no space) between them. The first word is the internal name of the thing
or room; the second is the name of the property. The value of the property
will be passed as an argument to the command. For example, if the thing
bicycle has the property model with the value Pedersen,
bicycle.model will evaluate to Pedersen.
A dollar sign is not used to reference a property, but the word(s) on either
or both sides of the dot can be variable references themselves, notated as
usual with the dollar sign prefix (‘$’). So if the variable vehicle contains
the word bicycle, then $vehicle.model will again evaluate to
32
Pedersen. With the appropriate variables set up, you could also use
bicycle.$info or even $vehicle.$info.
It is not an error to reference a nonexistent property of an existent thing
or room. Like variables, properties are considered to have a numeric value
of zero if they have not been initiated. It is an error to attempt to reference
any property of a nonexistent thing or room – in the above example, if the
variable vehicle had never been given a value, or currently had a value
that was not the internal name of a thing or room, $vehicle.model
would cause an error.
Referencing connected rooms
Similarly to referencing properties, you can reference a room’s
connections by direction. If the kitchen is west of the scullery, then
scullery.dir.west will evaluate to kitchen. Either the room or
the direction, or both, can be a variable reference, so with the appropriate
variables
you
could
use
scullery.dir.$whichway,
or
$room.dir.out, or $smell_origin.dir.$wind_direction.
Braced expressions
In any string argument, such as the arguments of the commands say,
write and status, variables can be embedded using braced
expressions – expressions contained between curly braces (‘{’, ‘}’).
There can be any number of these in a string. They cannot be nested
directly, but they can contain references to variables or properties whose
values include braced expressions of their own. If you want to output
curly braces, use the HTML entities ‘{’ and ‘}’.
Braced expressions consist of one or two words between the braces. The
‘principal word’ of the braced expression can be any literal word, or (more
usefully) a reference to a variable or property. The principal word appears
either on its own, or with another word before it, which must be an article
33
(a, an, the or your) or a pronoun reference (nom, obj, pos, ind or
ref).
If the principal word in the expression is the internal name of a thing, or is
a reference to a variable or property whose value is the internal name of a
thing, the expression will evaluate to the display name of the thing. (This
only happens with variables referenced from within braced expressions in
strings; it does not happen to variable references in other contexts.) So, if
you have a thing like
thing boss_2
name Droxar the Mighty
and a variable npc whose value is boss_2, then the instruction
say { $npc } leaps out of the shadows!
will refer to Droxar the Mighty by that name.
If the braced expression is prefixed by an article (the, a, an or your,
appearing inside the braces before the principal word and separated from it
by a space), the principal word will be prefixed with the appropriate
version of that article: if the principal world is (or is a reference to) a thing
with a def or indef property, that value will be used if appropriate;
otherwise ‘a’ will be changed to ‘an’ if the display name begins with a
vowel (or ‘an’ to ‘a’ if it doesn’t – ‘an’ behaves exactly the same as ‘a’ but
can be used for capitalisation, as explained below), or ‘some’ for plural
things or mass_nouns; ‘your’ will be changed to ‘my’ if the game is in
first person; and the article will be omitted entirely if the principal word is
(or references) a thing with the proper_name tag.
If the prefix is a pronoun reference, a pronoun will be used instead of the
thing’s name. The choice of pronoun depends on the thing’s gender and/or
plurality (i.e. whether it has any of the male, female, nonbinary or
plural tags; if none are present, the thing is assumed to be singular and
neuter, i.e. ‘it’). The pronoun references are:
34
Reference Case
Pronouns (neuter, male, female, nb, plural)
nom
nominative
it, he, she, they, they
obj
objective
it, him, her, them, them
pos
possessive
its, his, her, their, their
ind
independent its, his, hers, theirs, theirs
possessive
ref
reflexive
itself, himself, herself, themself*, themselves
So, the command
hide $victim: You sneak up on {the $victim} and
push {obj $victim} into the volcano.
will remove the thing referred to by the value of victim from the game,
and then might output
You sneak up on the policeman and push him into
the volcano.
or
You sneak up on Geraldine and push her into the
volcano.
or even (using a def property)
You sneak up on all your friends and push them
into the volcano.
depending on the value of the variable victim and the tags of the thing
that its value points to.
When a braced expression is written as part of a string into a variable,
property, tag description or the status line, the expression itself remains as
a braced expression in the string and will be evaluated whenever it is
*
I ran a thoroughly non-rigorous twitter straw poll asking nonbinary folk what
they preferred for this; most chose ‘themself’, but ‘themselves’ was a
significant minority. To give a nonbinary character ‘themselves’, you can use
plural (maybe temporarily), or give everyone a custom ref_pronoun
property and reference that, or otherwise hack around the issue.
35
output (either by say or by being displayed on a button or the status line).
If you want to keep the string as it is now, use the freeze command:
verb eat
write foo The last meal you ate was a lovely
{$this}.
freeze foo
hide $this
(note that freeze’s first argument is a variable, so it’s freeze foo,
not $foo!) will evaluate the braced expression in foo now and rewrite that
into the same variable, so foo will always display the same from now on,
regardless of how often the value of this changes.
Capitalisation in references
If a variable or property has a lowercase name, such as foo, it is possible
to refer to that variable with a different capitalisation – $Foo or $FOO –
to get the contents of that variable in Capitalised or UPPERCASE form
(unless another variable with the capitalised version of the name exists.) If
you do this with a property, you should capitalise the property name, not
the thing or room before it, e.g. banana.Ripeness or
$fruit.COLOUR. If the reference happens inside a braced expression,
and the contents of the variable or property are the internal name of a
thing (and that thing’s internal name is lowercase), the result will be a
capitalised or uppercase version of the display name.
This can also be applied to articles and pronoun references in braced
expressions. If an article is UPPERCASED, it will uppercase the name of
the thing with it (regardless of the capitalisation of the variable reference).
So if the variable fruit contains apple, and the property colour of
the apple is red:
say {The $fruit} is {$fruit.COLOUR}.
will print
The apple is RED.
36
and
say {THE $fruit} is {$fruit.Colour}.
(or the same line with $Fruit or $FRUIT) will print
THE APPLE is Red.
If you want to use uppercase with an indefinite article, ‘A’ is not long
enough to be unambiguous (Gruescript will guess that you mean to
capitalise the article only), so use ‘AN’ – it will obey the same rules as ‘a’
with respect to vowels, proper names, plurals and indef, so
assign fruit banana
say IT LOOKS LIKE {AN $Fruit}!
will print
IT LOOKS LIKE A BANANA!
Iterators
Iterators are commands that change the ‘flow’ of a block of instructions.
When Gruescript finds an iterator, it will consider the rest of the
instructions in the current block (that is, the game, verb, setverb,
proc or rule block that is currently being executed) to belong to this
assertion. It will then ‘iterate’ those instructions, running through them
one or more times. The iterated instructions can be commands, assertions
or even more iterators (in which case that iterator will, in turn, cause the
code after it to be iterated once or more, every time that iterator is called
by the previous iterator, and so on.)
The instructions below the iterator are treated like a ‘nested’ block of
instructions: upon each iteration, they will be run in turn until they are all
complete, in which case that iteration succeeds, or until an assertion fails,
in which case that iteration fails. Iterators are a special kind of assertion,
as they are considered to succeed or fail themselves after they are done
iterating. Note that a particular iteration failing does not necessarily mean
the iterator running it will fail.
37
Gruescript has three iterators. An iterator is always followed by a lister,
which creates its iteration list of things, rooms or values. The listers are the
same as the ones used by pick and count commands, with the same
arguments. The iterators are:
all
The iterator will iterate (run its instructions)
once each for every item in the iteration list.
It does not matter whether any iteration
succeeds or fails. The iterator itself always
succeeds.
sequence
The iterator will iterate for each item on the
iteration list in turn, until an iteration fails. If
all the iterations succeed, the iterator itself
succeeds. If any one iteration fails, the iterator
stops and fails itself.
select
The iterator will iterate for each item on the
iteration list in turn, until an iteration
succeeds. If all the iterations fail, the iterator
itself fails. If any one iteration succeeds, the
iterator stops and succeeds itself.
During each iteration, the special variable this will contain the current
item in the iteration list. (If this already had a value, it will be reset to its
previous value when the iterator completes, making it safe to ‘nest’
iterators or to call procedures that contain their own iterators.)
For example, the following iterator looks through all the things in the
room meadow, and causes a hungry to eat all of them, without condition:
all in meadow
say The hungry goat eats {the $this}!
hide $this
38
If we wanted to change the goat’s behaviour so that it is a little more
discerning, and only eats things with the tag edible, we can simply add
a condition to the block:
all in meadow
has $this edible # if this assertion fails,
proceed to next iteration. Otherwise...
say The hungry goat eats {the $this}!
Or, if we want it to eat a maximum of one thing, we could use select:
select in meadow
has $this edible # otherwise fail this iteration
say The hungry goat eats {the $this}!
# the iteration succeeds, so the sequence stops
and succeeds
On the other hand, if we want the goat to eat everything available for as
long as it can, until it attempts to eat something that is not edible, we
could use a sequence:
sequence in meadow
say The hungry goat eats {the $this}!
has $this edible: Oh dear, it looks ill. # if
this assertion fails, so does the sequence.
# Otherwise, the sequence is still going!
say It licks its lips and looks for more food.
As an iterator itself an assertion, the block it belongs to will fail if the
iterator does. It can be prefixed with ‘!’ to make it the opposite assertion
(this does not affect how the iteration itself or the instructions below it
behave), and it can be postfixed with ‘:’ followed by a string that will be
printed if the assertion fails. This will appear on its own line, after any
output from the iterated instructions.
Changing the order of iteration
An iterator command may include an orderer, which changes the order in
which the items in the iterator list are processed. This appears
immediately after the iterator keyword itself, before the lister.
39
The three orderers are:
forward
Do not change the order. This has no effect,
but is included anyway.
backward
Reverse the order of iteration
shuffle
Randomise the order of iteration
So, the instructions
all backward these Larry Curly Moe
say { $this }
will print:
Moe
Curly
Larry
but
all shuffle these Larry Curly Moe
say { $this }
might print the names in this order:
Curly
Larry
Moe
or any other order (but each name will be printed exactly once.)
40
Verbs
Verbs are the basic unit of interaction in Gruescript games. The player can
always see, in the ‘room’ window, the directions and verbs available to
them.
Verbs can be defined in two ways: specific to an object (‘specific verbs’) or
without an object (‘general verbs’). When the player clicks on a verb next
to an object, Gruescript will first look for specific verb definitions
matching that verb for that object, and then for general definitions of the
verb. Gruescript then goes through each of those definitions in turn,
running its instructions, until one ‘succeeds’.
In addition to any user-defined verbs, there are six native verbs, which
always succeed: take, drop, examine, wear, remove, and wait.
Here’s an example of a thing, and a specific verb that works with it:
thing guitar
has portable
cverbs play
verb play guitar
say It goes TWANG!
As play is listed in the guitar’s cverbs, the player will see a ‘play’
button listed next to the guitar whenever it is carried. In this case, the
effect of playing the guitar is simple: it prints a message.
Suppose we wanted to define ‘play’ in a more general way.
thing guitar
has portable instrument
cverbs play
thing piano
has instrument
verbs play
41
verb play
say You extract a strange sound from {the
$this}!
Now the guitar and the piano both have the verb play (in the guitar’s
case, only when it is carried) but, because there is no specific verb for
either play guitar or play piano, The general verb play is used.
While a verb’s instructions are being executed, the special variable this
always contains the object of the verb – that is, the noun that the player
has clicked a button next to. So the say instruction in the general
verb play block will refer to either the guitar or the piano, whichever
is being played.
If Gruescript finds multiple verb blocks that match the player’s command,
it will run through them all (specific first, then general) until one succeeds,
then stop.
This means we can do something like this (using more variables):
verb play piano
set noise plink plonk
continue
verb play guitar
set noise kraang
continue
verb play
say It makes a noise like “{noise}”!
Verbs with directions
Verbs can be used to interfere with player movement, such as to make an
exit from a room impossible until a certain condition is met. For this
purpose, the verb is considered to be go. There is no object (so the verb
block must be general), but the direction of travel is available in the special
variable direction. As with any verb blocks, if a block succeeds, the
42
execution of the verb stops. So, to block an exit, you need to create a verb
block that succeeds:
verb go
direction north
at parlour
here gorilla
The gorilla stands in the way of the door.
If you want to allow the travel, use continue to make the block fail:
verb go west
at ocean_beach
say You dive into the sea and swim west...
assign swimming 1
continue
Or you can mess with the action entirely:
verb go
eq $lost 1
taghere outside
say You wander around the city at random...
random lostwalk 3
continue
verb go
eq $lost 1
eq $lostwalk 1
goto park
verb go
eq $lost 1
eq $lostwalk 2
goto graveyard
verb go
eq $lost 1
eq $lostwalk 3
goto abandoned_building
43
Setverbs
Setverbs are crucial to Gruescript’s keyboardless interface – they tell
Gruescript when to activate or de-activate particular verbs for particular
things. They look very similar to verbs – in fact, apart from beginning
with setverb instead of verb, their syntax is identical. However,
setverbs should not contain commands, only assertions, and they
should not emit messages. Using a command in a setverb, or printing a
message after a failed assertion using ‘:’, is not actually an error, but it can
have highly odd results, since it is not easy to predict when these
instructions will be run. Gruescript will check setverbs at least once every
turn, and also every time the player changes the inventory item they are
‘holding’ – but on most of these occasions, not all setverb blocks will
actually be run. This is because once any successful setverb block has
determined that a certain verb is to be active for a certain thing, no other
setverbs will be checked for that thing-verb pair.
Like verbs, setverb blocks can be specific or general, depending on
whether they specify a thing in the first line. In a general setverb (with no
thing), you can use the contextual variable this to refer to whatever
thing is currently being considered. So
setverb cook
hasall $this food raw
here oven
means that any thing with both the food and raw tags will have the verb
cook active if the oven is in the player’s current room. (Since verbs are
only ever visible for items that are in the player’s room, or being held, we
do not need to check whether $this is actually present.)
Specific setverbs come with a noun:
setverb cook tomato
here special_tomato_oven
will catch any attempt to cook the tomato before the general ‘cook’
setverb is checked.
44
Instead of a noun, a setverb may have the keyword intransitive. This
means that (if the setverb is successful) the verb will be active, but not
attached to any noun: it will show in the ‘Actions’ line in the room
descriptions window, along with the permanent verbs of the current room:
setverb fly intransitive
has cape worn
will make the ‘fly’ verb available anywhere.
Blocks of similar setverbs, like verbs, run until one of them succeeds – that
is, if any setverb succeeds for a given verb and a given thing (regardless of
whether it is a specific or general setverb), no further setverbs will
consider that verb and thing together. So if our Gruescript contains the
setverb example above, it will never be possible to deactivate the cook
verb for any thing with the food and raw tags if the oven is present.
Any exceptions must be accounted for in that same setverb block, or dealt
with another way. It can be helpful to use rules (see the next chapter) to
change a variable, and write a single setverb block that depends on the
value of that variable.
To keep a verb active for a thing, the relevant setverb(s) must pass
continually. Whenever setverbs are checked, all verbs are deactivated for
all things unless a setverb turns them on. The only exceptions are the
native verbs take, drop, wear and remove, which are set depending on
context, and the native verb examine, which is always considered active
for all things (although it is performed by clicking the noun, rather than
the verb) if your game has examine on.
45
Conversation
Everything in this chapter only applies if your game uses Gruescript’s
conversation system – that is, if your game block contains the line:
conversation on
If this line is not present, or is conversation off, you can ignore this
chapter and are free to implement dialogue however you wish, or not at
all.
The conversation system allows you to create more complex dialogue in
your game by switching to a more choice-based system when the player is
talking to a non-player character (NPC). While a conversation is going on,
a new pane appears in the interface, between the scroller and room
description. This specifies who or what the player is talking to, and
contains up to three lists of ‘topics’ – essentially, a special kind of verb –
that the player can ‘ask’, ‘tell’ or ‘say’. Finally, there is a button to end the
conversation.
For the purpose of the conversation system, an NPC is any thing with the
tag conversation. It is likely (but not necessary) that you will also
want to give it the tag alive, and one of male, female or nonbinary
to set the character’s pronouns. An example:
thing mrs_ft Mrs Fothertonhayes-Cranstanley
name mrs fothertonhayes-thomas
loc pta_meeting
tags alive female conversation
prop start_conversation "How may I help you?" \
asks Mrs Fothertonhayes-Cranstanley, looking \
down her nose at you.
prop end_conversation \
Mrs Fothertonhayes-Cranstanley gives you \
a curt nod.
46
The
special
properties
start_conversation
and
end_conversation contain strings that will be printed when the
player starts or ends a conversation with this NPC. If they are not present,
default messages are used: “You start talking to (the NPC).” or “You stop
talking to (the NPC).” (or their first-person equivalents, in a game with
person 1.)
When the player ‘talks’ to Mrs Fothertonhayes-Cranstanley, they will see
something like:
Talking to: Mrs Fothertonhayes-Cranstanley
Ask about: [history] [geography]
Tell about: [husband] [burglary]
Say: [club password]
[end conversation]
The ‘end conversation’ verb will hide the conversation panel. It will also
disappear if the NPC that the player was talking to is no longer in scope,
either because the player walked to another room or the NPC was moved
somewhere else, or if the player begin another conversation by talking to a
different NPC. If the conversation ends by any means other than the
player clicking ‘end conversation’, the NPC’s end_conversation
message will not be printed.
During the conversation, the room description and inventory are visible as
normal, and the player can continue to use whatever other verbs are
available in the room. The special variable conversation will contain
the internal name of the NPC. If you want to force the conversation to end
without removing the NPC,
assign conversation 0
will do so.
47
You are free to treat talk as an ordinary verb, including ‘overriding’ it
with specific or general verb blocks (the object is the NPC), or adding it
with a setverb to other things, such as simple NPCs that you don’t want to
make a complex conversation tree for (just leave out the conversation
tag.)
Asks, tells and says are defined by setverb and verb blocks, the same as
ordinary verbs. The ‘object’ of ask, tell or say is considered to be the
conversation topic, which can be a thing name or any arbitrary value. You
can change the display of these ‘verbs’ with display and prompt, and
do anything else that you can do in ordinary verb and setverb blocks.
Regardless of setverbs, ‘ask’, ‘say’ and ‘tell’ will only be considered for
activation when a conversation is open. They are not tied to particular
things. So,
setverb ask alibi
will mean you can “ask about alibi” when talking to any NPC, and you do
not need to worry about the verb becoming active for other things.
To make asks, tells or says that are specific to a particular NPC, use verbs
that begin with ask_, tell_ or say_, followed immediately (no space)
by the internal name of the NPC. So:
setverb ask_mrs_ft hat
will make ‘hat’ an available ‘ask’ topic for Mrs FothertonhayesCranstanley, and nobody else, whether or not the hat is actually a thing.
As usual, the setverb block can contain instructions:
setverb ask_mrs_ft hat
has mrs_ft wearing_hat
will succeed, and activate the topic, only if she has the wearing_hat
tag.
48
Verb blocks can be made the same way. Any ask_, tell_ or say_ verb
blocks with an NPC will be considered before any ask, tell or say
blocks without, with execution stopping after a success as usual, so
verb ask_mrs_ft hat
say "I inherited it from a particularly dreadful
great-aunt,"
she says. "Elegant, isn't it?"
verb ask hat
say "It makes her look like a tree," says {the
$conversation}.
will print the first message when talking to Mrs FothertonhayesCranstanley, and the second message when talking to anyone else. Any
general verb ask blocks would be considered after either of them.
General setverb ask or setverb_ask_topic are also allowed:
verb ask_fish_expert
has $this fish
will activate “ask fish expert about” for every thing with the fish tag,
and
verb ask
has $this hot_topic
will make any thing with the hot_topic tag available as an ask for
everyone with conversation. Note that in these cases, only ‘things’
will be considered. If you want to do this other topics, create ‘dummy’
things.
By using variables, properties or tags in conversational verbs and setverbs,
it is possible to create quite complex conversation trees.
49
Procedures and rules
Procedures
Procedures consist of a name and a group of instructions. A simple
example:
proc do_cat
bring cat
say The cat appears and meows at you.
This can then be ‘called’ by its name, either with the command
run do_cat
or the assertion
try do_cat
This can be anywhere that instructions are allowed – a verb, setverb, rule,
the game block, or another procedure. A procedure can even call itselff
(although if it does, you should take care to avoid infinite loops.)
The difference between run and try is that run is a command and try
is an assertion. run will always just run the procedure, and then the next
instruction after the run (if any) will be executed. try will succeed or fail
depending on whether the procedure succeeds or fails; like any assertion,
if try fails, the block it is in will also stop running and fail.
There can be several proc blocks with the same name. In this case, when
that name is called by run or try, the proc blocks will be run one after
the other, in the order that they appear in your Gruescript source, until
one of them fails. (Even when called from run, a procedure block can fail
and stop this execution; the only difference is that run itself is not an
assertion and cannot fail.) try will succeed if all the procedure blocks of
the specified name succeed, or fail as soon as any one of those blocks fails.
50
Arguments
Procedure blocks can have arguments. These are variables that are ‘local’
to the procedure block, which can be given specific values when calling
the procedure with run or try. For example, given a procedure
proc say_clothing_colour item colour
say You are wearing a {$item} {$colour}.
then calling it with
run say_clothing_colour tie red
will print
You are wearing a red tie.
You could also pass variable values to the run command in the usual way:
run say_clothing_colour $neckwear
$neckwear_colour
Any ‘global’ variables with the same names as the arguments will not be
affected (and will not be accessible from the procedure block). If variables
called item or colour existed before the procedure was called, they will
have their original values again after the procedure is executed.
You do not have to specify all (or any) of the arguments when calling a
procedure. If an argument is not specified by a try or run instruction,
procedure blocks with that argument will treat its value as zero (even if it
had a 'global' value already.) If the try or run instruction contains more
values than a procedure block has arguments, the block will ignore the
extraneous values.
Note that strictly speaking, arguments are ‘local’ to a procedure block, not
a whole procedure! It is possible, but probably not wise, to have multiple
blocks for the same procedure with completely different arguments; each
block that is executed will be passed the same values in the same order,
but it is the first line of the block that decides which values go into which
arguments. Also note that changing the value of an ‘argument’ variable
51
within the procedure will not affect the value being given to other blocks.
So, given the multi-block procedure
proc counting num
say {$num}...
add num 1
say ...{$num}...
continue
proc counting num
say ...{$num}!
the instruction run counting 1 will print
1...
...2...
...1!
not ...3! on the last line.
Variables that are not named as arguments in a procedure block are treated
as ‘global’, identical to the same variables in all other contexts. Changing
their value in the procedure block will change them everywhere.
Arguments allow procedures to be recursive:
proc countdown num
eq $num 0
say BLAST OFF!
proc countdown num
say {$num}...
add num -1
run countdown $num
Rules
Rules are procedures that are run every turn, beginning at the end of the
player’s first turn. They are like procedures, but have no name or
arguments; their first line consists of the word rule on its own. Every
52
rule runs its instructions until they run out or an assertion fails; whether a
rule block fails or not makes no difference, except to where its instructions
stop. Rules run in the order that they are declared in the Gruescript source.
53
Special variables
Gruescript keeps track of the following special variables. You should only
use them for reading and not writing – writing is not illegal, but will have
unpredictable results. Generally there is a right way to change things; for
example, rather than assign room laboratory, you probably want
goto laboratory.
verb
The internal name of the last verb used by the
player. If they moved in a direction, this is go.
thing
The internal name of the object of the last verb
used by the player, i.e. the thing that they clicked
a verb next to (or on, for examine.)
this
The thing currently being considered by a verb or
setverb. When used in a verb block, this will
always have the same value as thing. When
used in a setverb block, it is the thing
Gruescript is currently considering activating the
verb for – its value is unpredictable, but it will
stay the same on any one run through any one
setverb block. It should not be used in rules.
direction
The last direction travelled, or the direction
currently being travelled, by the player.
held
The thing the player is currently holding. If they
are not holding anything, this has a numeric value
of zero.
room
The room that the player is currently standing in.
54
cantsee
If this value is zero, the player can see. If it is 1 (or
anything else) they cannot. Remember that a
value of zero is the same as having never been set.
The player being innately unable to see is not the
same as the room being dark – these two concepts
are independent of each other. This variable
should be used for things like being temporarily
dazzled or wearing a blindfold. Unlike the other
special variables, it is safe to write to cantsee –
in fact, the correct way to change its value is to do
so. (The assertion cansee exists as shorthand for
“eq $cantsee 0”)
score
maxscore
By default, the value of these variable will be
shown as score/maxscore (e.g. “0/5”) at the
right of the status bar. If the value of maxscore
is zero, only the score will be shown. This can be
overridden by the status command.
Visible tags
Tags can be made ‘visible’ by using a tagdesc block. This is a single line
consisting of the identifier tagdesc, followed by the name of the tag
and then a string that will be printed, in parentheses (like this),
after the thing when it appears in a room description or the player’s
inventory. If the string is omitted, the name of the tag is used, with
underscores replaced by spaces. This can be done with special tags like
lightsource; this adds the printed message but does not affect the
behaviour of the tag. Examples:
tagdesc bargain labelled "half price"
tagdesc lightsource providing light
tagdesc broken
55
Tags for rooms are never visible (change the room’s desc property
instead.)
56
Appendix I: Visual configuration
The game block may contain colour lines which determine the colours
used by the game. You can spell it color if you like. These lines take the
form
colour colour-area HEXCODE
where colour-area is one of the below:
statusbar_background
statusbar_text
main_background
main_text
main_prompt
main_text_old
main_prompt_old
instructions_button
instructions_button_text
room_background
room_text
room_button
room_button_text
conversation_background
conversation_text
conversation_button
conversation_button_text
examine_button
examine_button_text
inventory_background
inventory_text
inventory_button
inventory_button_text
inventory_inactive_text
save_background
save_button
save_button_text
page_background
Most of these are (hopefully) self-explanatory. Note that the save...
colour-areas apply to the part of the page containing the ‘save’, ‘restore’,
‘restart’ and ‘undo’ buttons, and all those buttons – with the default
colours, its background is the same as page_background – and
inventory_inactive_text usually applies only to the button in
your inventory that corresponds to the thing currently held by the player.
Messages in the scroller appear in the main_text colour initially, then
change to main_text_old (usually a dimmer colour) on subsequent
turns. main_prompt and main_prompt_old apply to the mock
‘command prompts’ echoed in the scroller.
57
HEXCODE is a three- or six-digit colour code. It is not preceded by ‘#’ –
that would make it a comment! It can also be a css colour name like red.
For advanced visual configuration, you can apply whatever CSS you want
to your game’s HTML page once you have downloaded it. You can also
change the layout of the page itself, as long as it keeps the div elements
that Gruescript uses: topbar_left, topbar_right, scroller
(containing scroller_content), room_description, holding,
inventory, save_prompt, restart_prompt, save_load, and
saved_games and options.
58
Appendix II: Cloak of Darkness
Roger Firth’s Cloak of Darkness is a small game that has become a sort of
reverse Rosetta stone for interactive fiction authoring systems: it is
traditional to rewrite Cloak of Darkness in any new authoring system, in
order to give an overview of how that system deals with common game
elements.
The specification of the game is deliberately simple: the player begins the
game in the foyer of an opera house, wearing a cloak. There are two other
rooms, a cloakroom and a bar. Entering the bar, the player finds that the
room is dark; if they remove their cloak and (optionally) hang it on a hook
in the cloakroom and then go back to the bar, they will find the bar is now
lit. If they did not spend too long in the bar while it was dark, they will
now see a message written in the dust telling them they have won the
game; otherwise, they have scuffed out the message, and lose the game.
A Gruescript version of Cloak of Darkness goes something like this…
# Game metadata and global parameters
game Cloak of Darkness
id CLOD
# The game ID is used to identify saved games in
# browser storage. This should be different for
# each of the Gruescript games on your site, so
# they don’t interfere with each others’ saves.
author Roger Firth, adapted to Gruescript by Robin
Johnson
version 0.0.1
person 2 # "You are in..."
examine off
# custom status line. On the left, display the
# player’s current room; on the right, whether
# they are wearing the cloak – we’ll use a
# variable called ‘cloaked’ for this.
status { $Room | $cloaked }
59
# a portable item, the cloak
thing cloak pitch-black opera cloak
carried # starts in inventory
tags portable wearable worn
# These are all special engine-recognised tags:
# ‘portable’ means it can be picked up and
# dropped; ‘wearable’ means it can be worn (if
# carried) and removed (when worn); ‘worn’ means
# the player is wearing it at the start of the
game.
# the ‘cloaked’ variable, which we are displaying
# on the status bar, and a rule to set it
var cloaked Cloaked # its initial value
rule
assign cloaked Cloaked
!has cloak worn
assign cloaked Uncloaked
# rooms
room foyer You're in the foyer of the Opera House.
tags start # the player starts here
# directions to other rooms
south bar
west cloakroom
north foyer
# ‘north foyer’ is a dummy direction, so that the
# button appears: attempting to go north will be
# caught by the following verb block:
verb go north
at foyer
say But you've only just arrived!
# This verb block always ‘succeeds’, effectively
# blocking the action.
room bar You're in the bar.
north foyer
tags dark # this room is dark
60
# The bar should be dark unless the cloak is
# elsewhere. Because a rule block will fail when
# an assertion inside it fails, the easiest way to
# do this in a single rule is to make the bar
# dark, then “un-make it dark” if the conditions
# are met.
rule
tag bar dark
!thingat cloak bar # includes carried/worn
# The ‘!’ prefix negates the assertion, so if the
# cloak is NOT at the bar, the rule will continue:
untag bar dark
# If we are in the bar and it’s dark, increase the
‘mess’. The player gets one warning.
rule
at bar
has bar dark
add mess 1
!eq $mess 2: You should probably go back out to the
foyer – you wouldn't want to accidentally
disturb anything in the dark.
room cloakroom You're in a small cloakroom.
east foyer
# a non-portable item
thing hook brass hook
loc cloakroom
# determine when to activate the verb ‘hang’.
# In a parser game, the player would type
# “hang cloak”, not “hang hook”. We’ll use
# ‘display’ and ‘prompt’ to make the mock prompt
# look like that, but we’ll actually attach the
# verb to the hook, not the cloak.
# This is a little more intuitive: you ‘hold’ the
# cloak, and then look round the ‘room’ for
# something to attach it to.
61
setverb hang hook # when to activate 'hang' verb
for the hook
!eq $held 0 # check we’re holding *something*
# (the contextual variable ‘held’ contains the
# item being held, or 0 if none.)
has $held wearable
# *any* wearable garment(s) can be hung on the
# hook. (There just happens to be only one in the
# game.)
verb hang
display hang {$held}
prompt hang {$held} on {$this}
# we’ll use an author-defined tag, ‘hooked’, to
# make something show if it’s currently hanging
# on the hook. It doesn’t change any other
# behaviour (you can still pick it back up
# normally with ‘take’), so this is
# straightforward.
tag $held hooked
say You hang {the $held} on the {the $this}.
put $held $this.loc
# create a ‘visible tag’
tagdesc hooked on hook
# taking anything that is 'hooked' removes that
# tag
verb take
untag $this hooked
continue
# ‘continue’ forces this verb block to fail, so
# the native verb ‘take’ will pick it up
thing dust dust (on floor)
loc bar
# The game ends when the player is in the bar and
# the bar isn’t dark; whether they win or lose
# depends on how much mess they’ve made in the
# bar.
62
rule
at bar
!has bar dark
lt $mess 3
say A message is scrawled in the dust! It
reads:
die You win # end the game
rule
at bar
!has bar dark
# There is no need to check $mess here – if it is
# less than three, the assertion in the above rule
# would already have passed, and the game ended.
say A message is scrawled in the dust!
say What a pity, it's too scuffed to read.
die You lose
63
Download