*Aiee! Index |  Variables |  Adventure File Syntax |  ADVENTURE |  ROUTINE |  TOKEN |  FUNCTION |  GRUE |  INTRO |  ITEM |  PLAYER |  ROOM |  How-To Guide |  Programmer's Text Editors | 

   Aiee! adventures are written in XML. The smallest possible adventure looks like this:


<adventure start="cell">
  <intro>
    <text>\tSanitarium
\n\nYour family finally committed you...  But you'll show them!  You'll escape
and have your revenge!
</text>
  </intro>

  <room id="cell" name="Padded Cell">
    <look>
      <text>You are trapped in a totally barren padded cell.</text>
    </look>
    <exit dir="u"><text>You thought you had found a way out, but you were
mistaken.</text></exit>
  </room>
</adventure>

   For a more useful example, open cloak.xml or dungeoncrawl.xml in a good text editor, and study them.


Variables

   Aiee! uses global variables--any variable you define is available anywhere in the adventure. A variable can have any name you want, as long as it does not contain the characters ", ', (, or ). See ID below. Once defined, you can refer to a variable with $(ID).

   There is no limit on the number of variables, or how large their contents can be.

   System variables start with an underscore. You cannot modify any of these, they will be set automatically with every command.

"_who" holds the id of the current player or actor (during the actor's turn),
    or "" for items and rooms.
"_this" holds the id of whatever room or item contains the command.
"_here" holds the id of whatever room the player or item is currently in.
"_plroom" holds the id of whatever room the player is currently in.
"_turn" holds the current game turn.
"_cmd" holds the current command.
"_arg1" holds the id of the first argument in a command, or empty string if
    not identified.
"_name1" holds the name of the first argument in a command, or empty string
    if not identified.
"_text1" holds the text the user typed for the first argument in a command.
"_prep" holds the preposition the user typed between the first and second
    arguments.
"_arg2" holds the id of the second argument in a command, or empty string if
    not identified.
"_name2" holds the name of the second argument in a command, or empty string
    if not identified.
"_text2" holds the text the user typed for the second argument in a command.
"_score" holds the player's current score.
"_maxscore" holds the maximum score defined for the adventure.
"_grue" holds the grue chance of the current room.


Adventure File Syntax

   The syntax below is given in a simple but programmer-ish form. A nice manual will be along eventually, but this and the sample adventures should be sufficient to make your own adventures. If you still have questions, email me and ask.

   Additional tags will be available in future versions, but I do not expect to change any currently-defined tags; your adventures should work in all future versions of Aiee!.

   Anything in all-uppercase below is a term defined elsewhere. Definitions are given in the form "TERM := DEFINE".

[] :=
Anything inside the brackets is optional. "[a]" means that you can use "" or "a".
[]... :=
Anything inside the brackets may appear 0 or more times. "[a]..." means that you can use "", "a", "aa", "aaa", etc.
| :=
Anything separated by | bars is a choice. "a|b" means that you can use "a" or "b".
BOOL :=
true|false|1|0
DIR :=
n|ne|e|se|s|sw|w|nw|u|d
N :=
any integer value from -2147483648 to 2147483647
ID :=
any characters *except* single quotes ('), double quotes (") or parentheses ().
All actor, item, and room IDs must be unique, it does not matter for other IDs.
The IDs 'player' and 'null' are reserved, and cannot be used for new rooms or items. 'player' refers to the player, 'null' is a non-existent location used to hold objects that have been "destroyed".
REF :=
As ID, but may contain variable references in the form:
$(REF)
which will be replaced with the value of the variable. If the variable is not defined, the text "$(Undefined REF)" will be inserted instead.
NAME :=
Any legal XML text. Variables are not evaluated in NAMEs.
You can insert a newline into text with \n
Or a tab with \t
Or a backslash with \\
Special characters like $, <, >, &, etc. can be embedded with \uFFFF, where "FFFF" is the UNICODE value of the character in hexadecimal, or you can use \xFF, which is equivalent to \u00FF. There is a complete list of ASCII and Latin-1 (ISO-8859-1) characters in the file 'charset.txt'; you should only use those characters on most English or Roman-alphabet systems, as other UNICODE characters will not display correctly.
TEXT :=
As NAME, but Text may also contain variable references in the form:
$(ID)
which will be replaced with the value of the variable. If the variable is not defined, the text "$(UNDEFINED VARNAME)" will be inserted instead.
ROUTINE :=
[TOKEN]...
Routines execute each TOKEN in order until a <continue /> or <abort /> is encountered. If the routine runs out of tokens, it is treated as if there was a <continue /> at the end.
TOKEN :=
    <abort />
        <!-- Stops evaluating any further in a routine, and aborts the current
            user command.
        -->

    <call function='REF' />
        <!-- Invokes a function.  There are no arguments, but you can use
            variables to pass information in.
        -->

    <continue />
        <!-- Stops evaluating any further in a routine, but allows the current
            user command to continue normally.
        -->

    <damage [target='REF'] value="REF" [element='REF'] />
        <!-- Causes damage on actor 'target'.  If 'target' is undefined, it is
            assumed to be the player.
            'value' is the amount of damage done; it must be a valid integer.
            If 'element' is defined, the weapon does damage of that type;
            otherwise, it does damage type "p" (physical).  Only one element can
            be given for damage.
        -->

    <debug on='BOOL' />
        <!-- Turns debugging mode on or off.
            You should never use this command in the final version of an
            adventure, but it's very helpful while designing one.
        -->

    <do [silent='BOOL']>TEXT</do>
        <!-- Causes the player to perform command TEXT.
            If 'silent' is defined and true, no text is printed out.
        -->

    <gameover [die='BOOL'] />
        <!-- Displays the player's score and number of hints, and ends the
            game.
            If 'die' is defined and true, the player dies.
        -->

    <if>
        [<test var='REF' [op='ID']>TEXT</test>]...
        [<hasitem [owner='REF'] item='REF' [ready='BOOL] />]...
        [<haslight [item='REF'] />]...
        [<istype item='REF' type='ID' />]...
        [<then>[TOKEN]...</then>]...
        [<else>[TOKEN]...</else>]...
    </if>
        <!-- Evaluates the tags inside, one after another.  <test>, <hasitem>,
            and <haslight> set the "if flag" to true or false.  <then> is
            evaluated and ends the <if> block if the flag is true; <else> is
            evaluated and ends the <if> block if the flag is false.  Normally,
            you will use it in the most basic form:
            <if><test var='enteredcrypt'>1</test>
              <then><text>You entered the crypt.</text></then>
              <else><text>You have not entered the crypt yet.</text></else>
            </if>

            However, you can use it for longer chains of logic by repeating
            <test> <then> <test> <then> with a final <else>.  See the
            example under <player><score>.

            <test> compares a variable and the text by an operator 'op'; if
                'op' is undefined, the default is "eq":
                eq      Equals
                ne      Not Equals
                le      Less Than or Equal To
                lt      Less Than
                gt      Greater Than
                ge      Greater Than or Equal To
                            eq, ne, le, lt, gt, and ge first check to see if
                            both 'var' and 'TEXT' are numbers, and if so will
                            do a numeric comparison; otherwise they do a
                            case-insensitive string comparison.
                in      Text In: does a case-insensitive match on two strings.
                            If 'TEXT' is contained in 'var', the result is
                            true, otherwise false.
            <hasitem /> checks to see if 'item' is contained in 'owner'
                (defaults to $(_this)), or in a container that is not closed;
                if the owner is a room, it will not detect an item carried by
                an actor or player, though.
                If 'ready' is true, the item must also be readied.
            <haslight /> checks to see if 'item' is lit; if 'item' is not
                defined, the current room is used.
            <istype /> checks to see if 'item' is of a given type.  The types
                are "room", "item", "player", and "actor".
        -->

    <img src='FILENAME' />
        <!-- Displays an image.  Images must be in .gif, .jpg, or .png format,
            and included in the adventure zip file.
            The image will be displayed until you move to a new room or another
            image is displayed.
            The space the image takes will be taken out of available space to
            display text, so it should not be very tall--320 pixels is a good
            height.  It can be as wide as you like, but over 800 pixels wide
            will be off the screen of some users.
            Images will not be shown in the text-only client, but the filename
            will be displayed.
        -->

    <light on='BOOL' [item='REF'] />
        <!-- Lights or darkens a room or item.
            If 'item' is not defined, the current room is used.
        -->

    <moveto [item='REF'] loc='REF' />
        <!-- If 'item' is undefined, moves the player to room 'loc'.
            Otherwise, moves a specific item to 'loc'.
            The loc can be a room, item, or actor, or the reserved ID
            'player', in which case an item is moved to the player's inventory,
            or 'null', in which case it is moved to a "nowhere" room.  It is
            illegal to move the player to 'player' or 'null'.
        -->

    <output>TEXT</output>
        <!-- Shows TEXT to the player, if _who is "player" (i.e., only on the
            player's actions).
        -->

    <random var='REF' [n='N'] range='N' />
        <!-- Sets a variable 'var' to the total of 'n' random numbers from 1 to
            'range'.  If 'n' is undefined, it defaults to 1.  For example:
            <random var='chance' range='100' />
            Generates a random number from 1 to 100.
            <random var='chance' n='2' range='6' />
            Generates a random number from 2 to 12, averaging 7.
        -->

    <score value='N' />
        <!-- Adds N to the player's score.
        -->

    <set var='REF' [op='ID']>TEXT</set>
        <!-- Sets a variable 'var'.  If operator 'op' is undefined, it is
            assumed to be '='.  The operators are:
                =       Sets 'var' equal to 'TEXT'.
                +       Converts 'TEXT' to a number, and adds it to 'var'.
                -       As +, but subtracts 'TEXT' from 'var'.
                *       As +, but multiplies 'var' by 'TEXT'.
                /       As +, but divides 'var' by 'TEXT' and leaves the
                            integer quotient.
                %       As +, but divides 'var' by 'TEXT' and leaves the
                            integer remainder.
                app     Appends 'TEXT' to 'var'.
                pre     Prepends 'TEXT' to 'var'.
                name    Sets 'var' equal to the name of stuff with id 'TEXT'.
                            For instance, with an actor with id "orc" and name
                            "Gruumsh the Orc", you'd use:
                            <set var='orcname' op='name'>orc</set>
                aname   As 'name', but includes the indefinite article (a/an).
                thename As 'name', but includes the definite article (the).
                input	Prints TEXT as a prompt, waits for a line of input
            		    from the player, and sets 'var' to that input.

            While individual rooms, items, and actors do not have any
            properties or flags, you can simulate that by using a variable name
            in the form 'ID.someflag'.
        -->

    <sound src='FILENAME' [control='play|loop|stop'] />
        <!-- Plays a sound file.  Sounds must be in .au, .wav, or .mid format,
            and included in the adventure zip file.  mp3 will be supported in a
            later version, but for now only primitive sound types work.
            If 'control' is not defined, or is "play", the sound is played once
            and stops.  If 'control' is "loop", the sound repeats constantly
            until stopped with "stop".  If 'control' is "stop", the sound with
            that filename is immediately stopped.
            Sounds will not be shown in the text-only client, but the filename
            will be displayed.
        -->

    <text>TEXT</text>
        <!-- Shows TEXT to the player.
        -->
    
ADVENTURE :=
<adventure start='ID' [maxscore='N']>
    <!-- Creates a new adventure.
        The player will start in room 'start'.
        The maximum score possible is 'maxscore', for displaying at game end;
        if not defined, the default is 100.
    -->

    [ACTOR]...
    [FUNCTION]...
    [GRUE]
    [INTRO]
    [ITEM]...
    [PLAYER]
    [ROOM]...
    <!-- The child tags may be given in almost any order; if you set the
        location of an item or actor, the location must be defined first.  You
        can't put something in a place that doesn't exist yet.
    -->

</adventure>
    
ACTOR :=
    <actor id='ID' [article='NAME'] name='NAME' [gender='ID'] [hits='N'] loc='ID'>
        <!-- Creates a new actor with the given name, in room 'loc'.
            The actor is friendly unless given a weapon item.
            'article' contains the indefinite article (a, an) for the actor; if
                not set, the item has a proper noun name.  "The" will be used
                as the definite article if 'article' is set.
            'gender' must be "m" (male), "f" (female), or "n" (neuter); if
                undefined, it defaults to "n".
            'hits' is the amount of damage the actor can take before dying; if
                undefined, it defaults to 10.
        -->

        [<alias name='NAME' />]...
            <!-- Adds another name for the actor.  You might have the
                following:
                <actor id='bluegoblin' name='blue goblin' loc='cave'>
                    <alias name='goblin' />
                </actor>
                You could now refer to that actor as 'goblin' or 'blue goblin'.
            -->

        [<ask [subject='NAME']>ROUTINE</ask>]
            <!-- ROUTINE is evaluated when the actor is asked about a
                given subject.  Any text that contains the subject matches
                (case-insensitive).  The first defined ask which matches is
                used.
                If the subject is not defined, this ask routine is used for
                any ask that does not match any other ask.  The text will be
                in $(_text2).
                Creative use of <ask> would allow you to implement the
                Eliza therapist program...
                If a actor responds to a word or phrase, it's only fair to
                have either the actor or someone else mention that word or
                phrase first.  Word-guessing games aren't fun.
                "say SUBJECT to ACTOR" also calls ask, with the actor in _arg1
                and the subject in _text2, just like "ask ACTOR about SUBJECT".
                You can differentiate the two by checking _cmd.
            -->

        [<die>ROUTINE</die>]
            <!-- ROUTINE is evaluated when the actor is killed.
                A common replacement is to increase the player's score:
                <die>
                  <text>The goblin vanishes in a puff of greasy black smoke!<text>
                  <score value='10' />
                  <moveto loc='null' />
                </die>
                If the routine is NOT aborted, the actor is moved to 'null' and
                all contents are moved to the current room.
            -->

        [<give>ROUTINE</give>]
            <!-- ROUTINE is evaluated when an item is given to the actor.
                The item ID will be in _arg2.
                If the routine is aborted, the give fails.
            -->

        [<guard dir='DIR'>ROUTINE</guard>]...
            <!-- ROUTINE is evaluated when the player attempts to move in
                direction 'dir'.
                If the routine is aborted, the move fails.
            -->

        [<hurt>ROUTINE</hurt>]
            <!-- ROUTINE is evaluated when the actor has been injured but not
                killed.
            -->

        [<invisible />]
            <!-- Makes the actor "invisible"--it will not be listed in the
                room description.
            -->

        [<look>ROUTINE</look>]
            <!-- ROUTINE is evaluated when the player types 'look CREATURE'.
                If the routine does not exist, the standard "You see nothing
                special about the whatsit." is shown.
            -->

        [<observe>ROUTINE</observe>]
            <!-- ROUTINE is evaluated when the actor is in the same room as the
                player, before the player performs an action.  The player's
                command is available in the system variables.
                Actor <observe> is run after the player <command>,
                and before the room <command>.
                If the routine is aborted, the player's command fails.
            -->

        [<turn>ROUTINE</turn>]
            <!-- ROUTINE is evaluated every turn.
                <set var='$(_this).distance'>3</default>
                [...]
                <turn>
                  <if><hasitem owner='$(_plroom)' item='$(_this)' />
                    <else><abort /></else>
                  </if>
                  <if><test var='$(_this).distance'>0</test>
                    <then>
                      <text>The thing hits you with its ropy tentacles!</text>
                      <damage value='10' />
                    </then>
                    <else>
                      <text>The horrible thing slithers toward you...</text>
                      <set var='$(_this).distance' op='-'>1</set>
                    </else>
                  </if>
                </turn>
            -->

    </actor>
    
FUNCTION :=
    <function id='ID'>ROUTINE</function>
        <!-- Defines a function.  Functions can be invoked with <call /> from
            any routine.
        -->
    
GRUE :=
    <grue>ROUTINE</grue>
        <!-- ROUTINE is evaluated when the player moves from a dark room with a
            "grue" value into a dark room or in an exitless direction.  See
            <room> for more information.
            Example:
<grue>
  <random var="roll" range="100"/>
  <if><test var="roll" op="le">$(_grue)</test>
    <then>
      <text>You step forward boldly, and fall into a bottomless pit.</text>
      <gameover die="true"/>
    </then>
    <else><text>You stumble in the dark, and nearly fall in a pit.</text></else>
  </if>
</grue>
        -->
    
INTRO :=
    <intro>ROUTINE</intro>
        <!-- ROUTINE is evaluated when the game starts.
            Use it to give the user an introduction to the game, instructions,
            and set up any variables needed.
        -->
    
ITEM :=
    <item id='ID' name='NAME' [loc='ID'] [light='BOOL'] [article='NAME']>
        <!-- Creates a new item with the given name in room 'loc' (same meaning
            as <moveto>), or room 'null' if not defined.
            If 'light' is defined and true, the item is a light source.
            'article' contains the indefinite article (a, an) for the item; if
                not set, the item has a proper noun name.  "The" will be used
                as the definite article if 'article' is set.
        -->

        [<alias name='NAME' />]...
            <!-- Adds another name for the item.
            -->

        [<close>ROUTINE</close>]
            <!-- ROUTINE is evaluated when the player types 'close ITEM'.
                If the routine is aborted, the close does not succeed.
            -->

        [<container [capacity='N'] [closed='BOOL'] [locked='ID'] />]
            <!-- Makes the item a container.
                If 'capacity' is defined, the item can hold "N" weight units;
                otherwise, the item can hold 1000 weight units.
                If 'closed' is defined, the item can be opened and closed; when
                closed, the contents are not listed in your inventory, and
                contained light sources don't shine.  If undefined, the
                container is always open and cannot be closed.
                If 'locked' is defined, the container locks when closed, and
                can only be opened if the player is carrying the item with the
                given ID.
            -->

        [<drop>ROUTINE</drop>]
            <!-- ROUTINE is evaluated when the player types 'drop ITEM'.
                If the routine is aborted, the drop does not succeed.
            -->

        [<look>ROUTINE</look>]
            <!-- ROUTINE is evaluated when the player types 'look ITEM'.
                If the routine does not exist, the standard "You see nothing
                special about the whatsit." is shown.
            -->

        [<invisible />]
            <!-- Makes the item "invisible"--it will not be listed in the room
                description.
            -->

        [<open>ROUTINE</open>]
            <!-- ROUTINE is evaluated when the player types 'open ITEM'.
                If the routine is aborted, the open does not succeed.
            -->

        [<points value='N' [loc='ID'] />]
            <!-- Adds to the player's score if found in 'loc' when <gameover />
                is hit.  'loc' defaults to 'player' if undefined.
            -->

        [<put>ROUTINE</put>]
            <!-- ROUTINE is evaluated when the player puts this item into
                something else.
                If the routine is aborted, the put does not succeed.
            -->

        [<ready type='ID' [elements='ID'] [armor='N']>ROUTINE</ready>]
            <!-- The item will be readied or removed when the player types
                'ready ITEM'.  If it is initially located on a player or actor,
                it is readied at game start.
                The player cannot have anything else of the same 'type' ready.
                Items which can be readied, must be readied to be used.
                If 'elements' is defined, the item is of all listed elements for
                combat purposes; the default is "p" (physical).  The other
                elements are "a" (air), "e" (earth), "f" (fire), and "w"
                (water).  Multiple elements can be listed.
                If 'armor' is defined, the item provides N defense against
                attacks listed in 'elements', N/4 defense against other
                elements.
                ROUTINE is evaluated when the item is readied; it cannot be
                readied if the routine ends with <abort />.
            -->

        [<remove>ROUTINE</remove>]
            <!-- ROUTINE is evaluated when the item is removed; it cannot be
                removed if the routine ends with <abort />.
            -->

        [<take>ROUTINE</take>]
            <!-- ROUTINE is evaluated when the player types 'take ITEM'.
                If the routine is aborted, the take does not succeed.
            -->

        [<turn>ROUTINE</turn>]
            <!-- ROUTINE is evaluated every turn.
                To make it only work if the player is in the same room, use:
                <turn>
                  <if><hasitem owner='$(_plroom)' item='$(_this)' />
                    <else><abort /></else>
                  </if>
                  ...whatever...
                </turn>
            -->

        [<use>ROUTINE</use>]
            <!-- ROUTINE is evaluated when the player types 'use ITEM [TARGET]'
                or 'kill CREATURE ITEM'.  If the routine is aborted, the use or
                attack does not succeed.
                When making a weapon, <use> should check that the target
                exists, possibly use a random chance of the attack hitting, and
                then apply damage to the target.  This is a good operation to
                put in a function:
                <function id='attack'>
                  <if><test var='atktarget'></test>
                    <then><abort /></then>
                  </if>
                  <random var='roll' range='100' />
                  <if><test var='roll' op='le'>$(atkchance)</test>
                    <then>
                      <damage target='$(atktarget)' value='$(atkdamage)' element='$(atkelement)' />
                    </then>
                    <else>
                      <text>You miss!</text>
                    </else>
                  </if>
                </function>
                <use>
                  <set var='atktarget'>$(_arg2)</set>
                  <set var='atkchance'>50</set>
                  <set var='atkdamage'>6</set>
                  <set var='atkelement'>p</set>
                  <call function='attack' />
                </use>
            -->

        [<weight value='N' />]
            <!-- The 'weight' of the item.  The player can carry up to 1000
                weight units, total.  Making the item weigh over 1000 is a good
                way to make it uncarryable (9999 is the maximum weight, usually
                used for "uncarryable" weight).  If <weight> is not defined,
                the item weighs 100 units.
            -->
    </item>
    
PLAYER :=
    <player [hits='N']>
        <!--
            'hits' is the amount of damage the actor can take before dying; if
                undefined, it defaults to 10.
        -->

        [<command>ROUTINE</command>]
            <!-- ROUTINE is evaluated when the player types an "active"
                command, before the command is performed.  An <abort />
                prevents the command from being evaluated, and does not take a
                turn.
                This routine is not called for 'look', defined exits, or
                Special commands.  It is called for undefined exits.
                Player <command> is run before actor <observe>s and
                room <command>.
                This routine is evaluated before the room <command> routine.
            -->

        [<die>ROUTINE</die>]
            <!-- ROUTINE is evaluated when the player is killed.
                The default is to end the game.
            -->

        [<inv>ROUTINE</inv>]
            <!-- ROUTINE is evaluated when the player types 'inv'.
                If the routine is aborted, the inventory does not continue.
                A common use of this routine is to display RPG stats stored in
                variables.
            -->

        [<score>ROUTINE</score>]
            <!-- ROUTINE is evaluated when the player's score is to be
                displayed.  If the routine is aborted, the score display does
                not continue.  You can use this to provide a more meaningful
                score description:
                <player>
                  <score>
                    <if>
                      <test var='_score' op='lt'>2</test>
                      <then><set var='rank'>Amateur</set></then>
                      <test var='_score' op='lt'>4</test>
                      <then><set var='rank'>Novice</set></then>
                      <test var='_score' op='lt'>6</test>
                      <then><set var='rank'>Adventurer</set></then>
                      <test var='_score' op='lt'>8</test>
                      <then><set var='rank'>Professional</set></then>
                      <else><set var='rank'>Master</set></else>
                    </if>
                    <text>Your score is $(_score), in $(_turn) turns.\n
                      This gives you a rank of $(rank).
                    </text>
                    <abort />
                  </score>
                </player>
            -->

        [<turn>ROUTINE</turn>]
            <!-- ROUTINE is evaluated every turn.
            -->

    </player>
    
ROOM :=
    <room id='ID' name='NAME' [light='BOOL'] [grue='N']> (one or more)
        <!-- Creates a new room.  The room name is shown in the title bar, and
            is printed every time the player enters the room after the first
            time.
            If 'light' is defined and false, the room starts darkened;
            otherwise, it is lit.

            If 'grue' is defined and greater than 0, something will happen when
            you try to move from a dark room to a dark room.
            If there is a <grue> routine in the adventure, the system variable
            "_grue" is set, and that routine is called; if not, the built-in
            "grue" function is used, which uses the grue value as your
            percentage chance of being eaten by a grue.  Grues originated in
            Infocom's _Zork_, but have since spread to adventures throughout
            the universe.
        -->

        [<command>ROUTINE</command>]
            <!-- ROUTINE is evaluated when the player types an "active" command
                in the room, before the command is performed.  An <abort />
                prevents the command from being evaluated, and does not take a
                turn.
                This routine is not called for 'look', defined exits, or
                Special commands.  It is called for undefined exits.
                Room <command> is run after the player <command> and
                actor <observe>.
            -->

        [<dark>ROUTINE</dark>]
            <!-- ROUTINE is evaluated when the player first enters the room or
                types 'look', if the room is not lit.  If not defined, the
                player is told "It is dark."
            -->

        [<enter>ROUTINE</enter>]
            <!-- ROUTINE is evaluated every time the player enters the room.
            -->

        [<exit dir='DIR' [visible='BOOL'] [room='ID']>ROUTINE</exit>]...
            <!-- Creates an exit from the room.
                If 'visible' is defined and true, the exit is listed after the
                description; otherwise you must describe it or leave it to the
                player to guess.
                If 'room' is defined, and the routine did not abort, you move
                there.  'room' is equivalent to having <moveto loc='ID' /> in
                the routine.
            -->

        [<hint>TEXT</help>]
            <!-- Hint text is displayed when the player types 'hint' in the
                room.  There may be multiple hints in a room, and they are
                displayed in order, once for each hint request.
                For example:
                <hint>The dwarf seems to want something for his help.</hint>
                <hint>Dwarves like precious metals.</hint>
                <hint>Give him the gold statue.</hint>
                The number of times you asked for hints is shown with your
                score.
            -->

        [<look>ROUTINE</look>]
            <!-- ROUTINE is evaluated when the player first enters the room or
                types 'look', *if* the room is lit.
            -->

        [<points value='N' />]
            <!-- Adds to the player's score when first entered.
            -->

        [<turn>ROUTINE</turn>]
            <!-- ROUTINE is evaluated every turn.
                To make it only work if the player is in the same room, use:
                <turn>
                  <if><hasitem owner='$(_plroom)' item='$(_this)' />
                    <else><abort /></else>
                  </if>
                  ...whatever...
                </turn>
            -->
    </room>
    


How-To Guide

While creating basic adventures in Aiee! is very easy, more advanced techniques can be a little more subtle...

How do I add commands?
You cannot add entirely new commands. This is a design decision I made early on, to make the game better. Commands are kept to the bare minimum for a consistent user interface. Adding adventure-specific verbs sounds good in theory, but in practice it leads to "guess-the-verb" puzzles, which are rarely fun for the player.

However, you can add skills to an adventure by creating items, and then the player can "use SKILL on TARGET":

<item id='frotz' name='Frotz spell' loc='player'>
    <look><text>A simple spell to create light on an object.</text></look>
    <drop><text>Don't be ridiculous.</text><abort /></drop>
    <put><text>Don't be ridiculous.</text><abort /></put>
    <take><text>Don't be ridiculous.</text><abort /></take>
    <use>
        <if><test var='_arg2'></test>
            <then><text>Frotz what?</text><abort /></then>
            <istype item='$(_arg2)' type='item' />
            <then><set var='frotzed' op='thename'>$(_arg2)</set>
                <text>You cast frotz on $(frotzed), which begins glowing.</text>
                <light on='true' item='$(_arg2)' />
                <continue />
            </then>
            <else><text>You can only frotz inanimate objects.</text></else>
        </if>
    </use>
    <weight value='0' />
</item>


Programmer's Text Editors

   If you don't have a good programmer's text editor with syntax highlighting for XML (no, not MS Notepad or MS Word), try one of these:

Vim (Unix or Windows)
Vim (Vi Improved) is small, fast, and incredibly powerful. It does have a steep initial learning curve, but it has an extensive help system. Type ":help" first thing when you start it to read the tutorial. I use Vim for everything.
Kate (Linux)
Kate (KDE Advanced Text Editor) is not quite as small, fast, or powerful as Vim, but it's much easier to use. It's probably the best "beginning programmer's editor" I've ever seen. Kate is a standard tool in KDE3.
KWrite (Linux)
KWrite doesn't support XML out of the box, but you can choose Settings:Configure Highlighting:Highlight Modes, change Highlight to "HTML", and change the File Extensions to "*.html;*.html;*.xml", and it'll highlight XML just fine.
KWrite's not powerful, but it's fast.
BBEdit (MacOS)
BBEdit's fast, powerful, and easy to use. You have to register it to get syntax highlighting, but if you're going to use a Mac seriously, you ought to have it.
JEdit (any platform with Java)
JEdit is very powerful, but fairly slow; don't use it unless you have a fast machine with at least 128MB RAM. If you do, it's better than Kate, and runs on systems other than Linux.
TextPad (Windows)
TextPad's a decent editor. It handles multiple buffers well, and has syntax highlighting, but it's not otherwise remarkable. The user interface has some odd quirks, especially weird keybindings.
XMLSpy (Windows)
XML-specific editors are wonderful, but I find that I'm more productive with just a good text editor. The benefit is that it's impossible to make badly-structured documents with it.