This file is part of the TADS 2 Author’s Manual.
Copyright © 1987 - 2002 by Michael J. Roberts. All rights reserved.
Edited and portions by NK Guy, tela design.


Chapter Twelve


Multimedia TADS Fundamentals

HTML and Multimedia TADS

You don’t actually need to know much HTML to use multimedia TADS, since the normal TADS formatting sequences (\b, \n, \t, and so on) work the same way in multimedia TADS as they do in the standard TADS. In fact, you may want to continue to use the standard TADS formatting sequences wherever you can, since this will make it easier to move your game to the standard TADS system if you decide to do so at some point.

However, you will need to learn HTML to the extent that you want to use HTML features with TADS. An HTML tutorial and reference is, as they say, beyond the scope of this document. Fortunately, one of the benefits of HTML’s popularity is a copious supply of documentation. You should have no problem finding a book on HTML for almost any level of expertise at your local bookstore, and a great deal of introductory and reference information is available free on the web.

For the most part, you should be able to apply your knowledge of standard HTML to writing games with multimedia TADS; most of the tags related to formatting work the same as they would in any other HTML renderer.

However, there are a number of areas where multimedia TADS differs from standard HTML, particularly with tags that define the document structure, and you’ll eventually want to familiarize yourself with these differences as you start to use the more advanced features; refer to appendix H, Multimedia TADS Deviations from Standard HTML for complete details.


HTML Debugging

HTML is a computer programming language, so it has a strict syntax that must be obeyed in order for it to work correctly.

When a multimedia TADS interpreter encounters syntax in your HTML that it can’t understand, the system will normally simply ignore the entire tag sequence. This has the generally desirable effect of leaving the surrounding text intact, but the incorrect markup will not do what you wanted it to do. When you’re writing a game, you might find it desirable to see any errors in your HTML tags. HTML TADS for Windows provides a debugging window for this purpose. To enable the debugging window, you use a system-specific option; on Windows, add the -debugwin switch on the command line when you start HTML TADS:

    htmltads -debugwin mygame.gam

The debug window will show you HTML errors as they occur, along with the line of text that contains the error (this is a line of text that your game displayed).

Note that the debug window is automatically included when you run the new Multimedia TADS Debugger for Windows 95/NT, so you won’t need to include the -debugwin option when you run your game with the debugger.


Enable HTML with the “\H+” sequence

To start using HTML features, the first thing you must do is tell multimedia TADS that your game is going to use HTML. To enable old games to play unchanged, multimedia TADS starts up in “compatibility” mode, which means that it passes through all of the text in the game to the display without HTML interpretation. In order to get multimedia TADS to start interpreting HTML markups, you need to send a special formatting code. At the beginning of your game, at or around the first line of your init() routine, you should put the following TADS code:
    "\H+";

(ie: print out the special control sequence consisting of the three characters \H+ ) This doesn’t actually display anything on the screen, but it does tell multimedia TADS interpreters to enter HTML mode.

From this point on, multimedia TADS will interpret HTML markups in your game, allowing you to use the full power of HTML to format your game’s display. Usually, you will do this once, when your game starts running. If you’re using the std.t library, the easiest place to do this is in the commonInit function. Here’s an example:

   #include <adv.t>
   #include <std.t>

   replace commonInit: function
   {
      /* enter HTML mode */
      "\H+";
   }

Note: if you use the “\H+” sequence in your init() function, you should be careful to also use it in your restore-game code, since it is possible under certain circumstances for the interpreter to bypass your init() function entirely. This happens when the user starts the interpreter by opening a saved game file directly from the operating system shell, which is supported on some systems.

If your game includes a test for the global.restarting variable in the init() function, be certain to put the \H+ text in before the global.restarting code. That way \H+ will be output to the text formatter every single time the game is started up, regardless of whether the game is running from scratch or loading from a saved game file. If your game doesn’t include a test for global.restarting then this isn’t an issue, of course.

You can also convert a game more incrementally by turning on HTML only when you want to use it, and then turning it off again. To turn HTML back off, use the \H-”; sequence. If you only want HTML functions in a few limited places, you can turn HTML on and off selectively, to avoid any impact on the rest of your game. However, if you’re developing a new game for multimedia TADS, you’ll probably find it easier to turn on HTML mode at the beginning of the game and leave it on at all times, though a special system verb which prints the “H\-” sequence is useful for testing.


Special characters: < and &

When HTML mode is active, two characters become special, because they introduce HTML sequences. The first is the less-than sign, (“<”) which introduces an HTML tag. The second is the ampersand, (“&”) which introduces a character specifier sequence.

You probably won’t have a lot of either of these characters in your game’s text. Any that are present, though, will have to be converted to special character sequences that tell HTML that you want to display these characters. You need to convert each less-than sign to this sequence of characters:

  &lt;

You need to convert each ampersand to this sequence of characters:

  &amp;
Note that the special embedded expression syntax, which uses “<<” and “>>” to delimit an expression contained within a double-quoted string, does not need to be changed, and in fact must not be changed. You should continue to write embedded expressions just as you always have. For example:
  sdesc = "The blackboard has an equation scribbled
             on it: x &lt; << blackboard.xValue >>"
The reason that you don’t need to change the “<<” sequence for an embedded expression is that this syntax is used only by the TADS compiler. The compiler recognizes embedded expressions and removes them from your strings before the strings are placed in your .GAM file. HTML tags, on the other hand, are handled by the multimedia TADS interpreter. Since the “<<” sequence of an embedded expression is removed at compile time, the multimedia TADS interpreter never sees it, hence it doesn’t need to be changed for HTML.

HTML Markups

HTML formatting commands are called “markups,” because they’re used to “mark up” plain text with additional information. There are two kinds of markups: entities, which let you specify a single character using its name; and tags, which contain formatting, annotation, or structural information about the text.

Entities

An entity is simply a long way of writing a single character. Entities were invented for two reasons:

Tags

Tags are used to insert information about the text into the text. All HTML formatting is done with tags.

A tag starts with a less-than sign (“<”) and ends with a greater-than sign (“>”). After the less-than sign comes the name of the tag. For many tags, that’s all there is. For example, if you want to start a new line, you can simply write <BR> where you want the line break to occur. In other cases, you will also include attributes, which contain additional information for the tag.

An attribute can simply be a name, in which case the mere presence of the attribute affects the tag, or it can have a value. If it has a value, the value follows an equals sign (“=”) that follows the attribute’s name.

For example, the <HR> (horizontal rule) tag takes the NOSHADE attribute, which has no value but whose presence indicates that the rule is to be drawn as a simple line without any shading. So, <HR> draws a default, shaded line, and <HR NOSHADE> draws a line without any shading. The tag also takes an ALIGN tag, which takes a value indicating what type of alignment to use for the rule: LEFT, RIGHT, or CENTER. So, <HR ALIGN=CENTER> draws a horizontally centered rule, and <HR ALIGN=RIGHT NOSHADE> draws a right-aligned rule without shading.

Container Tags

Some tags are container tags. A container tag marks a run of text, and always has an ending tag that specifies where the contained text ends. Everything from the starting tag to the corresponding ending tag is contained in the tag.

The ending tag always has the same name as the starting tag, but has a slash before the name. So, the ending tag for <B> is </B>. Ending tags never have any attributes.

