This is one of those works-in-progress. It isn't complete. It isn't thorough. It isn't finished. The word TODO is used frequently. And I'll probably try to port it to IFWiki.
This is my attempt to compare, on a feature-by-feature basis, most of the main IF languages in use today: ADRIFT, Inform 6, Inform 7, Hugo, Quest, TADS 2, and TADS 3. I am intrigued by the intellectual challenge. Each language uses different approaches to the many requirements of an IF work, and I want to know how are they different, and what stays the same.
Plus, I'm curious how I might compare them, how I might organize such a thing. What if a TADS operator's functionality is served by a function call in Hugo? Or if an object attribute in Inform corresponds to an object class in TADS? Sometimes, a low-level feature in language A has no direct comparison in language B because language B uses a completely different high-level approach; how to represent that?
There's also the practical usage of such a comparison when migrating from one language to another. I know how to readily create a reasonably nice program using Inform, but not in any of the other languages. Perhaps this comparison will help me or others learn a new language, or assist with the porting of existing IF programs. Anyone who is tempted to create RAIF-POOL (an unlikely program that can freely translate between the IF languages automatically) will need to go much further than this document proposes to go; that theoretical RAIF-POOL creator will not only have to resolve the conflicts between the languages, but also divine the intent of someone else's game code.
The reader will notice that I haven't included ADRIFT in this comparision. Although ADRIFT is a commonly-used IF development system, it isn't a language in the usual sense, and thus, it's not obvious to me how to represent its features here. I definitely do not want to insert screenshots. So, until I figure out how to get around that, I'm just going to skip ADRIFT for now. There's quite enough work to do with all the other languages as it is.
[TODO: Explain ground rules; that I'm using standard libraries wherever possible, that sort of thing.]
[TODO: Talk a bit about ALAN 2 and Alan 3]
[TODO: Talk a bit about Hugo]
[TODO: Talk a bit about Inform 6]
[TODO: Talk a bit about Inform 7]
[TODO: Talk a bit about TADS 2]
[TODO: Talk a bit about TADS 3]
[TODO: Explain my own syntax]
token?
token
is optional; may occur 0 or 1 times.
token+
token
is required, and may occur several times.
token*
token
is optional, yet may occur several times.
NL
literal newline.
Addition of two numeric values is usually done with an operator, and that operator is usually a plus sign.
x + y
($A plus $B into $C)
A and B must be bound to numbers; C is unified with their sum. If the result is outside the valid range of numbers, the query fails.
X + Y
X plus Y
<+ integer1 integer2>
<ADD integer1 integer2>
Possibly you're allowed to add more than two arguments with this built-in instruction; I'm not really sure.
Not applicable.
&function
&object.property
&function
&property
&property
Not available.
array arrayname [ size ] ! elements 0 to size-1
(to initialize:)
arrayname [ startindex ] = val [, val]*
Arrays may contain a mix of datatypes. Local arrays are illegal.
(property array:)
propertyname val+
(global array:)
Array arrayname --> size ; ! empty array; 0 to size-1
Array arrayname --> val val* ; ! filled array
Array arrayname --> "chars" ; ! char array
Array arrayname table size ; ! empty wordarray; puts size in arrayname-->0; elements 1 to size.
Array arrayname string "chars" ; ! char bytearray; puts length of string in arrayname->0; elements 1 to length.
Replace -->
with ->
to get a byte array.
Wordarray elements may be integers, strings, chars, dictionary words, or object references.
Bytearray elements may only be integers from 0 to 255, or chars.
Use tables as directed in chapter 14. Tables are declared in a single paragraph with no blank lines inbetween rows.
The first row must be the title line in one of three formats, eg:
Table code
Table of Whatever
The second row must be the column header names separated by tabs.
The remaining rows are the table entries, columns separated by tabs.
All values in a column must have mutually compatible datatypes, eg: you can't have strings and numbers in the same column.
Rows are numbered from 1; columns are refered to by their names.
Table code - Whatever
[ listitem* ]
Lists may be empty. Lists may contain a mix of subtypes. Listitems may be explicitly separately by commas. If the list is the value of a property, all listitems in the list must be constant values (eg: integers, single-quoted strings, constant lists); otherwise, a list may contain expressions.
[ ] // for an empty list
[ listitem [, listitem]* ]
Same as in TADS 2, except listitems must be separated with commas. If the list is the value of a property, all listitems in the list must still be constant values; however, the compiler will translate
theProp = [rand(3), foo.location]
into
theProp { return [rand(3), foo.location]; }
That is, how to refer to an array/list when it's the value of an object's property.
Not applicable.
object.&arrayproperty
object.property
By "array operations", we mean any predefined functions, operators, and statements that manipulate arrays in any way.
Not applicable.
Returns array
's length:
array[]
If the array is a property of an object, you can do this:
object .# arrayproperty
length(list)
list.length()
By default, Inform 6 attempts to guess
"a" or "an" for the indefinite article based on the item's short name's
first character. Give the proper
attribute to an item if no
article is appropriate. Set the article
property of an item
to the appropiate string value to override the default indefinite
article. Set the articles
property of an item to a list of
string values to explicitly declare all articles of an item (this last
is meant for non-English games). Use the (The)
, (the)
,
and (a)
functions to print item's names with articles.
By default, the values of a thing's
adesc
and thedesc
properties are "a <<self.sdesc>>"
and "the <<self.sdesc>>"
respectively. Give these properties new values to override their default
values.
SET x TO n.
x = n
x := n // default style
x : n // C mode style
For convenience, some programming languages provide some operators that are one operator combined with the assignment operator.
No combos available. Instead, use:
SET a TO a op b.
Hugo's assignment combos are:
+= -= *= /= &= |=
No combos available. Instead, use:
a = a op b
TADS's assignment combos are:
+= -= *= /= %= &= |= ^= <<= >>=
There are many choices of programming languages or environments to create a work of interactive fiction with. Some of the systems are listed below (not an exhaustive list by any means):
This operation tests if a numerical value is between two other values (inclusive). Most authoring systems don't have a built-in operator for this. Programmers are usually comfortable using a combination of their system's less-than-or-equal-to and the logical-AND operators to do the job.
n BETWEEN x AND y
x <= n && n <= y
x <= n and n <= y
Not supported.
a & b
Learning ZIL mentions a BAND
instruction
(in a bare list of "other instructions") and to see the YZIP Spec for more information.
YZIP was Infocom's interpreter for Z6 games. Because it also lists BTST
, BOR
, and BCOM
,
I assume BAND
means bitwise AND.
Not supported.
~a
Not supported.
a | b
Learning ZIL mentions a BOR
instruction
(in a bare list of "other instructions") and to see the YZIP Spec for more information.
YZIP was Infocom's interpreter for Z6 games. Because it also lists BTST
, BAND
, and BCOM
,
I assume BOR
means bitwise OR.
Not supported.
Not specified, but here's a workaround:
((a | b) & ~(a & b))
a ^ b
Also known as "binary constants" or "truth values". Boolean variables are sometimes called "flags".
Not specified. Use 1
and 0
instead.
Use true
and false
. These are equal to 1 and 0, respectively.
Use true
and false
. Their kind of value is a truth state
.
Use true
and nil
.
Use T
to mean true and <>
to mean false. For example, here's how to declare two global boolean variables:
<GLOBAL SECRET-PASSAGE-OPENED <>>
<GLOBAL SLEEPY T>
Note that true and false are equivalent to 1 and 0, internally.
Not specified. Best you can do is put something like
$n$t
in front of each line of the quote.
box string+ ;
Use the <blockquote>
and </blockquote>
tags. May be abbreviated to <bq>
and </bq>
.
Use <credit>
and </credit>
around the last
line of the quote if it credits the quote's author.
Not applicable.
break
break ;
break label? ;
call var [( expr [, expr]* )]?
run object.property
By default, the carrying capacity
of the player, containers, and supporters is a maximum of 100 items.
You can easily change the capacity of something with a statement like:
The carrying capacity of the cardboard box is 6.
This article is about the single-character data type. For info about people and actors, see creatures.
In ALAN and TADS, there is no distinct Character datatype.
Just use strings; for example:
"x"
in ALAN, or 'x'
in TADS.
For example:
'x'
In Inform, be careful not to confuse character constants with dictionary words.
Use ""
for a quote character, eg: "Bob says, ""Hi!"""
Use $n
for a newline.
Use $z
for a literal dollar-sign. (Actually, put any character
after the $
, as long as that combo doesn't mean anything to ALAN.)
Use \"
for a quote character, eg: "Bob says, \"Hi!\""
Use \n
for a newline; use \\
for a literal backslash.
Accents, eg: \`a
= à;
\'e
= é; \^o
= ô;
\:u
= ü; \,c
= ç; \~n
= ñ.
Also: \<
= «; \>
= »;
\!
= ¡; \?
= ¿; \ae
= æ;
\AE
= Æ; \c
= ¢; \L
= £;
\Y
= ¥; \-
= — (em-dash).
And, \#xxx
= any ASCII character where xxx is a
3-digit number.
Use ~
for a doublequote, eg: "Bob says, ~Hi!~"
Use ^
for a newline, eg: "Line one^Line two"
Accents, eg: @`a
= à;
@'e
= é; @^o
= ô;
@:u
= ü; @,c
= ç; @~n
= ñ;
@oa
= å; @\o
= ø.
Also: @<<
= «; @>>
= »;
@!!
= ¡; @??
= ¿; @ae
= æ;
@AE
= Æ; @oe
= œ; @OE
= Œ;
@ss
= ß; @LL
= £;
@th
= þ; @Th
= Þ;
@et
= ð; @Et
= Ð.
And, @@num
for other characters, where num
is the ZSCII value, eg: @@92
= \;
@@64
= @; @@94
= ^; @@126
= ~.
Plus, @{hhhh}
is a Unicode character, where hhhh
is its hex value. Originally, few interpretors (if any) supported Unicode, but now it's becoming more commonplace.
Use \"
for a quote character; \'
for apostrophe.
Use \n
for a newline; use \\
for a literal backslash.
Use \<
for < (to disambig. vs. <<
).
Use \-
followed by any two bytes to pass those bytes literally
(eg: for multi-byte characters like Japanese).
if using HTML-TADS:
Use &
for &; <
for <; >
for >.
Use named entities like é
and £
to get special characters like é and £.
Similar to TADS 2, except that it's always in HTML mode, so entity codes like
&
for '&', etc. are now required.
Also, \-
is no longer used; instead use Unicode characters,
eg: \uABCD
, where ABCD
is the hexadecimal code value.
Inform 7 calls this a kind
. You can create a new kind with a statement like this:
A planet is a kind of thing.
Make item NOT attribute .
give object ~attribute ;
Just use a normal assignment statement; for example:
now the umbrella is closed;
now the umbrella is not open;
A construction like not open
will only work in an assignment like this when
the property's kind has only two possible values.
TADS never had "attributes", just properties that can take any value, including boolean ones:
object.property = nil;
<FCLEAR object flag>
Not specified. Fake it by printing a string with 24 \n
characters in it.
cls
@erase_window window
where window
should be 0
for lower window, 1
for upper, or -1
for entire screen.
The following phrases are defined in Basic Screen Effects by Emily Short which is a built-in extension.
To clear the entire screen (including the status line):
clear the screen.
To clear only one section of the screen, we also have:
clear only the main screen.
clear only the status line.
clearscreen();
clearScreen(); // see tadsio.h
<CLEAR integer>
where integer indicates which window to clear. The main window is window 0. You can have up to 8 windows.
The basic model of clothing in most IF authoring systems is very simple:
It's also notable that clothing usually ignores any carrying capacity that the player might have. There's usually no built-in limit on how many items a character can wear.
Declare a wearable object with the wearable
attribute (see wear.i
).
Locate it in the worn
container to indicate that it's currently worn by the Hero
(see invent.i
).
Declare a wearable object with the clothing
attribute.
Give the worn
attribute to an object to indicate that it's currently worn by player
.
By default, worn
affects only the player's clothing, not an NPC's.
Use the wearable
adjective to give something the wearable
property.
For example, The bowler hat is wearable.
means the hat is an article of clothing.
(The wearable
property is equivalent to Inform 6's clothing
attribute.)
Clothing can also be defined indirectly via the verb "to wear" which asserts the wearing relation.
For example, the assertion Fred is wearing the bowler hat.
also gives the wearable property to the hat.
Declare a wearable object as an instance of clothingItem
class.
Set the item's isworn
property to true
to indicate that it's currently worn by its parent object.
Declare a wearable object as an instance of Wearable
class (see objects.t).
Set the item's wornBy
property to the object that's wearing it.
Give the WEARBIT
flag to an object to make it wearable.
Give the WORNBIT
flag to an object to indicate that it's currently worn.
Can't specify colors.
TODO. Obviously the color capabilities of the Z-machine are much more limited than Glulx's.
Verb meta? verbWord+ grammarLine+ ;
Extend only? verbWord [first | last | replace]? grammarLine+ ;
where
verbWord → dictionaryWord
grammarLine → * grammarToken* -> actionID reverse?
Predefined English Verb
directives are in grammar.h
.
VerbRule(VerbTag) grammarLine : VerbTagAction
verbPhrase = 'verb/verbing (what)? prep* (what)?'
propertyDefinition*
;
where
grammarLine → ( grammarLine )
OR grammarLine | grammarLine
OR grammarToken*
Note that VerbRule
is a macro defined in en_us.h
,
where VerbRule(tag)
becomes grammar predicate(tag):
;
and grammar
itself seems to be macro, whose definition eludes me.
Predefined English VerbRule
s are in en_us.t
.
Comments are private notes for the author's own benefit, to remind themselves of what they're trying to do with their code or why. Players normally never see these comments unless the author publishes their source code.
-- This is a comment in ALAN 2.
-- There is no multi-line comment form in ALAN 2.
%% This is a comment in Dialog. Comments run from the %% to the end of the line.
%% There is no multi-line comment form in Dialog.
! This is a single-line comment in Hugo.
!\
And this is a multi-line comment
Which goes across more than one line.
\!
! This is a comment in Inform 6.
! There is no multi-line comment form in Inform 6.
Note that Inform 7 likes to render its comments in green.
[ This is a comment in Inform 7. ]
[ And this is a multi-line comment
Which goes across more than one line. ]
[* This type of comment turns into a footnote when source code is published. ]
// This is a single-line comment in TADS.
/*
And this is a multi-line comment
Which goes across more than one line.
*/
; This is a comment in ZIL.
; There is no multi-line comment form in ZIL.
See either:
Not supported. Use an if-statement instead.
a ? b : c
a , b
Containers are objects that can contain other objects. In some systems, a container is a property or attribute of an object, but in other systems, a container is a subclass of object.
Contrast containers with supporters, which are objects which you can put other objects on top of.
Give items the container
attribute. If it is open, also give it the open
attribute.
If it's openable and closeable, also give it the openable
attribute.
A container
is a kind of thing. You can declare something as a container with a statement like:
The cardboard box is a container.
Declare items of class container
or qcontainer
. The latter is "quiet"; it doesn't list
its contents in certain circumstances. Set its isopen
property to true
or nil
as appropriate.
If the container is also openable and closeable, also declare
the container to be of class openable
.
Declare with class BasicContainer
, or Container
,
or one of Container
's subclasses. Set its isOpen
property to true
or nil
as appropriate.
Use OpenableContainer
for a container that is openable and
closeable. Customize listing behaviour thru the properties isListed
,
isListedInContents
, isListedInInventory
,
contentsListed
, contentsListedSeparately
, etc.
(see Thing
class).
Not applicable.
continue ;
continue label? ;
Inside a REPEAT
instruction, use AGAIN
to return to the beginning of the loop:
<AGAIN>
Includes actors, "animates", animals, and people.
Declare creatures with the Actor
construct.
Declare with the (animate $)
trait.
Note that the (female $)
and (male $)
traits imply the (animate $)
trait.
Give creatures the animate
attribute.
Declare creatures as instances of Actor
,
or one of its subclasses: UntakeableActor
or Person
.
Not supported. Instead, use: SET n TO n - 1.
pre-increment format:
--n
post-increment format:
n--
Learning ZIL mentions a DEC
instruction
(in a bare list of "other instructions") and to see the YZIP Spec for more information.
YZIP was Infocom's interpreter for Z6 games. If <DEC integer-variable>
isn't valid, you'll have to do something like this:
<SETG SCORE <- ,SCORE 1>>
object provides property
Use: defined(object, &property)
Note that a property pointer is passed to defined()
.
Use: object.propDefined(&property)
For room descriptions, use (look $)
.
For descriptions of things, use (descr $)
.
The description [of the-object-name] is "Some descriptive text."
If you don't include the "of the-object-name" clause, Inform 7 assumes you're implictly continuing to define the most recently named object earlier in your code.
Dialog is a new authoring system created by Linus Åkesson, first released in November 2018. It's a rule-based language inspired by both Prolog and Inform 7. The first major IF work written in Dialog is Tethered by Linus Åkesson, which was entered into the IF Comp 2018 event.
At the time of writing (November 2018), Dialog only creates works for the Z-machine 8 platform. Note also that the language is still in development and may change somewhat from its initial release.
Not applicable. Use normal and quoted variables in NAME
phrases.
Also, see the SYNTAX
construct.
eg: "x" "joe's" "silver" "keys"
Always in doublequotes. Doesn't use Inform's //p
, etc.
eg: 'x//' 'joe^s' 'silver' 'keys//p'
or "x" "joe^s" "silver" "keys//p"
The single-quoted syntax is the preferred form.
Use ^
for an apostrophe, eg: 'joe^s'
. Append //
for a single-character dictionary word,
eg: 'c//'
. Append //p
for a word that is always plural, eg: 'keys//p'
.
Nine character resolution; note that digits and typewriter symbols count as two characters,
and accented characters even more.
Not applicable. Use string constants, eg: 'x' 'joe\'s' 'silver' 'keys'
.
TODO
This article is about the exits of a room, most of which are almost always named after compass directions.
Rooms can have the properties NORTH
, SOUTH
, EAST
, WEST
,
NE
, SE
, NW
, SW
, UP
, DOWN
, IN
, and OUT
.
ZIL understands five types of exits: UEXIT (unconditional exit), CEXIT (conditional exit), FEXIT (function exit), NEXIT (non-exit), and DEXIT (door exit). Examples of each below:
(EAST TO KITCHEN)
(WEST TO STRANGE-PASSAGE IF CYCLOPS-FLED ELSE "The wooden door is nailed shut.")
(DOWN PER TRAP-DOOR-EXIT)
(NW SORRY "The royal hedge blocks your way.")
(SOUTH TO GARAGE IF GARAGE-DOOR IS OPEN ELSE "Alas, the garage door remains stubbornly closed.")
The ELSE clauses in CEXITs and DEXITs are optional; there are default refusal messages.
Division of two numeric values is done with an operator, usually a forward-slash character. Note that we mean integer division here, where any remainder is ignored and the result is also an integer.
x / y
($A divided by $B into $C)
A and B must be bound to numbers; C is unified with the (integer) quotient after dividing A by B. The query fails if B is zero.
X / Y
X divided by Y
</ integer1 integer2>
<DIV integer1 integer2>
Not applicable.
do statement NL while expr
do statement until ( expr ) ;
do statement while ( expr ) ;
Not specified. Section 6.4 of the Alan manual
suggests defining two door objects, one for each side.
Define the doors' VERB open
clauses to open both sides
simultaneously (MAKE side1 NOT closed. MAKE side2 NOT closed.
).
Also, define the EXIT
clauses in the rooms
to CHECK side1 IS NOT closed
.
Give a door object the door
,
static
, and openable
attributes, and if applicable, the open
and lockable
attributes. Set the appropriate exits in the
rooms to point to the door itself, eg: n_to green_door
.
Set the door's door_to
property to the destination room,
and the door's door_dir
property to the direction, eg: n_to
.
Optionally, define the door's when_open
and when_closed
properties.
Typically, an Inform 6 door is also defined as a floating item;
set its found_in
property to a list of the two rooms that
the door is found in. If you do this, remember to make the door's
door_to
and door_dir
properties into routines
to return the appropriate value based on self.location
.
Most doors should be declared as instances of class Door
.
(Other possibilities include SecretDoor
, HiddenDoor
, and AutoClosingDoor
.)
For normal two-way doors, declare a pair of Door
objects, one for each side of the door.
One side will be the 'master'; set the other side's masterObject
property to the first side.
For one-way doors, you will need to set the destination
property of the door. Since a Door
is also a TravelConnector
, you can easily associate a Door
with its direction of travel
by setting the appropriate direction property of the room with the door, e.g.: north = bedroomDoor
See food.
Not applicable.
The first element of a Hugo array is at index 0.
array [ index ]
The first element of an Inform 6 array is at index 0.
wordarray --> index
bytearray -> index
The first element of a TADS list is at index 1.
list [ index ]
This is about comparing two values to determine if they're equal. For setting a variable to be equal to some value, see assignment.
x = y
To check for numerical equality, use regular unification, i.e. ($ = $).
x == y
Tests if the first argument is equal to any of the others; the last two arguments are optional:
<EQUAL? integer1 integer2 integer3 integer4>
If you just want to test if a value is equal to zero, there's a special instruction for that:
<ZERO? integer>
$p
= New paragraph (one empty line)$i
= Indent on a new line.$t
= Insert a tabulation.$$
= Do not insert a space.The special characters in Dialog are
#
, $
, @
, ~
, *
, |
, \
, parentheses, brackets, and braces. Prefix with \
to print.
\_
= Forced space (overrides left-justification).\B
= Boldface on; \b
= Boldface off.\I
= Italics on; \i
= Italics off.\U
= Underlining on; \u
= Underlining off.\P
= Proportional font on; \p
= Proportional off.\
= For "folding lines" (no longer needed).\b
= Insert a blank line.\t
= Insert a tab.\space
= Literal space; overrides default spacing.\^
= Capitalize next letter; \v
= lowercase next letter.\(
= Highlighting on; \)
= Highlighting off.\H+
= HTML-TADS on; \H-
= HTML-TADS off.Also, if using HTML-TADS, several HTML tags like <b>
, <i>
and <font>
are supported,
plus a few tags unique to HTML-TADS, eg: <sound>
.
See direction properties.
a , b
For example:
if x = 2, 3, 5, 7, 11
a or b
For example:
if (player in Forest or House or Lake)
Not supported. Write the condition in full.
You may use (a , b)
in conjunction with is in
or not in
. For example:
if (cheese is in (brie, cheddar, swiss))
child(parentObj)
eldest(parentObj)
child(parentObj)
<FIRST? object>
By "floating items", we mean objects found in multiple locations.
Locate your floating objects in pure containers, using
the Container
structure. Objects in pure containers are always where the Hero is.
Create a matching storage object with the container property, and define a pair of
rules to EMPTY
the contents from pure container to storage container
(and vice-versa) when appropriate. (See 6.10 of the ALAN manual.)
Define the object's found_in
property as either a list of locations, or as a routine which
returns true
if the item should be found in location
.
Note that if a floating object is also given the absent
attribute and the object removed, then the found_in
property is
ignored, and the object isn't anywhere.
Declare as of class floatingItem
in addition to at least one other class. Only floatingItem
objects may have a variable location
property.
See real numbers.
Not supported. Can't specify the text font within the program. If you want to use ASCII graphics, you'll have to ask the player to make sure their ALAN interpreter is using a fixed-width font, and play the entire game that way.
Note: Food only, not drinks (see liquids). By default in most systems, edible objects are removed from the game when eaten.
If using std.i
, use IS edible.
Give the edible
attribute to a object that can be eaten.
Nourishment is not modeled.
Declare an edible object as a member of fooditem
class.
Also, global.lastMealTime
is decremented by the item's foodvalue
property.
By default, the foodvalue
property is set to global.eatTime
.
Declare an edible object as an instance of Food
class.
Nourishment is not modeled.
Not applicable.
for ( expr? : expr? : expr? ) statement
repeat with var running from expr to expr begin; statements; end repeat.
for ( expr? ; expr? ; expr? ) statement
for ( initlist ; expr? ; expr? ) statement
where initlist
→ init [, init]*
and init
→ local? id = expr
See output.
Examples of how you'd write a function.
[ addlist arg1 arg2 sum count i;
...statements...
return sum;
];
addlist: function(arg1, arg2)
{
local sum, count, i;
...statements...
return(sum);
}
function addlist(arg1, arg2)
{
local sum, count, i;
...statements...
return sum;
}
<ROUTINE ADDLIST (ARG1 ARG2 "AUX" SUM COUNT I)
<guts-of-the-routine>
<RETURN .SUM>>
It's often necessary to mark objects as male, female, or neuter, so the work can generate the correct pronouns for them, or so the player can refer to the objects by their pronouns.
Not specified. Although it's simple to give Actors attributes like IS male
or IS female
,
you still need to write your code to check for those attributes.
By default, objects have no particular gender.
Use the (male $)
and (female $)
traits to declare an object's gender.
Note that the gendered traits imply the (animate $)
trait.
By default, animate
objects are male, and all other objects are neuter.
Give the male
, female
, or neuter
attribute to an object to indicate its gender.
By default, all objects are neuter.
Set the isHim
or isHer
property of an object to true
to indicate gender.
Most objects are neuter by default. If the object has the PERSONBIT
flag set, the object is considered an Actor and is assumed to be male,
unless it also has the FEMALEBIT
flag set, in which case the Actor is understood to be female.
Not applicable.
jump label
jump label ;
goto label ;
n/s. No graphics support as yet.
Z-Code: TODO (v6 only)
Glulx-Code:
glk_image_draw(window, image, val1, val2)
glk_image_draw_scaled(window, image, val1, val2, width, height)
x > y
($A > $B)
This predicate succeeds if and only if A is numerically greater than B.
if the score is greater than 10
if the score > 10
<G? integer1 integer2>
<GRTR? integer1 integer2>
x >= y
if the score is at least 10
if the score >= 10
Is it not supported? Do this instead:
<OR <G? int1 int2> <EQUAL? int1 int2>>
object IS attribute
object is attribute
object has attribute
n/a. Use: object.property
<FSET? object flag>
object IS NOT attribute
object is not attribute
object hasnt attribute
n/a. Use: !object.property
I think you'd have to do it like this:
<NOT <FSET? object flag>>
(program entry point)
Hello, world!
routine main
{
print "Hello world"
pause
quit
}
[ Main; print "Hello world^"; ];
"Hello World" by John Smith
Hello World is a room.
#include "tads.h"
main(args)
{
"Hello from TADS 3!!!\b";
}
Or concealed. TODO.
Normal identifiers must not start with a digit. May contain letters, digits or underscores. Max length TBD.
There are also quoted identifiers, which must begin and end with single-quotes, and may contain any character (including spaces). Note that there are several restrictions on when and how to use quoted identifiers.
Normal identifiers are not case sensitive; however, quoted indentifiers are case sensitive.
Identifiers must not start with a digit. May contain letters, digits or underscores. Can be up to 32 characters long.
Identifiers are not case sensitive; room101
is the same ID as Room101
.
Identifiers must start with a letter. May contain letters, digits, dollar signs, or underscores. Can be up to 39 characters long.
Identifiers are case sensitive! showSum
is distinct from showsum
and ShowSum
.
Valid characters TBD. Can be up to 40 characters long.
Identifiers are case sensitive! showSum
is distinct from showsum
and ShowSum
.
As near as I can tell without actually using ZIL, identifiers probably must begin with an uppercase letter, and may only contain uppercase letters, hyphens, and digits. I have no idea how long they can be. Since lowercase letters aren't permitted in IDs, the issue of case sensitivity is avoided.
IF expr THEN statement* [ELSIF expr THEN statement*]* [ELSE statement
*]? END IF.
if expr NL statement [NL elseif expr NL statement]* [NL else statement]?
if ( expr ) statement [else statement]?
if condition [then | ,] phrase [; otherwise phrase]
if condition begin; phrases; [otherwise; phrases;] end if
See 10.5, 10.7, 10.8. Note: else
can be used instead of otherwise
.
<COND (<predicate> <do-stuff>)*>
During the pre-processing phase of compilation, include-statements are replaced with the contents of the files they refer to.
$INCLUDE 'filename'
Include "filename";
Include ">shortname";
Use #Include
(with the #
)
if using the directive inside a routine.
Not supported. Instead, use: SET n TO n + 1.
pre-increment format:
++n
post-increment format:
n++
Learning ZIL mentions an INC
instruction
(in a bare list of "other instructions") and to see the YZIP Spec for more information.
YZIP was Infocom's interpreter for Z6 games. If <INC integer-variable>
isn't valid, you'll have to do something like this:
<SETG PIZZA-EATEN <+ ,PIZZA-EATEN 1>>
How to specify the protagonist's initial location? This can be awkward because the object that defines the protagonist is often hidden deep within the authoring system's libraries, which a story author can't directly edit.
This is the first line of the Start section, eg:
START AT Kitchen.
Set the value of location
in the Initialise
function, eg:
location = Bedroom;
The ID of the initial location must be startroom
, eg: TODO.
Put introductory text in the Start section, after the "START AT
" statement.
Put introductory text in the Initialise
function.
input
pause
TODO: explain what input and pause do.
Kwi tells me, "when using the standard library, you should call
inputManager
methods instead of inputLine()
etc.,
to ensure that any pending output is displayed first."
Which means that this section needs a TODO label stuck on it. :(
inputLine()
(read a line of text from the keyboard)inputKey()
(read a single keystroke from the keyboard)inputEvent(timeout?)
(read a single input event)inputDialog(icon, prompt, buttons, defaultBtn, cancelBtn)
(display dialog)inputFile(prompt, dialogType, fileType, flags)
(display a file selector dialog)inputLineTimeout(timeout?)
(read a line from the keyboard with optional timeout)inputLineCancel(reset)
(cancel an input line that was interrupted by timeout)All are intrinsic functions; see tadsio.h
and t3tadsio.htm
.
Integers must be in decimal notation, eg: 4205
.
ALAN 2's integer range is TBD.
A number is a non-negative integer in the range 0–16383 inclusive. The printed representation of a number is always in decimal form, with no unnecessary leading zeros. Numbers that appear in the source code must also adhere to this format.
Integers must be in decimal notation, eg: 4205
.
Hugo's integer range is from −32768 to 32767.
Integers may in decimal, hex, or binary notation.
hex example: $3f08
(begins with $
)
binary example: $$1000111010110
(begins with $$
)
Inform 6's integer range is from −32768 to 32767.
Inform 7's integer range is from −32768 to 32767.
Integers may be in decimal, hex, or octal notation.
hex example: 0x3f08
(begins with 0x
)
octal example: 035
(begins with 0
)
TADS's integer range is from −2147483648 to 2147483647 (signed 32-bit integer).
ZIL's integer range is from −32767 to 32767, according to §7.1 of Learning ZIL.
object IN obj2
object AT location
object HERE
object NEARBY
object in obj2
object in obj2
Use: object.location = obj2
object.isIn(obj2) // indirect containment
object.isDirectlyIn(obj2) // direct containment
Although T3 still uses the location
property, you
are advised not to fiddle with it directly. See also in the Thing class:
isNominallyIn(obj), isInFixedIn(loc), isHeldBy(actor), isOwnedBy(obj)
.
object NOT IN obj2
object NOT AT location
object NOT HERE
object NOT NEARBY
object not in obj2
object notin obj2
Use: object.location <> obj2
!object.isIn(obj2) // indirect containment
!object.isDirectlyIn(obj2) // direct containment
Although T3 still uses the location
property, you
are advised not to fiddle with it directly. See also in the Thing class:
isNominallyIn(obj), isInFixedIn(loc), isHeldBy(actor), isOwnedBy(obj)
.
(Negate with !
like any other T3 expression.)
object ISA class
Note: ISA
is only useable in Syntax constructs.
TODO. I note that object.type
returns the value of object
's primary class,
but that's not quite the same thing.
object ofclass class
isclass(object , class)
object.ofKind(class)
This is about keys in the story world, things that unlock other things.
Not specified.
Not specified. However, to associate a key with the thing it unlocks,
set the lockable
object's with_key
property
to the key object.
Declare a key of class keyItem
.
To associate a key with the thing it unlocks,
set the keyLockable
item's myKey
property
to the key object.
Declare a key of class Key
(see extras.t).
To associate keys with the thing they unlock,
set the LockableWithKey
item's keyList
property
to a list of key objects, eg:
frontDoor.keylist = [ brassKey, masterKey ]
Not applicable.
: label
. label ;
label : ;
Supports either English or Swedish games via the Language option. According to the Alan manual: "Other non-English languages may be supported in the future depending on demand."
English only. Maybe. The Hugo manual doesn't seem to address this topic.
For a non-English Inform game,
one must replace (at minimum) both the english.h
and
grammar.h
files with language-specific versions.
Versions of these files have been written in other languages,
including French, German, Italian, and even Lojban.
There exists a Spanish variant of Inform called InformATE.
It helps if the target language is close to English in structure
and alphabet. It would be very difficult to create Inform
language files for Arabic or Japanese.
At minimum, a non-English TADS game
would require one to replace/rewrite both the adv.t
and std.t
files. I'm not at all certain if that is
sufficient or not. Still, TADS seems to be have the most potential
for non-English language support: there was a
Chinese game in TADS3 [**check this**], released in 2002.
youngest(parentObj)
Not specified. One could write a function to figure it out, though, if you had to.
Not supported.
In Z-code:
@log_shift a b -> result
a << b
Learning ZIL mentions a SHIFT
and ASHIFT
instructions
(in a bare list of "other instructions") and to see the YZIP Spec for more information.
YZIP was Infocom's interpreter for Z6 games. I'm guessing one of these means left shift?
x < y
($A < $B)
This predicate succeeds if and only if A is numerically less than B.
if the score is less than 10
if the score < 10
<L? integer1 integer2>
<LESS? integer1 integer2>
x <= y
if the score is at most 10
if the score <= 10
Is it not supported? Do this instead:
<OR <L? int1 int2> <EQUAL? int1 int2>>
Not specified. However, section 6.11 of the ALAN manual suggests an approach. First, declare the default attributes for objects and locations as:
Object Attributes
lightsource 0.
Location Attributes
lit.
Set lightsource OF
an object TO 5
(or some other non-zero value)
when it's lit. Set dark rooms to IS NOT lit.
Then, test for SUM OF lightsource HERE = 0
in your dark rooms
and test for SUM OF lightsource HERE = 0 AND LOCATION IS NOT lit
in your new Look verb definition. Also, you must use a container trick to swap out visible
objects so they aren't described when you enter a dark room.
Give the light
attribute
to an object or room to indicate that it gives off light or is lit.
By default, all objects and rooms are unlit.
Declare light-emitting objects of class lightsource
.
Set its islit
property to true
or nil
as appropriate.
Declare lit locations of class room
, and unlit locations
of class darkroom
. To give a darkroom
light, set its
lightsOn
property to true
; don't change its islit
property, because it is a routine.
Light is a potentially complicated topic in TADS 3. Here's the basics:
Room
class for a lit location or the DarkRoom
class for an unlit location.LightSource
class, or one of its subclasses Candle
, Flashlight
, or Matchstick
.brightness
property (of Thing
) can be set from 0 to 4 to represent different levels of illumination.
For comparison purposes, brightnesses 0 and 3 correspond to unlit and lit respectively in other authoring systems.If using std.i
, and the liquid is drinkable, use IS drinkable
. No other support.
Not specified. The author in on their own in handling liquids' various properties, eg: availablity (eg: general water vs. carryable water), drinking, divisibility, evaporation, effects of emmersion/soaking, floating/density, mixing of liquids, portability (which containers may carry liquid), quantity, swimming.
Not applicable.
Not supported.
a + b
where a
must be a list, and b
must be either a list or of a data type that can be in a list.
Not applicable.
Not supported.
a - b
where a
must be a list, and b
must be either a list or of a data type that can be in a list.
Not applicable. Instead, declare "local variables" as other attributes in your Objects, Locations, and Actors.
Not applicable. A function's local variables are declared as part of the function's declaration frame.
local var [, var]*
Give it the lockable
attribute.
Declare it of class lockable
or keyedLockable
, both of which are subclasses of openable
.
Use the Lockable
mix-in class for lockable objects. The predefined subclasses of Lockable
are IndirectLockable
, LockableContainer
, LockableWithKey
, and KeyedContainer
.
Set the LOCKEDBIT
flag on an object to indicate that it is locked.
a AND b
a and b
a && b
a and b
a && b // alternate syntax
a && b
<AND predicate1 predicate2>
Note that you're not limited to two predicates; one example shows you can have at least four.
Not supported. However, you can use NOT
as a modifier of another operation.
For example, instead of NOT(x = y)
,
use x NOT = y
. And instead of NOT(x IS male AND y AT House)
,
use x IS NOT male OR y NOT AT House
.
not a
~~a
not a
!a // alternate syntax
!a
<NOT predicate>
a OR b
a or b
a || b
a or b
a || b // alternate syntax
a || b
<OR predicate1 predicate2>
Note that you're not limited to two predicates; one example shows you can have at least four.
See remainder.
To move an object (or the Hero) normally:
LOCATE object where_clause.
To remove an object from the game, create a Location that the Hero can't reach and Locate the object there (NOWHERE
is part of std.i
):
LOCATE object AT NOWHERE.
A where_clause
is one of IN object
, AT location
,
HERE
, or NEARBY
.
move obj to loc
remove obj
move obj to loc ;
remove obj ;
TODO: You should use something else to move the player.
The very powerful now
statement should be used for this, eg:
now the player is in Mountain Plateau;
now the player is carrying the broken string;
now the balloon is nowhere;
obj.moveInto(loc)
obj.moveInto(loc) // for normal movement
obj.mainMoveInto(loc) // for teleport-style moves
Move things to nil
to remove them from the story world.
(There is also obj.moveIntoForTravel(loc)
,
but I haven't figured that one out yet.)
To move object1 into object2:
<MOVE object1 object2>
To remove object1 from the story world:
<REMOVE object>
To teleport the PC into a room, triggering any appropriate on-entry routines:
<GOTO room>
To attempt making the PC go a specific direction:
<DO-WALK ,P?direction-property>
Multiplication of two numeric values is done with an operator, usually an asterisk sign.
x * y
($A times $B into $C)
A and B must be bound to numbers; C is unified with their product. If the product is outside the valid range of numbers, the query succeeds, but the numeric result is unpredictable (i.e. it depends on the interpreter).
X * Y
X multiplied by Y
<* integer1 integer2>
<MUL integer1 integer2>
sibling(childObj)
younger(childObj)
sibling(childObj)
<NEXT? object>
x <> y
x ~= y
x != y
How are the input grammars for objects (that is, their adjectives and nouns) defined?
At the time of writing (November 2018), Dialog assumes that all words declared by
either (name $)
or (dict $)
are valid words for the player to use
to refer to the object. There are no distinctions between adjectives and nouns.
Complex noun phrases might possibly be handled via (rewrite $ into $)
during parsing the player's command, but I'm not sure if that's the best place to do it.
'adjective* noun[/noun]*
[* pluralnoun+]?'
For example:
'painted framed picture/portrait*pictures portraits'
Note 1: Put brackets around a vocabword to mark it as a "weak" word.
Note 2: Use a hyphen character by itself to represent no noun.
Not supported. But depending on what you're trying
to do, you may be able to use one of the aggregates COUNT
,
SUM OF property
, or MAX OF property
; eg:
SET total_weight OF Hero TO 50 + SUM OF weight IN INVENTORY.
LIST object.
to list contents of a container.EMPTY object to obj2.
to transfer objects.for var in object NL statement
objectloop condition statement
repeat with var running through expr begin; statements; end repeat.
By "object operations", we mean any predefined functions, operators, and statements that manipulate objects in any way.
readfile filename NL statement
Opens a file for reading at the beginning of the block, and closes the file at the end.
If Z-Code, use one of:
@input_stream n
! 0=keybd; 1=file
@output_stream n array?
! ±1=screen; ±2=script file; ±3=array; ±4=command file
Positive values open a stream; negative values, close it. [see DM4 §42]
fopen(filename, mode);
This category is about all output issues, including text formatting.
Fixed two-panel layout: main text panel and status bar panel at top. No control over status bar's contents. In the Options Section of your program, you may specify a Width of line to display, and a Length value representing how many lines to display before a <More> prompt, but an interpreter may ignore these options.
parent(childObj)
Best approximation is probably:
object.location
Not supported. If the parent object isn't fixed in place, you'll probably have to use the container trick to keep sub-objects with their parent; see containers and floating objects.
Not supported. Use workarounds to put the part in scope:
static
or scenery
items may be implemented just as
separate static
or scenery
items in the same location.transparent
attribute to the parent item. (Not practical
if the parent is either a container
or supporter
; see §12 of DM4.)add_to_scope
field.Declare as an instance of the Component
class.
How do we play sounds or music?
Not supported.
music repeat? "file" , "song" [, vol]?
music 0
sound repeat? "file" , "sample" [, vol]?
sound 0
For Z-Code, z5 or z6 or z8 only:
@sound_effect number effect? volrep? routine?
See DM4 §42.
Also test if (($10-->0) & 128 ~= 0)
then the player's interpreter can play sound.
For Glulx-Code:
glk_schannel_play(channel, sound)
glk_schannel_play_ext(channel, sound, repeats, notify)
For HTML-TADS:
Use the <SOUND>
tag:
"<sound src='resourcefile' layer=foreground|bgambient|ambient|background
random=n repeat=n|loop sequence=replace|random|cycle
interrupt cancel[=layer] alt='text'
fadein=n fadeout=n>";
<SOUND integer1 integer2 integer3 integer4>
where:
If a single object has a plural name like "glass shards", you want to mark the item as plural for two reasons. First, you want the default indefinite article to be "some" (instead of "a" or "an"). Second, you want the work or the player to be able to refer to the object with they/them pronouns.
Contrast with plural name.
Declared with the (plural $)
trait.
Use the pluralname
attribute in the object's has
clause.
Inform can usually infer whether your objects are singular or plural
from your use of "is", "are", or "some" when you first declare the object without
you needing to otherwise declare its pluralness more explicitly. If you do need to
specify it explicitly, use the either/or properties singular-named
and plural-named
respectively. For example:
The fruit are plural-named.
Set the object's PLURALBIT
flag; see Appendix B in Learning ZIL.
If you have a class of objects that share a name, like "key", you may want the player to be able to refer to all the keys at once, but to do that, you need to code the word "keys" as the plural name of all "key" objects.
Contrast with plural.
(plural dict $)
associates plural synonyms with an object or set of objects. For example:
(plural dict (stone $))
stones
For input, the dictionary words in an object's name field that end in //p
are understood to be a plural name for the object. For example:
'books//p'
For output, the plural
field of an object specifies a string (or a routine to print a string)
with the plural name of that object.
An example from Writing with Inform:
Understand "birds" as the plural of duck.
Inform also itself needs to understand plural forms within your source code. Writing with Inform claims Inform is quite good at guessing likely plurals for many English nouns, but admits that English is irregular enough that you still might need to explicitly declare a plural form:
The plural of something is somethings.
For example:
The plural of brother in law is brothers in law.
I'm guessing this is specified with the PLURAL
property? It's mentioned but not described in Appendix A in Learning ZIL.
Not applicable.
(pointer)
For example:
obj.(propPtr)(actor);
Closest equivalent is the optional Options Section at the beginning of an ALAN source file.
The Options Section begins with the word OPTIONS
followed
by one or more option statements:
LANGUAGE lang.
— where lang
is English
(default) or Swedish
.WIDTH num.
— where num
is from 24 to 255. Default 80.LENGTH num.
— where num
is from 5 to 255. Default 24.PACK.
or NO PACK.
— to turn on/off text compression. Default off.DEBUG.
or NO DEBUG.
— to turn on/off debugging. Default off.Note that an interpreter may override the Width and Length options, and that debugging may be enabled instead by a compiler option.
Replace SomeRoutine;
System_file;
Message [error | fatalerror | warning]? "message";
Release number;
Serial "dddddd";
Ifdef name;
|
Ifndef name;
| Iftrue condition;
|
Iffalse condition;
] NL statements
NL [Ifnot;
NL statements
NL]? Endif;
Default name value;
Stub name number;
TODO.
debugging metaverbs: abstract, actions, changes, daemons, gonear, goto, messages, purloin, random, recording, replay, routines, scope, showobj, showverb, timers, trace, tree.
metaverbs: brief, die, full, fullscore, long, normal, noscript, notify, nouns, objects, places, pronouns, q, quit, restart, restore, save, score, script, short, superbrief, transcript, unscript, verbose, verify, version.
game verbs: adjust, answer, ask, attach, attack, awake, awaken, blow, bother, break, burn, buy, carry, check, chop, clean, clear, climb, close, consult, cover, crack, cross, curses, cut, d, damn, darn, describe, destroy, dig, discard, display, disrobe, dive, doff, don, down, drag, drat, drink, drop, dust, e, east, eat, embrace, empty, enter, exit, examine, fasten, feed, feel, fight, fill, fix, fondle, fuck, get, give, go, grope, hear, hit, hold, hop, hug, i, in, inside, insert, inv, inventory, jump, kill, kiss, l, leave, lie, light, listen, lock, look, move, murder, n, nap, ne, no, north, northeast, northwest, nw, offer, open, out, outside, pay, peel, pick, polish, pray, present, press, prune, pull, punch, purchase, push, put, q, quit, read, remove, rotate, rub, run, s, say, scale, screw, scrub, se, search, set, shed, shift, shine, shit, shout, show, shut, sing, sip, sit, skip, sleep, slice, smash, smell, sniff, sod, sorry, south, southeast, southwest, speak, squash, squeeze, stand, sw, swallow, sweep, switch, swim, swing, take, taste, tell, think, throw, thump, tie, torture, touch, transfer, turn, twist, u, uncover, undo, unlock, unscrew, unwrap, up, w, wait, walk, wake, watch, wave, wear, west, wipe, wreck, x, y, yes, z.
other verbs: again, amusing, g, o, oops.
debugging verbs: debug.
game verbs: a, about, activate, affirmative, aft, again, ask, attack, attach, back, blow, board, break, buckle, burn, bye, clean, climb, close, connect, consult, consume, credits, cut, d, deactivate, destroy, detach, dig, disconnect, disembark, drag, drink, drop, doff, don, douse, down, e, east, eat, enter, examine, exit, exits, extinguish, f, fasten, feel, find, flip, follow, footnote, footnotes, fore, foreward, full, fullscore, g, get, give, go, greet, good, good-bye, goodbye, hear, hi, hint, hints, hit, hello, holler, i, ignite, imbibe, in, inspect, inventory, jump, kick, kiss, kill, l, leave, lie, light, listen, lock, look, move, n, ne, negative, no, north, northeast, northwest, note, notify, nw, o, offer, oops, open, out, p, pause, pick, place, plug, port, pour, press, pull, punch, push, put, q, quaff, quit, read, record, remove, replay, restart, restore, return, rotate, rq, ruin, s, save, say, sb, score, scream, screw, script, se, search, set, shout, show, shut, sit, sleep, smell, sniff, south, southeast, southwest, stand, starboard, status, strike, sw, switch, t, take, talk, taste, tell, terse, throw, topics, toss, touch, turn, twist, type, u, undo, unbuckle, unfasten, unlock, unplug, unscrew, unscript, up, verbose, version, w, wait, walk, wear, west, wreck, x, yell, yes, z.
elder(childObj)
Not supported. But you could write a function to figure it out, if you needed to.
print print-arg [; print-arg]*
printchar var [, var]*
Not supported.
picture "resourcefile" , "picture"
picture "picturefile"
(line)
requests a line break.(par)
requests a paragraph break.(par $)
prints $N
blank lines.Dialog does its best to collapse consecutive requests for line and paragraph breaks into something sensible.
print newline
new_line;
"\n";
property OF object
object.property
Also known as the player-character or the PC, this object respresents the player within the game, or is the character that the player directly controls.
Use HERO
, which is pre-defined. Its container property
is INVENTORY
. If you need to give new attributes to Hero, then explicitly
declare Hero with the appropriate Actor construct.
Use player
(a global declared in parserm.h
),
which refers to the selfobj
object (also declared in parserm.h
).
Use Me
, which is of class BasicMe
.
There is no predefined PC object; you must create your own.
Typically, one defines me
as an instance of class Actor
, and then within the mainCommon
function, set gPlayerChar = me;
so the game knows which object represents the player character.
This is for ending the program immediately.
QUIT .
(quit)
quit
throw new QuittingException;
(TODO: Is this for adv3 only? This needs more explanation.)
<QUIT>
(random from $A to $B into $C)
A and B must be bound to numbers, such that B is greater than or equal to A. A random number in the range A to B (inclusive) is picked, and then unified with C.
Returns a random number between one and the given number, inclusive:
<RANDOM integer>
No support. By default, most specialized authoring systems for interactive fiction don't provide any native support for real numbers or floating point arithmetic. It's almost never necessary.
Supported via the BigNumber
class, able to represent values from 10−32,767 to 1032,767. (See t3_doc\t3bignum.htm)
ALAN 2 has no built-in operator for this. You'll have to do it the hard way:
(x - ((x / y) * y))
($A modulo $B into $C)
A and B must be bound to numbers; C is unified with the remainder after dividing A by B. The query fails if B is zero.
mod(x, y)
x % y
remainder after dividing X by Y
<MOD integer1 integer2>
TODO.
Not applicable.
return expr?
return expr? ;
<RETURN anything>
to return any value.<RTRUE>
to return 1 (that is, true).<RFALSE>
to return 0 (that is, false).Not supported.
In Z-code:
@log_shift a -b -> result
a >> b
Learning ZIL mentions a SHIFT
and ASHIFT
instructions
(in a bare list of "other instructions") and to see the YZIP Spec for more information.
YZIP was Infocom's interpreter for Z6 games. I'm guessing one of these means right shift?
By long custom, distinct locations in a work of IF are called rooms, even if the locations are outdoors, underwater, or in the vacuum of outer space.
Use the Location construct, eg:
LOCATION Kitchen
DESCRIPTION "What a boring room. The exit is east."
EXIT east TO Hallway.
END LOCATION Kitchen.
There is no default room class. A room is
just another object. Objects that can be entered (eg: chairs, beds) are
given the enterable
attribute.
Define its cant_go
property to define a room's
"you can't go that way" message.
The base room class is room
.
Subclasses are darkroom
for unlit rooms, and
nestedroom
for enterable objects within a room,
which in turn has chairitem
, beditem
and vehicle
subclasses.
Define its noexit
method to print a room's
"you can't go that way" message (and which should also return nil
).
Implemented via the Room
class
or any of its subclasses; eg: Darkroom, OutdoorRoom, FloorlessRoom
.
Use the mix-in class ShipboardRoom
with another
Room
class for shipboard locations.
Use BasicLocation
or one of its many subclasses
for any other location.
Make item attribute .
give object attribute ;
Just use a normal assignment statement; for example:
now the umbrella is open;
TADS never had "attributes", just properties that can take any value, including boolean ones:
object.property = true;
<FSET object flag>
Not applicable.
color foreground [, background [, input ]]
Z-Code:
@set_colour foreground background
HTML-TADS:
"<body bgcolor='background'><font color='foreground'>";
Not supported.
locate ( row , column )
TODO. TADS 3 has "TextGrid
banners", I'm told.
Not supported.
ALAN statements end in periods.
Hugo statements have no explicit terminator character; the end of the line marks the end of a statement.
Use \
at the end of a line to split a statement onto two or more lines;
the backslash is optional in long string constants broken over multiple lines.
Use :
to put two or more statements onto the same line.
Inform 6 and TADS statements end in semi-colons.
Inform 7's punctation tries to mimic English's as much as possible. Statements generally end in periods or are delimited by semicolons within compound statements.
However, it is also valid to end a statement with a string that either itself ends in a period, question mark, or exclamation mark, or ends in single-quote mark preceeded by a period, question mark, or exclamation mark.
statement*
{ statement [NL statement]* }
{ statement+ }
[OPTIONS option+]? unit+ start
"This is a string constant."
'This is a string constant.'
Note that a doublequoted string in TADS is not a string constant; it is a directive to print the string.
This operator, if available, joins two strings of text together into one string.
Not applicable.
Note that TADS overloads the plus sign for this, which normally does addition between two numbers.
x + y // where x must be a string.
Subtraction of two numeric values is done with an operator, usually a hyphen.
x - y
($A minus $B into $C)
A and B must be bound to numbers; C is unified with their difference. If the result is outside the valid range of numbers, the query fails.
X - Y
X minus Y
<- integer1 integer2>
<SUB integer1 integer2>
That is, how do we call (or access) the superclass's property (or method) from within the current object's property (or method)?
class..property
class::property
I'm confused on this still. I've been told that pass prop;
is equivalent to return inherited(args);
where
args
are the parameters passed to the current method.
It might also be valid to either use inherited.property
or inherited class.property
as appropriate.
TODO. TADS 3 doesn't use TADS 2's pass
statement.
Also known as surfaces, supporters are objects that can have other objects on top of them. In most systems, an object cannot be both a container and a supporter at the same time, and the author should instead code two objects; for example, a trunk (the container) and its lid (the supporter) or a dresser (the supporter) and its drawer (the container).
Give it the supporter
attribute. An object cannot be both a container and a supporter.
Declare it of class surface
or qsurface
.
The latter is "quiet", and doesn't list its contents in certain circumstances.
An object cannot be both a container and a surface.
Declare it of class Surface
or one of its
subclasses, such as Bed
, Chair
, or Platform
. However, objects that are both a container
and a surface ought to be declared of class ComplexContainer
.
See supporters for things that have flat upper surfaces you can put other things on top of.
See walls for room surfaces, including floors and ceilings.
DEPENDING ON lexpr case-clause* default-clause? END DEPENDING.
where case-clause
→ rexpr : statement*
and default-clause
→ ELSE : statement*
select expr case-clause* default-clause?
where case-clause
→ NL case const [, const]* NL statement
and default-clause
→ NL case else NL statement
Note: Avoid an expr
with side-effects; it is executed for every case in the select.
switch ( expr ) { case-clause* default-clause? }
where case-clause
→ case const [, const]* : statement*
and default-clause
→ default : statement*
switch ( expr ) { case-clause* default-clause? }
where case-clause
→ case const-expr : statement*
and default-clause
→ default : statement*
Left justified only.
Manual spacing won't work because Alan compresses multiple spaces before displaying text.
But use $t
in a string to print a tab.
Not supported. Can't specify boldness or italics.
(bold)
enables bold text.(fixed pitch)
enables fixed-pitch text.(italic)
enables italic text.(reverse)
enables reverse-video text.(roman)
disables all text styles (bold, italic, reverse, and fixed pitch).\B
= Boldface on; \b
= Boldface off.<b>
= Boldface on; </b>
= Boldface off<i>
= Italics on; </i>
= Italics off.<HLIGHT integer>
where the integer is one of: 0 (no highlighting), 1 (inverse video),
2 (bold), 4 (underline/italic), 8 (monospaced).
Global constants like H-INVERSE
, H-BOLD
, and H-ITALIC
exist so you don't have to remember these numbers.
<ITALICIZE string>
See objects.
children(parentObj)
Sometimes objects in a game need to be transparent so the player-character can look through them. How do you code that?
Give the object the transparent
attribute.
Declare it of class transparentItem
.
Or, if you just wish to "look through" it, declare it of
class seethruItem
and define its thrudesc
method as appropriate.
Transparency in TADS 3 is modeled on the more general notion of sense-passing, in this case, with respect to the
sense of sight. For the simple case where you want to make a container transparent, you probably want to set the container's
material
property to glass
, e.g.: displayCase.material = glass
. Glass is predefined as
transparent to sight, but opaque to sound, smell, and touch. (Other predefined materials are
adventium
(which is the default and opaque to all senses), paper
, fineMesh
,
and coarseMesh
. See sense.t.)
Set the TRANSBIT
flag of an object to make it transparent.
See booleans.
In many programming languages, unary negation looks much like subtraction but without specifying that we're subtracting from zero.
Note that in ALAN 2, unary negation is only supported in certain contexts, but I failed to determined what those contexts are.
-x
@{hhhh}
where hhhh
is the hexadecimal code value.
Use \-
followed by any two bytes to pass those bytes literally.
\uhhhh
where hhhh
is the hexadecimal code value.
$l
= name of current Location$v
= verb that player used (first word)$a
= The name of the actor that is executing$o
= The current object (first parameter)$n
= The parameter with number n
, where n
is a digit.Not applicable.
@00
to @31
=
String constants set via Inform's string
statement.<<expr>>
= Evaluate the expression. It must evaluate to a number
or a string (single or doublequoted). This feature only in doublequoted
strings, and may not be nested.<<expr>>
evaluates expr
just like
in TADS 2, still only useable in doublequoted strings.{the dobj/he}
is an example of substitution codes,
usable in both single and doublequoted strings.All standard libraries of all four languages assume 2nd person and present tense. Changing the default voice and verb tense is a similar job to changing the language: editing/replacing the library files. It is simpler in one respect, in that you only need worry about output, not input.
2nd person and present tense are still the defaults.
To change Voice:
Actor.pcReferralPerson = FirstPerson // or SecondPerson or ThirdPerson
To change Tense: TODO.
We're discussing all room surfaces here: walls, floors, and ceilings. Sometimes a "floor" is really the ground, and a "ceiling" is really the sky.
Not specified. See floating items for a way to handle them.
By default, walls are bundled with the eight compass directions; for example, the north direction and the north wall are treated as the same object. Likewise, the floor is the same as the down direction, and the ceiling is the same as up direction.
By default, locations don't have walls or a ceiling, but do have a floor/ground item: theFloor
,
which is implemented as a beditem floatingItem
.
Implemented via the RoomPart
class or its subclasses Floor
or DefaultWall
.
By default, a Room
comes equipped with defaultFloor,
defaultCeiling, defaultNorthWall, defaultSouthWall,
defaultEastWall,
and defaultWestWall
; an OutdoorRoom
has only defaultGround
and defaultSky
; and
a FloorlessRoom
has none.
See clothing.
Not applicable.
while expr NL statement
while ( expr ) statement
ZIL stands for Zork Implementation Language. This was the programming language that Infocom invented and used to write its games.
External links: