Introduction • Notation • Meta-Game • Input • Output • World Model • Index
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 the ifwiki.
This is my attempt to compare, on a feature-by-feature basis, most of the main IF languages in use today: Alan 2 & 3, Inform 6 & 7, Hugo, and TADS 2 & 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.
Hugo
routine main
{
print "Hello world"
pause
quit
}
Inform 6
[ Main; print "Hello world^"; ];
Inform 7
"Hello World" by John Smith Hello World is a room.
TADS 3
#include "tads.h"
main(args)
{
"Hello from TADS 3!!!\b";
}
Alan 2 TADS 2
TODO
Alan 2
[OPTIONS option+]? unit+ start
Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2
-- This is a comment in Alan.
-- There is no multi-line comment form in Alan.
Hugo
! This is a single-line comment in Hugo.
!\ And this is a multi-line comment Which goes across more than one line. \!
Inform 6
! This is a comment in Inform 6.
! There is no multi-line comment form in Inform 6.
Inform 7
[ 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. ]
TADS 2 TADS 3
// This is a single-line comment in TADS.
/* And this is a multi-line comment Which goes across more than one line. */
Alan 2 Inform 6 TADS 2 TADS 3
Non-applicable issue for most languages. Alan statements end in periods; Inform and TADS statements end in semi-colons. How you format your code is up to you.
Hugo
Hugo statements have no 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.
Alan 2
$INCLUDE 'filename'
Inform 6
Include "filename";
Include ">shortname";
Use #Include (with the #) if using the directive inside a routine.
Hugo TADS 2 TADS 3
TODO
Inform 6
[Ifdef name; |
Ifndef name; | Iftrue condition; |
Iffalse condition;] NL stmts NL [Ifnot;
NL stmts NL]? Endif;
Default name value;
Stub name number;
Alan 2 Hugo TADS 2 TADS 3
TODO
Alan 2
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:
Note that an interpreter may override the Width and Length options, and that debugging may be enabled instead by a compiler option.
Inform 6
Replace SomeRoutine;
System_file;
Message [error | fatalerror | warning]? "message";
Release number;
Serial "dddddd";
Hugo TADS 2 TADS 3
TODO
TODO
Alan 2
n/s. Use 1 and 0.
Hugo Inform 6
true and false (which are equal to 1 and 0, respectively)
TADS 2 TADS 3
true and nil
Alan 2 TADS 2 TADS 3
In Alan and TADS, there is no distinct Character datatype. Just use one-character string constants; eg: "x" in Alan, or 'x' in TADS.
Hugo Inform 6
eg: 'x'
In Inform, be careful not to confuse character constants with dictionary words.
Alan 2
n/a. Use normal and quoted variables in NAME phrases. Also, see the SYNTAX construct.
Hugo
eg: "x" "joe's" "silver" "keys"
Always in doublequotes. Doesn't use Inform's //p, etc.
Inform 6
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.
TADS 2 TADS 3
n/a. Use string constants, eg: 'x' 'joe\'s' 'silver' 'keys'.
ALL Alan 2 Hugo
All languages understand simple decimal notation, eg: 4205
For Alan and Hugo, this is the only integer notation format.
Inform 6
hex example: $3f08 (begins with $)
binary example: $$1000111010110 (begins with $$)
TADS 2 TADS 3
hex example: 0x3f08 (begins with 0x)
octal example: 035 (begins with 0)
Hugo Inform 6 Inform 7
−32768 to 32767
TADS 2 TADS 3
−2147483648 to 2147483647 (signed 32-bit integer)
Alan 2
TODO
Alan 2 Hugo Inform 6 Inform 7 TADS 2
n/s. Most IF languages don't provide any native support for real numbers or floating point arithmetic. It's almost never necessary.
TADS 3
Supported via the BigNumber class, able to represent values from 10−32,767 to 1032,767. (See t3_doc\t3bignum.htm)
Alan 2 Hugo Inform 6 Inform 7
"This is a string constant."
TADS 2 TADS 3
'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.
Alan 2
Use "" for a doublequote, 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.)
Hugo
Use \" for a doublequote, 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 its 3-digit number.
Inform 6
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. Unfortunately, few interpretors (if any) support Unicode.
TADS 2
Use \" for a doublequote; \' 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 £.
TADS 3
Similar to TADS 2, except that it's always in HTML mode, so entity codes like & for '&', etc. is now required. Also, \- is no longer used; instead use Unicode characters, eg: \uABCD, where ABCD is the hexadecimal code value.
Alan 2
$p = New paragraph (one empty line)
$i = Indent on a new line.
$t = Insert a tabulation.
$$ = Do not insert a space.
Hugo
\_ = 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.
Inform 6
\ = For "folding lines" (no longer needed).
TADS 2
\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.
(if using HTML-TADS:)
Several HTML tags, like <b>, <i>
and <font> are supported,
plus a few tags unique to HTML-TADS, eg: <sound>.
TADS 3
TODO
Alan 2
$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.
Hugo
n/a.
Inform 6
@00 to @31 = String constants set via Inform's string statement.
TADS 2
<<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.
TADS 3
<<expr>> evaluates expr just like in TADS 2, still only useable in doublequoted strings.
{the dobj/he} is an example of the new substitution codes, useable in both single and doublequoted strings.
Alan 2
No: Normal identifiers are not case sensitive.
Yes: Quoted identifiers are case sensitive.
Hugo Inform 6
No. room101 is the same name as Room101.
TADS 2 TADS 3
Yes. showSum is distinct from showsum and ShowSum.
Alan 2
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.
Hugo Inform 6
Identifiers must not start with a digit. May contain letters, digits or underscores. Can be up to 32 characters long.
TADS 2
Identifiers must start with a letter. May contain letters, digits, dollar signs, or underscores. Can be up to 39 characters long.
TADS 3
TODO. Can be up to 40 characters long.
TODO
TODO
TODO
Alan 2
n/s. Use: SET a TO a + 1. • SET a TO a - 1.
Hugo Inform 6 TADS 2 TADS 3
++a and a++ • --a and a--
Alan 2
-a (but only supported in certain contexts?)
Hugo Inform 6 TADS 2 TADS 3
-a
ALL
a * b • a / b • a + b • a - b
Inform 7
I7 understands both *, /, +, and -, and the following forms as well:
a multiplied by b • a divided by b • a plus b • a minus b
Alan 2
Use: (a - ((a / b) * b))
Hugo
Use: mod(a, b)
Inform 6 TADS 2 TADS 3
a % b
Inform 7
remainder after dividing a by b
Alan 2
n/a
Hugo
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.
Inform 6
(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.
Inform 7
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 - whateverTADS 2
[ 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.
TADS 3
[ ] (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]; }
Alan 2
n/a
Hugo
array [ index ] (first element is index 0)
Inform 6
wordarray --> index
bytearray -> index (first element is index 0)
TADS 2 TADS 3
list [ index ] (first element is index 1)
That is, how to refer to an array/list when it's the value of an object's property.
Alan 2
n/a
Inform 6
object .& arrayproperty
TADS 2 TADS 3
object . property
Hugo
TODO
Alan 2
n/a
Hugo
array[] returns array's length.
Inform 6
object .# arrayproperty
(Note: Returns length of a bytearray, or 2×length of a wordarray.)
TADS 2
length(list)
TADS 3
list.length()
Alan 2
Neither are applicable.
Hugo
TODO
Inform 6
Neither are supported.
TADS 2 TADS 3
a + b a - b
where a must be a list; b must be either a list or a dataitem that can be in a list.
Alan 2
Use: SET a TO b.
Hugo Inform 6 TADS 3
a = b
TADS 2
a := b (default style)
a = b (C mode style)
Alan 2
Use: SET a TO a op b.
Hugo
+= -= *= /= &= |=
Inform 6
Use: a = a op b
TADS 2 TADS 3
+= -= *= /= %= &= |= ^= <<= >>=
Alan 2
Not supported.
Hugo Inform 6 TADS 2 TADS 3
a & b a | b ~a
Alan 2
Not supported.
Hugo Inform 6
Use: ((a | b) & ~(a & b))
TADS 2 TADS 3
a ^ b
Alan 2 Hugo
Not supported.
Inform 6
(ZCode left shift:) @log_shift a b -> result
(ZCode right shift:) @log_shift a -b -> result
TADS 2 TADS 3
a << b a >> b
Alan 2
object ISA class
Note: ISA is only useable in Syntax constructs.
Inform 6
object ofclass class
TADS 2
Use: isclass(object , class)
TADS 3
object.ofKind(class)
Hugo
TODO
I note that object.type returns the value of object's primary class, but that's not quite the same thing.
Inform 6
object provides property
TADS 2
Use: defined(object, &property)
Note that a property pointer is passed to defined().
TADS 3
Use: object.propDefined(&property)
Alan 2 Hugo
TODO
Alan 2
property OF object
Inform 6 TADS 2 TADS 3
object . property
Hugo
TODO
That is, how do we call (or access) the superclass's property (or method) from within the current object's property (or method)?
Hugo
class .. property
Inform 6
class :: property
TADS 2
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.
TADS 3
TODO. TADS 3 doesn't use TADS 2's pass statement.
Alan 2
TODO
Alan 2
object IS attribute object IS NOT attribute
Hugo
object is attribute object is not attribute
Inform 6
object has attribute object hasnt attribute
TADS 2 TADS 3
n/a. Use: object.property !object.property
Alan 2
object IN obj2 • object NOT IN obj2
object AT location • object NOT AT location
object HERE • object NOT HERE
object NEARBY • object NOT NEARBY
Hugo
object in obj2 • object not in obj2
Inform 6
object in obj2 • object notin obj2
TADS 2
Use: object.location = obj2 • object.location <> obj2
TADS 3
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.)
Hugo
child(parentObj) or eldest(parentObj) • youngest(parentObj)
Inform 6
child(parentObj) • n/s
Alan 2 TADS 2 TADS 3
TODO
Hugo
elder(childObj) • sibling(childObj) or younger(childObj)
Inform 6
n/s • sibling(childObj)
Alan 2 TADS 2 TADS 3
TODO
Hugo Inform 6
children(parentObj)
Alan 2 TADS 2 TADS 3
TODO
Hugo Inform 6
parent(childObj)
TADS 2
Use: object.location
Alan 2 TADS 3
TODO
Alan 2
a AND b • a OR b • n/s.
For logical not, 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.
Hugo
a and b • a or b • not a
Inform 6
a && b • a || b • ~~a
TADS 2
a and b • a or b • not a
a && b • a || b • !a (alternate syntaxes)
TADS 3
a && b • a || b • !a
Alan 2
a = b • a <> b
Hugo
a = b • a ~= b
Inform 6
a == b • a ~= b
TADS 2
a = b • a <> b (default style)
a == b • a != b (C mode syntax)
TADS 3
a == b • a != b
Alan 2 Hugo Inform 6 TADS 2 TADS 3
a < b • a <= b • a >= b • a > b
Alan 2
x BETWEEN a AND b
Inform 6 TADS 3
Use: a <= x && x <= b
TADS 2
Use: a <= x and x <= b
Hugo
TODO
Inform 6
n/a
TADS 2 TADS 3
a + b where a must be a string.
Alan 2 Hugo
TODO
Alan 2 Inform 6
n/a
Hugo
&function &object.property
TADS 2
&function &property
TADS 3
&property
Alan 2
n/s. Use an IF statement.
Inform 6
n/s. Use an if statement.
TADS 2 TADS 3
a ? b : c
Hugo
TODO
Inform 6 TADS 2 TADS 3
a , b
Alan 2 Hugo
TODO
Alan 2 Inform 6
n/a
TADS 2
(pointer) eg: obj.(propPtr)(actor);
Hugo TADS 3
TODO
Alan 2
TODO
Hugo
a , b
eg: if x = 2, 3, 5, 7, 11
Inform 6
a or b
eg: if (player in Forest or House or Lake)
TADS 2
n/s. Write the condition in full.
TADS 3
(a , b) in conjuntion with is in or not in.
eg: if (cheese is in (brie, cheddar, swiss))
Inform 6
[ addlist arg1 arg2 sum count i; ...statements... return sum; ];
TADS 2
addlist: function(arg1, arg2)
{
local sum, count, i;
...statements...
return(sum);
}
TADS 3
function addlist(arg1, arg2)
{
local sum, count, i;
...statements...
return sum;
}
Alan 2 Hugo
TODO
TODO: array call capital dict hex number playback random readval recordoff recordon restart restore runevents save scriptoff scripton string system
Alan 2
stmt*
Hugo
{ stmt [NL stmt]* }
Inform 6 TADS 2 TADS 3
{ stmt+ }
Alan 2
n/a.
Hugo
break
Inform 6 TADS 2
break ;
TADS 3
break label? ;
Hugo
call var [( expr [, expr]* )]?
run object.property
Alan 2 Inform 6 TADS 2 TADS 3
TODO
Alan 2
n/s. Print a string with 24 \n in it.
Hugo
cls
Inform 6
(Z-Code:) @erase_window window
window should be 0 for lower window, 1 for upper, −1 for entire screen.
TADS 2
clearscreen();
TADS 3
clearScreen(); (see tadsio.h)
Alan 2
n/a.
Inform 6 TADS 2
continue ;
TADS 3
continue label? ;
Hugo
TODO
Alan 2
n/a.
Hugo
do stmt NL while expr
Inform 6
do stmt until ( expr ) ;
TADS 2 TADS 3
do stmt while ( expr ) ;
Alan 2
n/a.
Inform 6
for ( expr? : expr? : expr? ) stmt
Inform 7
repeat with var running from expr to expr begin; stmts; end repeat.
See 10.9,
Hugo TADS 2
for ( expr? ; expr? ; expr? ) stmt
TADS 3
for ( initlist ; expr? ; expr? ) stmt
where initlist → init [, init]*
and init → local? id = expr
Alan 2
n/a
Hugo
jump label
Inform 6
jump label ;
TADS 2 TADS 3
goto label ;
Alan 2
IF expr THEN stmt* [ELSIF expr THEN stmt*]* [ELSE stmt*]? END IF.
Hugo
if expr NL stmt [NL elseif expr NL stmt]* [NL else stmt]?
Inform 6 TADS 2 TADS 3
if ( expr ) stmt [else stmt]?
Inform 7
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.
Hugo
input
pause
TODO: explain what input and pause do.
TADS 3
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)
Alan 2 Inform 6 TADS 2
TODO
Alan 2
n/a
Hugo
: label
Inform 6
. label ;
TADS 2
label : ;
TADS 3
TODO
Alan 2
n/s. Declare "local variables" as other attributes in your Objects, Locations, and Actors.
Inform 6
n/a. A function's local variables are declared as part of the function's declaration frame.
Hugo
local var [, var]*
TADS 2 TADS 3
TODO
Alan 2
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.
Hugo
move obj to loc
remove obj
Inform 6
move obj to loc ;
remove obj ;
TADS 2
obj.moveInto(loc)
TADS 3
obj.moveInto(loc) (for normal movement)
obj.mainMoveInto(loc) (for teleport-style moves)
Move things to nil to remove them from the game world.
(There is also obj.moveIntoForTravel(loc), but I haven't figured that one out yet.)
Alan 2
n/s. 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. Use LIST object. to list contents of a container. Use EMPTY object to obj2. to transfer objects.
Hugo
for var in object NL stmt
Inform 6
objectloop condition stmt
Inform 7
repeat with var running through expr begin; stmts; end repeat.
See 10.10.
TADS 2 TADS 3
TODO
Hugo
readfile filename NL stmt
Opens a file for reading at the beginning of the block, and closes the file at the end.
Inform 6
(if ZCode, use one of:)
@input_stream n
0=keybd; 1=file
@output_stream n array?
±1=screen; ±2=script file; ±3=array; ±4=cmnd file
Positive values open a stream; negative values, close. [see DM4 §42]
TADS 2
Use: fopen(filename, mode);
Alan 2 TADS 3
TODO
Alan 2
n/s
Hugo
music repeat? "file" , "song" [, vol]?
music 0
sound repeat? "file" , "sample" [, vol]?
sound 0
Inform 6
(if ZCode, z5 or z6 or z8:)
@sound_effect number effect? volrep? routine? [see DM4 §42]
Also test if (($10-->0) & 128 ~= 0) then the player's interpreter can play sound.
TADS 2
(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>";
TADS 3
TODO
Hugo
print print-arg [; print-arg]*
printchar var [, var]*
Alan 2 Inform 6 TADS 2 TADS 3
TODO
Alan 2
n/s
Hugo
picture "resourcefile" , "picture"
picture "picturefile"
Inform 6 TADS 2 TADS 3
TODO
Hugo
print newline
Inform 6
new_line ;
TADS 2 TADS 3
"\n" ;
Alan 2
TODO
Alan 2
QUIT .
Hugo
quit
TADS 3
throw new QuittingException;
(TODO: for adv3 only? This needs more explanation.)
Inform 6 TADS 2
TODO
Alan 2
n/a.
Hugo
return expr?
TADS 2 TADS 3
return expr? ;
Inform 6
TODO
Alan 2
MAKE item attribute .
MAKE item NOT attribute .
Inform 6
give object attribute ;
give object ~attribute ;
TADS 2 TADS 3
n/a. Use: object.property = true; (or nil)
Hugo
TODO
Alan 2
n/a.
Hugo
color foreground [, background [, input ]]
Inform 6
Z-Code: @set_colour foreground background
TADS 2
HTML-TADS: "<body bgcolor='background'><font color='foreground'>";
TADS 3
TODO
Alan 2 TADS 2
n/s.
Hugo
locate ( row , column )
TADS 3
(TODO. TADS 3 has "TextGrid banners", I'm told.)
Inform 6
TODO
Alan 2
DEPENDING ON lexpr case-clause* default-clause? END DEPENDING.
where case-clause → rexpr : stmt*
and default-clause → ELSE : stmt*
Hugo
select expr case-clause* default-clause?
where case-clause → NL case const [, const]* NL stmt
and default-clause → NL case else NL stmt
Note: Avoid an expr with side-effects; it is executed for every case in the select.
Inform 6
switch ( expr ) { case-clause* default-clause? }
where case-clause → case const [, const]* : stmt*
and default-clause → default : stmt*
TADS 2 TADS 3
switch ( expr ) { case-clause* default-clause? }
where case-clause → case const-expr : stmt*
and default-clause → default : stmt*
Alan 2
n/a.
Hugo
while expr NL stmt
Inform 6 TADS 2 TADS 3
while ( expr ) stmt
Game's Name
Game's Subtitle
Game's Date
Game's Version
Author Info
Alan 2
This is the first line of the Start section, eg:
START AT Kitchen.
Inform 6
Set the value of location in the Initialise function, eg:
location = Bedroom;
TADS 2
The ID of the initial location must be startroom, eg:
TODO
Hugo TADS 3
TODO
Alan 2
Put intro text in the Start section, after the "START AT" statement.
Hugo
TODO
Inform 6
Put intro text in the Initialise function.
TADS 2 TADS 3
TODO
Alan 2
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."
Hugo
English only. Maybe. The Hugo manual doesn't seem to address this topic.
Inform 6
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.
TADS 2
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.
TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2
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.
TADS 3
2nd person and present tense are still the defaults.
To change Voice: Actor.pcReferralPerson = FirstPerson (or ThirdPerson).
To change Tense: TODO.
(includes AUTHOR, CREDITS, INFO, INFORMATION, INSTRUCTIONS, LICENSE)
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
(includes ENDNOTES)
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
(includes LONG, SHORT, SUPERBRIEF, TERSE)
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
(includes HELP, HINT, MENU, WALKTHROUGH, WALKTHRU)
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
(includes LOAD)
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
(includes FULL SCORE, FULLSCORE, STATUS)
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
(includes SCRIPT, UNSCRIPT)
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Inform 6
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.
TADS 3
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 VerbRules are in en_us.t.
Alan 2 Hugo TADS 2
TODO
TADS 3
'adjective* noun[/noun]* [* pluralnoun+]?'
eg: '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.
Alan 2 Hugo Inform 6 TADS 2
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Inform 6
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.
TADS 3
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.
Alan 2 Hugo TADS 2
TODO
Alan 2
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.
Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2
n/s. Best you can do is put something like $n$t in front of each line of the quote.
Inform 6
box string+ ;
TADS 3
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.
Hugo TADS 2
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2
n/s. Can't specify colors.
Inform 6
TODO. Obviously the color capabilities of the Z-machine are much more limited than Glulx's.
Hugo TADS 2 TADS 3
TODO
Alan 2
n/s. 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 his Alan interpreter is using a fixed-width font, and play the entire game that way.
Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2
n/s. No graphics support as yet.
Inform 6
Z-Code: TODO (v6 only)
Glulx-Code:
glk_image_draw(window, image, val1, val2)
glk_image_draw_scaled(window, image, val1, val2, width, height)
Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2
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.
Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2
n/s. No sound support as yet.
Inform 6
Z-Code: TODO (v6 only)
Glulx-Code:
glk_schannel_play(channel, sound)
glk_schannel_play_ext(channel, sound, repeats, notify)
Hugo TADS 2 TADS 3
TODO
Alan 2
n/s. Can't specify boldness or italics.
Hugo
\B = Boldface on; \b = Boldface off.
TADS 2 TADS 3
<b> = Boldface on; </b> = Boldface off; <i> = Italics on; </i> = Italics off.
Inform 6
TODO
Inform 6
By default, Inform 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.
TADS 2
By default, the values of an item's adesc and thedesc properties are "a <<self.sdesc>>" and "the <<self.sdesc>>" respectively. Give these properties a new value to override their default values.
Alan 2 Hugo TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Note: That is, objects found in multiple locations.
Alan 2
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 Alan manual.)
Inform 6
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.
TADS 2
Declare as of class floatingItem in addition to at least one other class. Only floatingItem objects may have a variable location property.
Hugo TADS 3
TODO
Alan 2
n/s. But it's simple to give Actors attributes like IS male or IS female.
Hugo
TODO
Inform 6
By default, animates are male, and all other objects are neuter.
Give the male, female, or neuter attribute to an object to indicate gender.
TADS 2
By default, all objects are neuter.
Set the isHim or isHer property of an object to true to indicate gender.
TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2 Hugo Inform 6 TADS 2 TADS 3
TODO
Alan 2
n/s. Considering the need to empty out the contents of opaque containers to a storage container when the former is closed, transparent containers may be simpler. (Unless the transparent container can go in a closeable opaque one, in which case it becomes difficult again.)
Hugo
TODO
Inform 6
Give it the transparent attribute.
TADS 2
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.
TADS 3
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.)
Alan 2
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).
Inform 6
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.
TADS 2
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.
TADS 3
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.
Hugo
TODO
Inform 6
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.
TADS 2
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.
TADS 3
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).
Alan 2 Hugo
TODO
Alan 2
Declare creatures with the Actor construct.
Inform 6
Give creatures the animate attribute.
TADS 3
Declare creatures as instances of Actor, or one of its subclasses: UntakeableActor or Person.
Hugo TADS 2
TODO
Alan 2
n/s. 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 NOTE closed.). Also, define the EXIT clauses in the rooms to CHECK side1 IS NOT closed.
Inform 6
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 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.
TADS 3
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
Hugo TADS 2
TODO
TODO
Note: Food only, not drinks (see Liquids). By default, edible objects are removed from the game when eaten.
Alan 2
If using std.i, use IS edible.
Hugo
TODO
Inform 6
Give the edible attribute to a object that can be eaten. Nourishment is not modeled.
TADS 2
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.
TADS 3
Declare an edible object as an instance of Food class. Nourishment is not modeled.
Alan 2
n/s.
Hugo
TODO
Inform 6
n/s. To associate a key with the thing it unlocks, set the lockable object's with_key property to the key object.
TADS 2
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.
TADS 3
Declare a key of class Key (extras.t). To associate a key with the thing it unlocks, set the LockableWithKey item's keyList property to a list of key objects, eg: frontDoor.keylist = [ brassKey, masterKey ]
Alan 2
n/s. Section 6.11 of the Alan manual suggests this 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 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.
Inform 6
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 dark.
TADS 2
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.
TADS 3
Light is a potentially complicated topic in TADS 3. Here's the basics:
Hugo
TODO
Alan 2
If using std.i, and the liquid is drinkable, use IS drinkable. No other support.
Hugo
TODO
Inform 6
n/s. The author in on his/her 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.
TADS 2
TODO
TADS 3
TODO
Alan 2
TODO
Inform 6
Give it the lockable attribute.
Hugo
TODO
TADS 2
Declare it of class lockable or keyedLockable, both of which are subclasses of openable.
TADS 3
Use the Lockable mix-in class for lockable objects. The predefined subclasses of Lockable are IndirectLockable, LockableContainer, LockableWithKey, and KeyedContainer.
Alan 2
TODO
Hugo
TODO
Inform 6
TODO
TADS 2
TODO
TADS 3
TODO
Alan 2
n/s. 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.
Hugo
TODO
Inform 6
n/s. Use workarounds to put the part in scope:
TADS 2
TODO
TADS 3
Declare as an instance of the Component class.
Alan 2
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.
Hugo
TODO
Inform 6
Use player (a global declared in parserm.h), which refers to the selfobj object (also declared in parserm.h).
TADS 2
Use Me, which is of class BasicMe.
TADS 3
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.
Alan 2
Use the Location construct, eg:
LOCATION Kitchen
DESCRIPTION "What a boring room. The exit is east."
EXIT east TO Hallway.
END LOCATION Kitchen.
Inform 6
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.
TADS 2
The basic 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).
TADS 3
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.
Alan 2
TODO
Hugo
TODO
Inform 6
Give it the supporter attribute. An object cannot be both a container and a supporter.
TADS 2
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.
TADS 3
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.
Alan 2
n/s. See floating items for a way to handle them.
Hugo
TODO
Inform 6
By default, walls are bundled with the 8 compass directions; the floor is the same as "down", and the ceiling is the same as "up".
TADS 2
By default, locations don't have walls or ceiling, but do have a floor/ground item: theFloor, which is implemented as a beditem floatingItem.
TADS 3
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.