For example, the boldface tag, <B>, is a container tag; all of the contained text is shown in boldface:

    "Here's some <B>bold</B> text! ";

In this example, the word “bold” is displayed in boldface.

Container tags must use simple nesting. This means that, if one container is nested within another, the inner container must end before the outer container. You can never have overlapping containers, so this is illegal:

   /* This is not acceptable HTML */
   "Here's some <B>bold, <I>bold italic, and </B>italic</I> text! ";

This is illegal because the <I> tag is nested within the <B> tag, but the <B> tag ends before the <I> tag. To write this properly, you must make sure the inner tag, <I>, ends before the outer tag, <B>:

   /* This is OK */
   "Here's some <B>bold, <I>bold italic, and </I></B><I>italic</I> text! "

Using markups in TADS

Using HTML markups in TADS is simple: just insert them into the text you display.

For example, suppose you want to put a couple of things in boldface in a room’s description. You do this by putting <B> tags around the parts you want in bold, right in the text of the room’s description:

   coldCave: room
     sdesc = "Cold Cave"
     ldesc = "This is an extremely <B>cold</B> cave.
             A chilling wind blows in from the narrow passage to
             the north.  You don't feel like you can stand to stay
             here long; you're positively <B>freezing</B>! "
   ;

HTML works only in text you display. Don’t use HTML within programming code; it should only go in quoted strings that your game displays.

TADS only interprets HTML in text that you display. TADS ignores HTML everywhere else. In ordinary string manipulations, even if you use what might look like HTML tags, TADS will ignore them - until you display the strings, at which point TADS interprets the HTML for formatting the output. For example, consider this code:

   ampkeyVerb: deepverb
     verb = 'ampkey'
     action(actor) =
     {
       local x;

       /* THIS IS A BAD EXAMPLE - THIS WON'T WORK!!! */
       x := inputkey();
       if (x = '&amp;')
         "You pressed the <q>&amp;</q> key!\n";
       else if (x = '&lt;')
         "You pressed the <q>&lt;</q> key!\n";
       else
         "You pressed <<x>>!\n";
     }
   ;

This code will not work as you might expect. The problem is that the string comparisons won’t work, because TADS doesn’t attempt to interpret any HTML markups for ordinary string manipulation. The correct way to write the ampersand test is (x = '&'), and the correct way to write the less-than test is (x = '<'). Don’t get confused into thinking that you have to worry about HTML everywhere in your program, as you don’t. You only have to think about HTML when you’re displaying text to the screen.

Here’s the correct version of this code:

   ampkeyVerb: deepverb
     verb = 'ampkey'
     action(actor) =
     {
       local x;

       x := inputkey();
       if (x = '&')
         "You pressed the <q>&amp;</q> key!\n";
       else if (x = '<')
         "You pressed the <q>&lt;</q> key!\n";
       else
         "You pressed <<x>>!\n";
     }
   ;
An exercise for the reader: Since this documentation is itself written in HTML, coding examples that use markup-significant characters (such as the examples above) must use entities to represent the markups. To show you something like &amp; in your web browser, for example, we must write &amp;amp; in the source code for this page. You might find it amusing as you hone your HTML skills to try writing out some of the HTML required to show the examples above or other examples on this page. To check your work, simply look at the HTML source for this page by opening the page in a plain text editor rather than a web browser.

The old and new status line.

One of the limitations of text-only TADS is that its status line format is rather inflexible. While this simplified game development, it made it impossible to get effects beyond the normal status line display.

The traditional TADS interpreter is hardcoded to produce an Infocom-style status line. In other words, the room name is printed on the left side of the bar and the player’s score and number of moves (separated by a / ) are printed on the right side of the bar. The room name is displayed by the statusLine hardcoded method in the room code. Any text that’s output by that method is automatically installed into the left side of the status line. The right side of the line is generated by the setscore() function (which in turn calls the scoreFormat() function, at least in TADS 2.4.0 and higher). Any time that function is called the text passed to it is written to the right side of the line.

The functionality of the traditional TADS status line grew over time, which is why the left side is controlled by a method and the right side by a function. TADS 1 didn’t allow you to change the right side of the status line - that feature was added later.

Multimedia TADS removes this limitation. In multimedia TADS, the status line is entirely under your control. Multimedia TADS provides a “banner” feature, explained in detail in the next section, which lets you designate that a block of text is displayed in a panel at the top of the window. This panel can be as large or small as you like, and can contain anything that you can use in the main HTML window - fancy formatting, graphics, and any other HTML features. In fact, you can go beyond this by using multiple status lines - you can have as many banners as you like (although this is obviously limited by the available window area). You can also make status lines come and go as needed throughout the game.

There is a small price to pay for all of this new flexibility, though: you must do all of the status line formatting. Whereas the status line formatting is done automatically by the user interface in the standard TADS, in multimedia TADS the game author must provide HTML markups to format the status line.

Fortunately, adv.t has built-in support that will automatically generate the necessary HTML commands to emulate the standard status line style when in HTML mode. You can replace this with your own status line formatting if you want, but for simplicity the default handling is available. To enable the default status line formatting with HTML markups, recompile your game (assuming it includes adv.t) with the preprocessor symbol USE_HTML_STATUS defined:

    tc -D USE_HTML_STATUS mygame.t

(If you’re using a Macintosh, use the box called “define preprocessor symbols” to define this symbol. Open the box and enter USE_HTML_STATUS on a line in the list of symbols to define.) Refer to the room object’s statusLine routine (the one defined within the #ifdef USE_HTML_STATUS section) to see how the traditional status line formatting translates to HTML. If you want to customize the formatting, simply replace room.statusLine with your own implementation, using the replace TADS language feature. If you’re not using adv.t in your game (or you’re using your own version of adv.t), you can copy that snippet of code from adv.t to your own game.


Banners.

BANNER is a tag from HTML 3.0 (not included in HTML 3.2) that allows a document to create a non-scrolling area on the screen, and display arbitrary HTML markups within this area. Multimedia TADS uses BANNER, with a few extensions, to implement the “status line” that traditional text adventure games display across the top of the screen to show, for example, the current location and score.

The BANNER feature is similar to the “frames” feature that most Web browsers provide, but is more suitable for multimedia TADS games than frames. (Multimedia TADS does not support frames.) The fundamental difference between BANNER and frames is that the contents of a banner are specified directly within the main HTML text stream, whereas a frame simply contains a pointer to a separate URL, which provides the contents of the frame. Using a separate URL doesn’t fit into the multimedia TADS model, so frames are not appropriate. Fortunately, BANNER provides the same type of functionality, and is a good fit for the way multimedia TADS works.

BANNER is a container tag. The markups between the <BANNER> and </BANNER> tags are the contents of the banner. A banner can contain almost anything, but cannot contain a TITLE tag or another BANNER tag (banners cannot be nested; another <BANNER> tag within a banner is ignored).


Banner ID

BANNER takes an ID attribute that lets the document assign the banner an identifier name. This name is arbitrary; its purpose is to name the banner, so that subsequent BANNER tags can refer to the same area on the screen. When multimedia TADS formats a BANNER tag, it first looks to see if it already has a banner on the screen with the same identifier; if so, it clears all of the markups out of the area that the banner is using on the screen, and formats the new contents. If no BANNER with the given ID is present, multimedia TADS creates a new banner area, and displays the contents of the banner in the new area. The system remembers the ID of the new banner, so that subsequent tags can replace the contents of the banner with a new display.

The ID feature is useful for banners that are updated from time to time, since it allows you to replace the contents of the banner while leaving it at the same position on the screen. This is how status lines are implemented in multimedia TADS - the status line is simply a banner at the top of the screen, and on each turn, the game replaces the status line contents to show the new game status.


Banner Positioning

The BANNER tag takes an ALIGN attribute that specifies where the banner goes on the screen. Four values are possible: TOP, BOTTOM, LEFT, and RIGHT; the default value is TOP. These values determine where the banner goes, as follows:

Each banner effectively splits the input window in two. Initially, before there are any banners, the input window takes up the entire area of the main multimedia TADS window. The first banner you display divides the window into two pieces, according to the banner’s alignment. For example, if the first banner you display is TOP-aligned, the main window will look like this:

    First Banner Contents    




    Input Window    



Each subsequent banner splits the remaining input window further. Note that this means that every banner is rectangular, and the input window is always rectangular. Banners can never fragment the window in such a way as to leave part of the window unused.

For example, if you now display a second banner, this time with LEFT alignment, the window will change to look like this:

    First (TOP) Banner Contents    
Second
(LEFT)
Banner
Contents




    Input Window    



Note that the order of the banners in the example above is important, in that it determines that the first banner takes up the full width of the main window, and the second banner is shortened vertically by the size of the first banner. If you wanted to achieve the opposite effect, you would simply reverse the order of the banners - you’d display the LEFT banner first, and the TOP banner second. This would achieve a window layout like this:

First
(LEFT)
Banner
Contents
Second (TOP) Banner Contents




    Input Window    



Note further that in none of the cases above are any of the windows overlapping. Banners are always sized to fit the areas that they’re allocated, and the banners tile the available area.


Coloring the Banner

You can specify the text and background colors of a banner using a BODY tag within the banner. You can also use BODY to specify the background image for the banner. A BODY tag within a banner affects only the banner, so the each banner and the main input window can all have different color settings.

Size Attributes

BANNER takes HEIGHT and WIDTH attributes that let you specify the size of the banner on the screen. Because banners are always constrained in one dimension according to their alignment, only one of HEIGHT or WIDTH will be meaningful for a particular banner.

For a horizontal banner (ALIGN=TOP or BOTTOM), only HEIGHT is meaningful, because horizontal banners always occupy the full width of the input window. For a horizontal banner, if no HEIGHT attribute is present, BANNER sets the size of the banner’s screen area to be the same height as the contents. If a HEIGHT value is provided, it specifies the height of the banner in pixels. You can also specify the height as a percentage of the main window height, by placing a percent sign (“%”) after the height value. For example, to create a banner that takes up the bottom quarter of the main game window, you’d write something like this:

   <banner id='myBanner' align=bottom height='25%'>

The HEIGHT attribute can also be set to the value “PREVIOUS”, rather than a pixel or percentage height. This specifies that, if banner is already being displayed (i.e., the ID matches the ID of a previous BANNER), the height is left unchanged. If HEIGHT=PREVIOUS is specified and the banner is not already displayed, the default behavior applies (i.e., the banner’s height is set to the height of the contents). For banners that are frequently updated, HEIGHT=PREVIOUS is usually desirable, because this makes the banner’s screen area remain stable. The default status line implementation uses HEIGHT=PREVIOUS to keep the status line fixed in position throughout the game.

For a vertical banner (ALIGN=LEFT or RIGHT), only WIDTH is meaningful. As with HEIGHT, WIDTH can specify a width in pixels, a percentage of the main window’s width, or the special value “PREVIOUS”. If WIDTH is not specified for a vertical banner, the system sets the width of the banner to the minimum width in which each “unbreakable” item will fit (individual words and pictures are unbreakable because they can’t be split across multiple text lines).

If you’re having trouble making a banner’s spacing and sizing come out exactly the way you want it, you may want to consider using a table within the banner. Tables give you the most direct control of spacing and sizing in HTML. Using a table may be especially helpful with a vertical (LEFT or RIGHT) banner, since you’ll probably want to be especially conservative with screen space in a banner running down one side of the main window.


Borders

The BORDER attribute lets you specify that the banner should be drawn with a border at its inside edge. For a TOP banner, the inside edge is at the bottom; for a LEFT banner, it’s at the right edge; for a BOTTOM banner, it’s at the top; and for a RIGHT banner, it’s at the left edge.

You may want to use a border if the banner is the same color as the window that appears just inside it (this adjacent window may be another banner or may be the main game window). BORDER takes no value; if it’s specified, a border is drawn, otherwise the banner is drawn without a border.


Removing a Banner

The REMOVE attribute specifies that a banner is simply to be removed. The banner currently being displayed whose ID matches the ID specified in the <BANNER REMOVE> tag is removed from the screen. When <BANNER REMOVE> is specified, <BANNER> is not a container, so no </BANNER> tag is allowed.

The REMOVEALL attribute specifies that all banners are to be removed. When this attribute is used, no ID is needed, since every banner will be removed. This tag is useful for abrupt global changes, such as restarting the game, when you want to reset the display to its initial state.


Interaction with UNDO, RESTART, RESTORE

If you use banners, you may find certain aspects of banner behavior confusing. To understand how banners interact with certain operations that make abrupt changes to the overall state of the game, you must keep in mind that banners are part of the display, and not part of the game state.

Certain commands make sweeping changes to the game state directly, without going through any of the steps that your game would normally go through. In particular, UNDO, RESTART, and RESTORE all update the internal state of the game to some previous game state. However, these commands will not affect any banners you have displayed, because banners are part of the display state, not the game state, and these commands never affect the display state.

Banners are thus not affected by UNDO, RESTART, and RESTORE for the same reason that text displayed previously on the screen is not affected. If you type UNDO, the text that was displayed by the command being undone is not erased from the screen - more text is simply added after it. The same holds for banners.

Depending on how you use banners in your game, you may find this behavior undesirable. For example, if you use a banner to display a picture of the current location, it’s a problem if the picture isn’t updated when you restore a game.

If you have banners that you use to display information that changes in response to changes in game state, the best approach to dealing with UNDO, RESTART, and RESTORE is to update the banners on each turn from within a daemon. This will ensure that the banners will always show the correct state at the start of each turn. (This is effectively how the status line works, incidentally; the status line is updated whenever a new command line is about to be read, so it always displays the correct information even though its contents aren’t part of the game state and thus aren’t updated by UNDO, RESTART, or RESTORE.)

Alternative approaches could work just as well, depending on your game. For example, if you have banners that change infrequently, you could define a routine to update the banners to the current state, and explicitly call this routine whenever something happens in the game that would affect the banners. You could then add a call to this routine to the action methods for the undo, restart, and restore deepverb objects (using the modify mechanism to change the adv.t object definitions).


Example of a Status Line

The default status line implementation in adv.t uses BANNER to provide a status line similar to the style used in text-only TADS interpreters.

    statusLine =
    {
        "<banner id=StatusLine height=previous>
        <body bgcolor=statusbg text=statustext><b>";

        self.statusRoot;

        "</b><tab align=right><i>";

        say(global.score); "/";
        say(global.turnsofar); " ";
        
        "</i></banner>";
    }

The first line contains the BANNER tag. This uses the default TOP alignment to make the status line a horizontal band at the top of the main window. It also gives the banner the ID “StatusLine”, so that the same banner window can be reused every time the status line is updated. (The ID “StatusLine” isn’t anything special - it’s just a way identifying the banner so that each update goes to the same window. You can use any ID you want for each banner, as long as each banner has a unique name relative to the other banners in your game.)

The second line uses the BODY tag to set the banner’s background and text color. These use the appropriate parameterized color settings for the status line.

The next line calls the statusRoot method to display the room’s name (usually via its sdesc property, although some rooms override this to provide additional information, such as “in the raft”).

The next line uses the <TAB ALIGN=RIGHT> tag to align the remainder of the current line against the right edge of the banner window. Whenever the window is resized, the system will reformat the text so that it’s aligned properly in the available space.

The next two lines display the current score and the number of turns played so far in the game.

Finally, the last line closes the banner. Since BANNER is a container tag, the closing </BANNER> is required, so that the system can figure out where the banner’s contents end and the rest of the main window’s text resumes.


Example of a Command Bar

You can use BANNER to provide a list of simple commands that’s always displayed. As an example, here’s some code that displays a list of commands in a vertical banner at the left edge of the window.
   "<banner id=CommandBar align=left width=75>
    <body bgcolor=yellow textcolor=black>
    <br><a href='inventory'>inventory</a>
    <br><a href='score'>score</a>
    <br><a href='look'>look</a>
    <br>
    <br><a href='go north'>go north</a>
    <br><a href='go south'>go south</a>";

    // add other commands as desired

    "</banner>";

Because of the dynamic nature of banners, you can extend the command bar by always updating it with a set of commands relevant to the current situation. You can do this by adding to the status line code, for example, and building a new banner on each turn with the same ID (which has the effect of replacing the old banner, but keeping the same screen area), and containing the commands currently available.


Splitting a Banner Area

You may find yourself in a situation where you want to divide a banner into two pieces, to achieve a layout something like this:

Banner 1 Banner 2




    Input Window    



The BANNER feature doesn’t provide a direct way of doing this. However, you can achieve a similar effect using a single banner that contains a table. To do this, simply specify a table with one row and two cells:

   "<table width='100%' cellspacing=0 cellpadding=0>
    <tr align=center valign=middle>
    <td bgcolor=yellow>This is the left half
    <td bgcolor=green>This is the right half
    </table>";

Multimedia TADS Sounds and Music

Multimedia TADS provides an extension to HTML that allows a game author to use sound effects and music within a game. Standard HTML doesn’t have any support for sound, and the popular browsers mostly delegate sound support to third-party “plug-in” products, so there are no good examples of HTML sound extensions that TADS could have used as a basis. Because of this, the sound features in multimedia TADS aren’t based on any existing HTML implementations or standards.


Sound and Music Formats

Multimedia TADS supports three sound formats as of version 2.2.7: MIDI for music (in the standard MIDI file format), Windows WAV (waveform digitized audio) for uncompressed digitized sound effects; and MPEG 2.0 Audio layers II and III for compressed, digitized sound and music. MPEG support was added in version 2.2.7; previous versions only supported the MIDI and WAV formats. MPEG 2 layer III is commonly known as “MP3”.

While these formats aren’t universal standards, they are widely supported and well-documented. Many multimedia authoring tools will produce files in these formats, and a large number of public domain files are available for all of the formats. In addition, together, these formats address most of the needs that game authors are likely to have when designing games. WAV provides high-quality digitized recordings that can reproduce essentially any sound, while MIDI provides a versatile and compact format for storing music. MPEG is a compressed format that offers a compromise between file size and recording quality; MPEG works well for both sound effects and music.


The MPEG Audio Format

The MPEG 2.0 audio format provides variable compression for digitized sound effects and music. This format allows you to substantially reduce the size of your sound files.

The MPEG 2.0 standard defines three different compression formats, referred to as layers I, II, and III. These layers are essentially independent formats, but for most purposes, layer III (MP3) delivers the highest quality and best compression of the three layers.

Note that some encoders provide another layer, usually called “2.5”. This uses a proprietary format, and multimedia TADS does not support this format. When encoding a sound, please be sure not to use layer 2.5, or the sound will not play.

The MPEG format is “lossy,” which means that it achieves better compression than might otherwise be possible by discarding some of the information in the original sound recording. The amount of loss is parameterized and thus adjustable. When you’re encoding a recording, you can select a compression rate that will provide the best compromise between sound quality and encoded data size. The more data loss you’re willing to accept, the smaller the encoded file will be.

MPEG is supported by numerous tools, including freeware, shareware, and commercial products; most platforms have at least one or two good MPEG encoders and players. You should have no problem finding MPEG software resources on the web; a good starting point is www.mpeg3.org.

In multimedia TADS, MPEG resources must be named with one of the following suffixes:

    .MPG
    .MP2
    .MP3

Conventionally, .MPG is used for layer I files; .MP2 for layer II files; and .MP3 for layer III files. However, the MPEG standard defines a common header format for all three layers, so multimedia TADS can automatically sense which type of decoding to use, as long as it can see that the file is an MPEG resource of some kind.

Because MPEG audio is suitable for both music and sound effects, the multimedia TADS sound system allows MPEG audio to be used in any layer, and makes no assumptions about which layer is appropriate for a particular sound. Therefore, all <SOUND> tags with MPEG resources must specify a layer.


Sound Layers

Sounds in multimedia TADS are divided into four layers: the background layer, the background ambient layer, the ambient layer, and the foreground layer. (Note: these layers don’t have anything to do with MPEG layers, which are simply different encoding formats.)

The background layer is used for music. Background music can repeat to provide a continuous soundtrack, and you can program multiple selections that play one after another. You can change the background music whenever you want; for example, each room can have its own background music.

The bgambient (background ambient) layer is used for continuous digitized sound effects. The purpose of this layer is essentially the same as that of the background layer, but the bgambient layer is used for digitized sound effects instead of music.

The ambient layer is used for sound effects that occur in the background, but not continuously like the background music. You can set up a group of ambient sounds that will play randomly to enhance the atmosphere. As with background music, you can change the ambient sounds whenever you want; you can, for example, provide an appropriate set of ambient sound effects for each location.

The foreground layer is used for sound effects that play immediately in response to an event in the game. For example, you could play a sound effect in the foreground when the player opens a door in the game.


Queueing Sound

Sound is an inherently time-based medium. Text adventures, in contrast, are essentially static, except to the extent that the game state evolves in bursts in response to commands from the player. To bridge this gap, multimedia TADS provides automatic management of the time domain. You simply specify which sounds are to be played and in what order, and multimedia TADS takes care of the timing details.

At any given time, multimedia TADS allows one active sound in each layer. The background sound must be MIDI or MPEG, and the bgambient, ambient, and foreground sounds must be WAV or MPEG. The layers are treated independently; a sound in one layer doesn’t normally affect sounds in the other layers.

However, the hardware or the operating system may limit the number of sounds that can be played simultaneously. In these cases, a bgambient sound will temporarily suspend a background sound, an ambient sound will temporarily suspend a bgambient or background sound, and a foreground sound will temporarily suspend an ambient, bgambient, or background sound. Except for this type of temporary preemption, though, the layers do not interact. On systems that are capable of mixing multiple sounds at once, this type of preemption will not occur, and all of the layers will play simultaneously.

Within a layer, sounds are queued. This means that sounds play sequentially, in the order that you specify the sounds. When you start a sound, you specify how it interacts with other queued sounds and how it plays:

This layered approach follows the sound hardware architecture common in Windows PCs. Most PC sound cards have a synthesizer, which the system uses to play back a MIDI sequence, and a separate digital-to-analog converter, which the system uses to play back digitized audio. Both of these subsystems can be used simultaneously, which allows MIDI music and digitized sound effects to be played back together. Windows can further mix multiple digitized sound effects together for simultaneous playback (via the DirectSound system).

Despite the PC-centric design of the layer system, it’s possible to adapt the model to other hardware, as HyperTADS for Macintosh demonstrates. On some systems, however, the hardware may not allow playing digitized and synthesized audio simultaneously. In these cases, the background music can be temporarily suspended whenever a digitized sound is played, then resumed after the digitized sound ends. While this will slightly degrade audio quality, the overall sequence of sounds will be essentially the same as the overlapped version.


The <SOUND> tag

The sound features of multimedia TADS are activated using a new tag, <SOUND>. This new tag is not an element of the standard HTML definition; this is a TADS extension.

Attributes of the SOUND tag specify the action that the SOUND tag should perform.

The SRC attribute specifies the name of the resource containing the sound data. The resource name must end in .WAV for a wave file, .MID or .MIDI for a MIDI file, or .MPG, .MP2, or .MP3 for an MPEG audio file. Refer to Resources in Multimedia TADS for information on how to include resource files in your game.

The LAYER attribute specifies the layer containing the sound. The value of the LAYER attribute must be FOREGROUND, BGAMBIENT, AMBIENT, or BACKGROUND. Although you should always specify a layer for each sound, multimedia TADS can sometimes infer the correct LAYER attribute for a sound based on its other attributes:

The RANDOM attribute lets you specify the probability of playing a sound in the ambient layer. Usually, you will want a sound in the ambient layer to be played randomly from time to time; this attribute specifies the probability that the sound will be played at any given time. This attribute takes a value from 1 to 100. A low value makes the sound play infrequently; a value of 100 causes the sound to play at every opportunity (i.e., whenever another sound in the same layer isn’t playing).

The REPEAT attribute lets you specify how many times a sound should play. This can be used for all layers. This attribute takes a numeric value specifying the number of times to play the sound, or a value of LOOP to indicate that the sound plays repeatedly until cancelled.

If you don’t specify a REPEAT attribute for an ambient sound, and the sound has a RANDOM setting, the default REPEAT=LOOP will be used. If you do specify a REPEAT parameter for an ambient sound, the sound will be played a maximum of the given number of times; the sound will still play only when the system randomly chooses the play it, the probability of which is controlled through the RANDOM attribute.

If you specify a REPEAT attribute for a foreground sound, the sound will be played the given number of times in sequence.

If you specify a REPEAT attribute for a sound in the background or bgambient layers, the sound will be played the given number of times. The actual sequence in which the sound is played depends on the SEQUENCE attribute used in the sound and other background sounds.

The SEQUENCE attribute is used to control the order of repetition for a group of background sounds; it’s meant primarily for use with the background and bgambient layers. The SEQUENCE value can be REPLACE, RANDOM, or CYCLE. REPLACE causes the sound to remove any previous background sounds from the queue when the new sound starts. RANDOM leaves any previous sounds in the queue, assuming they have enough REPEAT cycles remaining; when the new sound is finished, if no other background sounds are waiting to be played, the system randomly picks one of the sounds remaining in the queue and plays it again. CYCLE is similar to random, but goes back to the first sound in the queue when the new sound is done.

You can use SEQUENCE to provide transitions with the music. For example, you could specify REPEAT=1 for introductory music, then specify REPEAT=LOOP and SEQUENCE=RANDOM for a set of ongoing background music. By using SEQUENCE=RANDOM, you can prevent the music from becoming too repetitive by randomly varying the order of the tracks.

The INTERRUPT attribute (which takes no value) specifies that the sound is to abort any currently playing sound in the layer and start the new sound immediately. You should usually only use INTERRUPT with foreground sounds.

The CANCEL attribute turns off all currently queued sounds. With no value, a <SOUND CANCEL> tag cancels all queued sounds in all layers. You could use this, for example, when switching to a new room, to turn off all sounds. You can also specify a layer with CANCEL to specify that sounds in that particular layer are to be cancelled; the layer values FOREGROUND, AMBIENT, and BACKGROUND are allowed. For example: <SOUND CANCEL=AMBIENT> cancels only the sounds in the ambient layer.

The ALT attribute lets you specify a textual description of the sound. This could be used by a version of the interpreter that doesn’t support sound to display a description of the sound (the Windows version of the interpreter currently ignores this attribute).

FADEIN and FADEOUT specify the number of seconds over which to fade the music or sound effect in and out. These are currently ignored, but may be used in the future.


Clearing the screen.

Because the <SOUND> tag is part of the formatting information that makes up the display window, sounds are conceptually part of the page on which they appear. This means that all sounds are cancelled as soon as you clear the screen using the clearscreen() function.

If you want to perform full-screen animation or other effects that require erasing the display, but you want your sounds to continue playing, you must use a banner. A banner lets you replace the information displayed on part of the screen without clearing the entire window. Note that you can use a banner that covers the entire display window (by using the HEIGHT='100%' attribute) if you want to use the entire window for your animated effects.


Sound portability issues.

At the time of this writing, the MIDI, WAV, and MPEG audio formats are supported on both the 32-bit Windows and the Macintosh versions of multimedia TADS.

If and when other multimedia TADS ports appear, it is likely that some of the audio features will be supported, but it is possible that not all of the formats will be available. Sound requires specialized hardware; not all computers have any sound capabilities, although most reasonably modern machines do. The sound resource formats that multimedia TADS supports are not universal standards, but they are very widely used de facto standards and hence are widely supported. It is possible, though, that some future ports will not have access to support libraries for all of the audio formats.

As a game author, you should consider the trade-offs in using sound in your game. If you want to use sound, you should keep in mind that some players will be using systems that don’t provide sound support, and some will choose to play with sounds turned off.

Fortunately, in an adventure game, it’s relatively easy to use sound as an enhancement rather than as a crucial feature of the game. One of the primary benefits of using sound in a game is that it can add to the atmosphere and mood of the game; even though this type of sound can add a lot to the game, it can be be omitted without ruining the game, since the game will still be fully playable.

Unless you don’t mind limiting your audience, you should be careful to avoid using sound effects that provide crucial information. Whenever you use a sound effect as a clue, you should add some textual description of the sound as well, so that the game is still playable without sound.


Resources in multimedia TADS

If you’re a Macintosh or Windows system programmer (or you’ve done any other type of graphical user interface programming), you’re probably familiar with the term “resource,” meaning a bit of data, usually binary, that’s external to a program, and which is loaded and used by the program as it runs.

Resources in this context are used for things such as icons, bitmaps, menu definitions, and other types of initialized binary data that would be inconvenient to type in to a C program directly; resources are also used to externalize things such as strings, so that they can be changed without recompiling the program (which is useful when translating a program to a different national language, for example). On most GUI systems, the operating system provides a set of tools, programmatic interfaces, and file format definitions for manipulating resources.

Multimedia TADS uses the term “resource” for a similar concept, although the implementation is quite different. Multimedia TADS resources are not implemented using operating system resources. To avoid any confusion, keep in mind that normal operating system resources are never used in the multimedia TADS context.

Multimedia TADS allows the game author to incorporate certain types of binary data, such as JPEG and PNG images, into a game. With normal HTML in a normal Web browser, these objects are referenced using URLs (“Uniform Resource Locators,” the filename-like strings that identify web pages and graphics; URLs usually look something like “http://www.somewhere.com/dir/whatever.htm”).

However, multimedia TADS is not a normal Web browser, and it doesn’t interpret object references as URLs. Instead, it uses resources.


Specifying resource names

A game author uses a resource by referring to the resource from an HTML tag in the game’s text. When the game displays the tag, multimedia TADS loads the resource and displays it as specified by the tag.

As mentioned earlier, with normal HTML, this type of reference is simply a URL that points to a file stored on a web server. With multimedia TADS, the reference is instead a resource name.

At its simplest, a resource name is very much like a relative URL - that is, one which is specified relative to the address of the page that references it, and therefore doesn’t contain any protocol or absolute path prefix. This type of URL reference might look like this:

   <IMG SRC="background.jpeg">

This tells the browser to load an image from a file called “background.jpeg”, looking in the same location as the current page.

Multimedia TADS resource references work very much like this, because they’re simply filenames. The location of the “current page” for multimedia TADS is always the directory that contains your .GAM file.

For example, support you’re running Windows 95, and the .GAM file you’re working on is called C:\TADS\GAMES\MYGAME.GAM. The root location where multimedia TADS will start looking for resource files is the directory containing the .GAM file, C:\TADS\GAMES. Now, suppose you use this tag in your game text:

   <IMG SRC="picture.jpg">

Multimedia TADS will load the image from the file C:\TADS\GAMES\PICTURE.JPG, since it looks for the file you specify in the directory containing the .GAM file.


Relative Paths

The name of a resource can include a “relative path,” using roughly the same format as a relative URL. Since multimedia TADS doesn’t interpret actual URLs, you can’t start a resource name with “http://” as you would an absolute URL; instead, you use a path that’s relative to the current location (which is always the directory containing the .GAM file), just as you could use an URL relative to the current page.

Multimedia TADS resource names that use relative paths always use forward slashes (“/”) for the path separator characters, regardless of what conventions your operating system uses. (DOS and Windows use backslashes (“\”), Macintoshes up to MacOS 9 use colons (“:”) and UNIX machines including MacOS X use slashes (“/”).) TADS internally converts these paths into appropriate filenames for the local system. Because resource names always use a uniform notation, regardless of the type of operating system you’re using, you don’t have to worry about changing your game to make it run on other operating systems.

Suppose you’re running HyperTADS on a Macintosh, and your .GAM file is called Macintosh HD:TADS:Games:MyGame.gam. Now suppose your game displays this tag:

   <IMG SRC="pics/skull.png">

HyperTADS will convert this to a Macintosh filename, treating it as a path relative to the folder containing the .GAM file, so it will look for a file called Macintosh HD:TADS:Games:pics:skull.png.


Case Sensitivity

You need to be careful about using upper- and lower-case letters in your resource names. Multimedia TADS does not itself treat case as significant, but some file systems (notably UNIX, including MacOS X) do. If you’re developing your game on an operating system with case-sensitive filenames, you’ll need to use the exact mixture of upper- and lower-case letters in your resource references as you do in the actual filenames. One recommended approach is to use lowercase text for everything to avoid any problems.

Note that the multimedia TADS resource mechanism is not case-sensitive. So, if you develop a game on a system with case-sensitive filenames, and then you bundle your resources into the .GAM file for distribution, the resource names will not distinguish case in the version your players receive. While this may appear at first glance to simplify things for you, it actually can create a problem: if you have two resources whose names differ only in case, multimedia TADS will treat them as separate resources as long as they’re in external files, but it will not be able to tell them apart after you bundle them into the .GAM file. So, if you’re developing on a case-sensitive operating system, be careful that your resource names are all unique irrespective of case.

Note that resource names only need to be unique within a directory. You may still want to avoid using the same resource name for different files in different directories, because of the confusion it might create for you, but Multimedia TADS will distinguish files with the same name based on their paths, regardless of whether you’re using external files or bundled resources.


Image types

Multimedia TADS supports two image formats: JPEG and PNG. Ideally, Multimedia TADS would support only one format, since this would make it easier to port multimedia TADS to new operating systems; however, no single image format adequately addresses the full range of needs for storing images. Fortunately, the JPEG and PNG formats complement one another very well, so between the two, most needs should be met.

Note that the GIF format is not supported. Although GIF is a widely deployed and popular image format, I chose not to support it in multimedia TADS due to patent licensing restrictions on the GIF data compression system. PNG provides all of the benefits of GIF (and more), without the onerous legal restrictions encumbering GIF, and is becoming widely supported.

You can learn more about the PNG format at http://www.cdrom.com/pub/png/ . This site includes information about tools that support PNG. Even if the graphics software you prefer to use doesn’t support this format, conversion tools are available that produce PNG files from files in the other popular formats.


Sound types

Multimedia TADS supports three sound formats: MIDI, WAV, and MPEG Audio 2.0 (layers I, II, and III). Refer to the sounds and music section of this chapter for information on the sound features in multimedia TADS. For more details see the section on the sound tag, above.

Filename suffixes

Multimedia TADS determines the type of object that a resource contains based on the resource’s suffix. You must always use an appropriate suffix when naming a resource. Here are the valid suffixes:

Note that the suffix always begins with a period.


Embedding resources in a .GAM file

To make it easy to distribute a game, you can embed all of your resources into your .GAM file. Once the resources are embedded, you only have to distribute the .GAM file. (This also makes it a little more work for players to “cheat” by browsing the images in your game; the temptation could be overwhelming if you were to distribute your game with a set of .JPG files.)

Since you may not want to go to the trouble of embedding your resources in the .GAM file while you’re developing your game (since you’ll probably be recompiling the game frequently), the .GAM file embedding mechanism is strictly optional. Most authors will want to use external files while developing a game, and then bundle everything into the .GAM file when building the distribution version of the game. You generally won’t want to bundle resources into the .GAM file while working on the game, since you’d need to apply the extra resource bundling step each time you compile the game.

Note that, apart from the possible differences in case sensitivity between your operating system and the multimedia TADS resource mechanism, you won’t have to make any changes in your game to switch between using external files and bundled resources. The bundling mechanism stores the resources using the same name they’d have if they were external files.

To embed resources into a .GAM file, you use the TADSRSC tool. (This tool is not new, although it’s been extended to handle HTML resources with this version of TADS. TADSRSC was formerly provided to bundle external functions into a .GAM file; this feature has never been widely used, since a.GAM file that depends on an external function is not portable, because an external function is simply native machine code for a particular system.)

The simplest way of using TADSRSC is to store all of your resources in one or more subdirectories of the directory containing the .GAM file. Since relative paths work best for external files if you’re working this way, you’ll probably want to arrange your resources into this type of directory structure anyway.

Suppose you have your resources in two subdirectories of the directory containing your .GAM file; the subdirectories are called Rooms and Objects. Using external files, you’d refer to resources in one of these directories using a tag like this:

   <IMG SRC="Rooms/Cave.jpeg">

To bundle all of these resources into your .GAM file, you’d first compile your game as normal, then you’d run TADSRSC on it:

   tadsrsc mygame.gam Rooms Objects

This invokes the TADSRSC tool, and tells it to store every file in the Rooms and Objects subdirectories in your .GAM file. TADSRSC stores these resources using the same names they’d have if they were external files, so your cave picture gets stored as a resource called Rooms/Cave.jpeg in the .GAM file. (Macintosh users should have a look at the page of directions for using TADSRSC under MacOS)

Note that you need to run TADSRSC each time you compile your game, because the TADS compiler overwrites any existing copy of your .GAM file each time you compile your game. When you refer to a resource, Multimedia TADS always looks for the resource in the .GAM file first. If it can’t find a resource in the .GAM file, it looks for an external file.


Using External Resource Files for Multiple Configurations

If you’re planning to distribute your game on CD-ROM, or better yet DVD-ROM, you’re probably not too concerned about how big your game is going to be when you bundle together all of your image and sound files. However, if you’re planning to distribute your game over the Internet, you probably will be concerned about the total size of your distribution files, and you may want to accommodate players who have slow network connections.

One approach to accommodating players who don’t want to download very large game files is simply to be conservative in your use of graphics and sound resources. Multimedia TADS allows you to use graphics and sounds as heavily or lightly as you like; if you use graphics and sound in only a few places, where they will provide the greatest impact, you can keep your total distribution size within reason.

An alternative approach that some game authors may wish to consider is to offer their games in multiple configurations. The idea is that you offer your game in two or more pieces: a “core” file that everyone downloads, which includes the .GAM file plus the minimum set of resources; and one or more add-on files that people can download at their option, and which contain additional resources that you consider optional. Alternatively, you could provide one file that contains full-quality versions of your resources, and a separate file that contains lower-quality (using fewer colors, for example, or lower resolution digitized sound) and therefore smaller versions of the same resources; people with slow connections would be able to download the lower-quality version if they wanted, but those who had a fast network connection (or lots of patience) would still be able to get the full-quality version.

To facilitate these types of configuration options, multimedia TADS lets you put your resources into separate files from your .GAM file. With external resource files, you can still bundle a group of files into a single file for easier distribution, but now they’re separated from the .GAM file for more versatile configuration.

Note: the new external resource file mechanism requires the TADS resource manager (tadsrsc) version 2.2.4 or higher.


Creating External Resource Files

You prepare a secondary resource file using the same resource manager as you use to add resources to your .GAM file. The only difference is that, in order to create your external resource file in the first place, you must use the -create option on the resource manager command line:

   tadsrsc -create mygame.rs0 -add Rooms

The -create option tells the resource manager to create a new file rather than look for an existing file. You would never use this option with a .GAM file, of course, because the TADS compiler creates the .GAM file before you add resources to it; with a separate resource file, there’s no prior compilation step, so you need to create the file directly with the resource manager the first time you use it.


How Multimedia TADS Loads External Resource Files

Whenever multimedia TADS loads a game, it looks to see if there are any files in the same directory as the game with the same name as the game and the suffix “.rsN”, where N is a digit from 0 to 9. For example, if your game is called GOLD.GAM, multimedia TADS will look in the same directory as GOLD.GAM for files called GOLD.RS0, GOLD.RS1, GOLD.RS2, and so on. Multimedia TADS will open each file and add its resources to the resources in the .GAM file.

A resource in an external resource file overrides a resource of the same name in the .GAM file. This allows you to place your minimum, core set of resources in the .GAM file, so that everyone who downloads your game has at least that minimal set of resources, and then provide an “upgrade” resource file to players that don’t mind the additional download. Since the separate resource file overrides the .GAM file resources, players who download the additional file will automatically see the upgraded resources.

If resources with the same name appear in multiple external resource files, the resource in the file with the highest suffix number overrides any conflicting resources. For example, if MYGAME.RS3 and MYGAME.RS1 both contain a resource with the same name, the resource in MYGAME.RS3 is used, and the one in MYGAME.RS1 is ignored.

Note that the player can optionally specify the path to the external resource files. By default, multimedia TADS looks for resource files in the same directory that contains the .GAM file. If, for some reason, the player can’t put resource files into the same directory (which might be the case if some of the files are distributed on read-only media such as CD-ROM, while others are distributed for installation on the player’s hard disk), the player can specify another directory for resource files. To do this, the player uses the -respath command-line option when invoking multimedia TADS:

   htmltads -respath d:\gold\res gold.gam
This tells multimedia TADS to run GOLD.GAM from the current directory, but to look for GOLD.RS0, GOLD.RS1, and so on in the directory D:\GOLD\RES instead of in the current directory.

An Example of Using External Resource Files

Numerous configurations are possible using this mechanism. As an example, one use of external resource files would be to provide a high-quality version of your sound effects for people who don’t mind large files, and a lower-quality version for people with slow network connections. To do this, you’d sample your sound effects at full quality, then use the sound tool of your choice to produce smaller versions (for example, by reducing the quantization, or reducing a stereo recording to mono). Put the high-quality sounds in the directory AudioHQ, and put the more compact versions in AudioLQ. Now you can produce a pair of resource files for the sound effects:

    tadsrsc -create mygame.rs0 -add AudioLQ
    tadsrsc -create mygame.rs1 -add AudioHQ

We’ve intentionally placed the higher-quality resources in the .RS1 file, so that if a player should happen to have both resource files installed, the higher-quality ones will be used. (As described earlier, the resource mechanism automatically picks the resource in the highest-numbered resource file if the same resource name appears in multiple external resource files.)

When you distribute your game, you would put together two zip files. The first contains MYGAME.GAM and MYGAME.RS0; this is the large version, for people with fast network connections. The second contains MYGAME.GAM and MYGAME.RS1; this is the compact version.


Embedded Resources and .GAM File Compatibility

Multimedia TADS uses the same TADS .GAM file format as previous versions of TADS (file format version “C”), so games that you compile for multimedia TADS can be read by older versions of the interpreter. However, note that embedded HTML resources do use a new resource type, which older interpreters will not recognize.

Therefore, if you embed resources directly into your .GAM file, players that play the game with a character-mode interpreter must have at least version 2.2.3. If you do not embed resources directly in your .GAM file, this restriction does not apply; you may want to use external resource files, as described above, if this is of concern to you.


Converting an existing TADS game to HTML

Since standard games play unchanged in multimedia TADS, you can convert a game to multimedia TADS incrementally; that is, you can start off with a very small set of changes to your game, and add features at your own pace.

Here are the steps to convert an existing game to basic HTML, summarizing some of the points made earlier in this chapter.

Step 1: Replace all occurrences of special characters.

You have to replace each occurrence of any special character HTML with their entity equivalent. Replace each occurrence of:

< with &lt;
> with &gt;
& with &amp;

Remember that you only replace the symbols where they occur within textual output. You do not replace them if they appear within a code segment. For instance, the > symbol in the example below is a problem and must be replaced, because it appears in a line of text:

  if ( global.suchValue )
     "From this -> that! ";

However the > and << and >> symbols in the example below are not a problem, because they appear within TADS code and not within a line of text:

   if ( firstValue > secondValue )
   {
     "<<firstValue>> is bigger than <<secondValue>>! ";
   }

Unfortunately it’s not easy to instruct a computer to replace automatically only special characters which appear within strings versus those which appear within code. So the easiest thing to do is simply to go through your source code manually. Just do a search for each of the three characters and replace the troublesome ones one by one. This shouldn’t be a very time-consuming process as you probably won’t have that many occurrences of the three characters in your game.

Step 2: (optional) Replace text-only TADS codes with HTML.

Text-only TADS used a number of custom character sequences which you can replace if you wish. For example, a neutral quotation mark in text-only TADS has always been encoded as “\"”. If you want you can replace all occurrences of \" with &quot; for the same basic effect.

Doing so can be a bit tidier to look at, as you’re then encoding everything in HTML. However, this step is by no means necessary, since multimedia TADS fully understands all the old text-only TADS encoding. However, converting to HTML does afford you a greater degree of control over formatting.

For example, in regular TADS you would use the \t code to set a tab stop. The multimedia TADS equivalent is <TAB MULTIPLE=4>, which allows you to adjust this numeric value to anything you like. Likewise you could replace each occurrence of \" in your game to <Q>, which would automatically provide you with proper curved typographical quotation marks.

Similarly you can replace the begin and end highlighting codes \( and \) with <B> and </B> respectively. Or, if it’s more appropriate, <I> and </I> if you’d prefer italicized text to bold. The equivalent to \b is <P> and \n is <BR HEIGHT=0>. The HEIGHT tag attribute is another multimedia TADS extension that creates a new blank line but with a zero (in this instance) height.

Step 3: Update your status line code

The status line is the only part of the HTML conversion process that may involve a little work - or it may involve absolutely no work at all. It depends entirely on whether your game uses the default adv.t status line code or whether you’ve rolled your own.

If you simply use the adv.t status line and haven’t customized it in any way, rejoice! Converting your game to HTML involves no status line modifications at all, because the upgraded adv.t file contains new code to emulate the traditional behaviour of the older software using the new <BANNER> functionality. All you need to do is replace your old adv.t file with the latest one. Easy.

However, if you’ve fiddled the status line to do your own thing then you’ll need to rewrite it.

Banners (described in the banner section above) are fairly straightforward - you just insert a <BANNER> tag into your game. Each banner has a name associated with it so you can specify multiple banners with ease.

Unlike traditional TADS status lines, banners are not called by two separate bits of code - the contents of a given banner tag define the entire banner. So if you’ve divided your status line code into two pieces - one which updates the left side of the status line using statusLine and one which updates the right side using setscore() - you may have to rethink things a bit for banners.

One approach you might want to take is to set up two global variables - one for the left text and one for the right. These variables would be single-quoted strings, updated as necessary by your two separate pieces of code. Then once per turn the <BANNER> tag would be displayed and your text strings pulled out of the global object and printed with the say() function. Of course, you could simply scrap the whole left/right text model altogether and go for something totally new, since banners afford so many more options, but using two global variables might be the easiest way to do a quick and dirty conversion of the existing code.

Note that you shouldn’t have any \n newlines in your strings if you do things this way. Unlike the banner routine, the traditional statusLine method normally puts a newline at the end of the line. In a banner this simply inserts a blank line (thus increasing the height of the banner if you haven’t forced it to be a specific height) which can lead to formatting problems.

Another key thing to keep in mind here is that you shouldn’t use the existing status line specification methods at all in your game when it’s running in HTML mode in a multimedia TADS runtime. Never call setscore() and never set a double-quoted string or print any text at all in statusLine. This latter is very important. The old statusLine method should never ever be called in an HTML game, since statusLine is a hardcoded feature. (that’s one of the reasons why the revised adv.t file uses a method called statusRoot) If you call statusLine in an HTML game then the text it displays will simply be drawn down by the input prompt rather than in the status bar, which is almost certainly not what you want.

Now, having said all that, there will be an important case when you will need to use the old status line methods of displaying status line text. And that case will be when you write a game that’s designed to work both under multimedia TADS runtimes and text-only runtimes. Take the following example. Here we’ve assumed that we’ve done a test for multimedia TADS compatibility early on in the game - probably in the init() statement. We’ve put the result of that test into global.htmlEnabled. We’ve also separated out the text for the left and right side of our status bar and put the bits of text into global variables.

  if ( global.htmlEnabled )
  {
    // we're using a multimedia TADS runtime
    "<BANNER ID=StatusLine HEIGHT=PREVIOUS><BODY BGCOLOR=SILVER TEXT=BLACK><B>";
    say( global.leftStatusText );
    "</B><TAB ALIGN=RIGHT>";
    say( global.rightStatusText );
    "</BANNER>";
  }
  else
  {
    // we're using a plain-text TADS runtime
    setscore( global.rightStatusText );
  }

Now this won’t update the left side of the status line in plain-text runtimes. To do that we make sure that the base room class has the following statusLine method:

  statusLine =
  {
    if ( not global.htmlEnabled )
      say( global.leftStatusText );
  }

You now have a game with a status line that’s fully compatible with both HTML and plain-text runtimes.

Step 4: (optional) Add fancy formatting and multimedia.

You now have a basic conversion complete and can go in and add all kinds of fancy formatting, images and sound. However, remember that a lot of people may be playing your game on a text-only interpreter. Unless you intend to shut that sizeable audience out completely you should probably set up your game so that it’s playable in either environment.

Many kinds of advanced HTML formatting don’t survive very well when viewed by TADS interpreters that don’t support HTML. Tables are particularly messy that way. So you might, in certain places, want to put in some check code to test for the presence of HTML parsing. To do this use the systemInfo function. For example:

   if ( systemInfo(__SYSINFO_HTML ) = 1 )
   {
     // print out the HTML table
   }
   else
   {
     // print out the plain text equivalent
   }

In fact, since the browser’s ability to interpret HTML does not change at any time, you could put in a test early on in the game - say, in the init() code. This check could set a global variable that you could examine later on in the game. Note that the test for __SYSINFO_HTML returns 1 if HTML parsing is present and 0 if not, so don’t test for true or nil here.

Another important thing is that versions 2.2.4 and higher of the text-only TADS runtime do have the ability to understand limited HTML. That is, they can print entities correctly as well as handling a few simple tags, such as <P>, <BR> and <B>. Basically the runtime supports those HTML tags with traditional TADS \ sequence equivalents. However, a __SYSINFO_HTML test still returns 0 on these runtimes, because they don’t fully support HTML. This makes it quite easy to write a game that uses basic HTML (it prints the \H+ switch) but which works properly on both plain-text and full HTML runtimes. For more information on this, consult Appendix G, Multimedia Games with a Text-only Interpreter.

Step 5: enable HTML.

Finally, as explained at the top of this document, output the “\H+” sequence to enable HTML in your game. This is most commonly done in the init() function.

 


Chapter Eleven Table of Contents Appendix A