
/*
 *  The Golden Skull
 *
 *  An interactive introductory demonstration of HTML-TADS
 *
 *  Original Gold Skull game copyright (c) 1987-1998 Michael J. Roberts
 *
 *  HTML-TADS modifications, source code comments and original images
 *  copyright (c) 1996-98 N. K. Guy. tela@tela.bc.ca
 *
 *  http://www.tela.bc.ca/tela/tads/
 *
 *  Version 0.7
 *
 *  April 12, 1998. 12:41 AM.
 *
 */


/*
 *  IMPORTANT NOTE:
 *
 *  This file is the TADS source code file needed to create a
 *  demonstration HTML-TADS game with graphics and sound. It's
 *  not a standard TADS game. That means that you can compile
 *  this game with a regular TADS compiler, but you will *not*
 *  see any graphics or hear any sound unless you also have the
 *  graphics and sound files that the game requires.
 *
 *  That may sound a little obvious, but we don't want people
 *  eagerly compiling the game without reading the instructions,
 *  then getting frustrated when none of the multimedia features
 *  work. So we decided to err on the side of safety and include
 *  this reminder.
 *
 *  If you got this file along with the new TADS compiler, you
 *  will not have the accompanying graphics and sound. Those are
 *  available as a separate download, mainly because the files are
 *  fairly large. The complete Golden Skull demonstration game
 *  with the additional graphics and sound files should be available
 *  from the same place you got the compiler, packed into a file
 *  called goldsrc.zip.
 *
 *  As outlined in the HTML-TADS documentation, there are two ways
 *  you can play the game with graphics and sound once you've compiled
 *  it. The first way is to make sure that the graphics and sound
 *  files are all in the same directory or folder as the .gam file
 *  itself. The second way is to add the graphics and sound files
 *  *into* the .gam file as TADS resources, using the supplied TADS
 *  resource management program, TADSRSC.
 *
 *  There should also be a file called golddemo.zip at the
 *  same place you got all the other files. This archive
 *  contains the pre-compiled game, for those who want to try
 *  out HTML-TADS without having to bother compiling things. The
 *  pre-compiled game also includes the graphics and sounds
 *  pre-loaded as TADS resources. You cannot extract the
 *  graphics and sounds from the .gam file, so if you want to
 *  compile your own copy of the game you'll need to get the
 *  goldsrc.zip file.
 *
 *  So, to summarize:
 *
 *  + This file, gold.t, ships with the TADS compiler, but the
 *    TADS compiler package does *not* include the necessary sound
 *    and image files needed to make a fully playable game from
 *    this source file.
 *
 *  + If you want to experiment with compiling this game, you'll
 *    need this source file along with the necessary sound and
 *    image files. So get the archive called goldsrc.zip.
 *
 *  + If you want to play this game *without* having to compile
 *    it, grab the archive called golddemo.zip. (when the Mac
 *    version of HTML-TADS arrives I'll probably put together a
 *    Mac version of this file, called golddemo.hqx)
 *
 *  Phew!
 */


/*
 *
 *  COPYRIGHT AND LICENCE
 *
 *  The Golden Skull started out life as sample code included in
 *  the TADS Author's Manual - copyright (c) 1987-98 by Michael
 *  J. Roberts.
 *
 *  Conversion to HTML, extensive commentary, additional material
 *  and original graphics and sound copyright (c) 1996-98 by N. K.
 *  Guy, tela design.
 *
 *  The TADS code that makes up this game may be copied, distributed,
 *  used freely in the creation of other TADS games and modified.
 *  Though I'd appreciate a small mention in the credits if you do
 *  use it. Warm and fuzzy feelings, you know.
 *
 *  The images, however, are under copyright as detailed above and
 *  may *not* be used in or in conjunction with any other game or
 *  Web page or whatever without the prior permission of me, the
 *  photographer. Thanks!
 *
 */


/*
 *
 *  ABOUT THIS GAME:
 *
 *  This is a miniature game that's designed to demonstrate some of
 *  the new features of HTML-TADS. As such, it's not a particularly
 *  engrossing or challenging work. Sorry about that. Nor is it a
 *  game meant to teach absolute novices how to program in TADS.
 *  You're expected to know a little bit about TADS basics before
 *  checking this out. Finally, it has some really annoying
 *  featurettes that you probably won't want to implement in a real
 *  game. At least, not if you have any taste... but they're here to
 *  show you the kind of interesting stuff that can be done with the
 *  new tools.
 *
 *  Here are the basic interesting features that this game
 *  illustrates:
 *
 *  1) Simple text styling. HTML-TADS can apply bold, italic and
 *  other styles to text. It can also use different typefaces if
 *  they're available.
 *
 *  2) Displaying inline graphics. HTML-TADS has the ability to
 *  display PNG or JPEG images within the body of the text, just
 *  like a Web page. Having the two formats is actually quite
 *  useful, as JPEG compresses photos and other images with
 *  naturalistic tones well whereas PNG is better for images with
 *  blocks of solid colour. Note that GIF is not supported, because
 *  you have to pay licencing fees to include GIF reading software
 *  within a program. As Mike Roberts is letting us use HTML-TADS for
 *  free, I would think that having to pay hefty fees was obviously
 *  something of a disincentive against including GIF support.
 *
 *  3) Background sound. HTML-TADS can play ambient background sounds.
 *  Very useful as mood-setting devices - waves washing on a beach,
 *  the chuff and rattle of an old steam train, the babble of voices
 *  in a crowd. Any digitized sound you like. HTML-TADS can also play
 *  MIDI music files, but I don't include this feature in this demo.
 *  Mainly, to be honest, because I think MIDI and MOD files generally
 *  sound dreadful. (Though if you have a well-written MIDI file, and
 *  your computer is plugged into a decent MIDI keyboard, they can
 *  sound okay - it's just that most of us don't have decent MIDI
 *  keyboards...)
 *
 *  4) Foreground sound. The game can play special sound effects at
 *  opportune - or, for that matter, inopportune - moments. Doors
 *  creaking open, explosions, the sound of a vehicle starting.
 *
 *  5) Clickable links. Just like a Web browser, HTML-TADS supports
 *  clickable textual links. This will be one of those love/hate things
 *  with a lot of users, so HTML-TADS allows users to switch the feature
 *  off.
 *
 *  6) Tables. HTML-TADS supports traditional HTML tables, which can
 *  be used for a variety of information display tasks. Common uses
 *  include displaying data in a tabular form, aligning bits of text
 *  (though HTML-TADS also supports simple tabs) and framing items
 *  with rectangular frames.
 *
 *  7) Page and text colours. HTML-TADS allows you to specify both
 *  text colours and background page colours at will. Luckily these
 *  can be overridden if you find yourself playing a game written
 *  by an author with no taste in colour choices. Or if you have, say,
 *  a machine with a video card that has very limited colour choices
 *  and the author's colour choices happen to map to illegible colour
 *  equivalents on your machine.
 *
 *  8) Typesetting support. HTML-TADS goes beyond simple ASCII and
 *  supports ISO-Latin character encoding, as well as typographical
 *  quotation marks. The former let you write in most Western languages
 *  and the latter make your pages look better.
 *
 *  9) Clickable images. Just like a Web page. You can specify hot spots
 *  on an image, and have TADS issue typed commands when a player clicks
 *  on a given location.
 *
 *
 *  Notes on Source Code Style:
 *
 *  1) I could have used the << operator to include function calls.
 *  This is just a stylistic thing. The following two lines are
 *  essentially equivalent:
 *
 *  ldesc = "This is a <<function();>> thing. "
 *  ldesc = { "This is a "; function(); " thing. "; }
 *
 *  2) There's no need for all the returns (blank lines) in the HTML-
 *  formatted text. It's just white space that's collapsed by
 *  the compiler into a single space anyway, but whitespace
 *  makes the source easier to read.
 *
 *
 *  Some Opinionated Editorializing:
 *
 *  I thought I'd also offer a few suggestions, comments and
 *  editorial remarks concerning what I've learnt in assembling
 *  this simple demo, the first real TADS game to incorporate
 *  HTML, graphics and sound. Take this advice as you will. Some
 *  people will undoubtedly find these suggestions rather
 *  patronizing, but, well... there you go.
 *
 *  1) Graphics
 *
 *  First, graphics. Graphics are a hell of a lot of work to do!
 *  Putting this game together really hammered home that point for
 *  me, since I wanted something that looked professional, not
 *  some cheesy MacPaint or Windows Paintbrush doodlings.
 *
 *  There's a reason why text adventures are still being written
 *  by the proverbial guy or gal in a garage, and why modern
 *  graphical epics are assembled by large teams of underpaid
 *  slaves to a faceless corporation. Graphics are time-
 *  consuming to create (it took several days of intermittent
 *  work to get the five main images in Golden Skull done, mostly
 *  spent laboriously removing handrails and other unwanted
 *  things from the photos, and replicating leaves and so on to
 *  cover up patchy bits... pictures that take nanoseconds for
 *  the player to view!) and expensive to do well. On top of
 *  which, you need to have some modicum of talent to create
 *  decent artwork.
 *
 *  I dodged this last issue to some extent simply by taking
 *  photographs and reworking them... an approach many of us
 *  should probably consider. Because most of us can't draw
 *  worth crap. If you have any doubts about the professionalism
 *  of your images, it might be better for your reputation and
 *  the overall success of your game if you exercise the null
 *  option and simply leave them out. A well-written text
 *  adventure with no graphics is going to come across a hell of
 *  a lot better than the same game with awful, amateur
 *  graphics. Be honest with yourself. If your drawings look
 *  like something that belong on a proud parent's fridge, do
 *  yourself a favour and leave 'em out of your game.
 *
 *  Of course, if you actually are a person with artistic
 *  abilities or are in the position to get someone who is to do
 *  graphics for you, just think of the possibilities... Most
 *  games tend to go for retouched photographs or fuzzy full-
 *  motion video or the glossy, unreal look of computer imaging.
 *  But textual IF is different - it often has pretensions to a
 *  more literary form. So I think an illustrated book could be
 *  a very intriguing metaphor for an HTML-TADS game.
 *
 *  The illustrations could be watercolours, charcoal sketches,
 *  cross-hatched pen and ink. Like John Tenniel's drawings for
 *  Alice in Wonderland, or E. H. Shepard's sketches (later
 *  coloured with watercolours) for Winnie the Pooh. Or, for
 *  something more contemporary, the stylized look of a comic
 *  book with exaggerated perspective and flat colour. Hell -
 *  why not a game about Elvis and UFOs, illustrated uniquely
 *  with black velvet paintings?
 *
 *  Going for an illustration-based approach also neatly side-
 *  steps one of the bigger problems with including graphics in a
 *  game - state changes. If you go for a more literal approach
 *  to game illustration you'll want to have different images to
 *  represent different states of the objects in question. So
 *  you'll need a picture of the cave, a picture of the cave with
 *  the gold skull in it, etc. Or two pictures of a car - one
 *  with the door open and one with the door shut. That rapidly
 *  becomes very space and time consuming. It took an entire
 *  evening's mucking around to get the compass graphics done,
 *  with all of its different pieces and colour variants.
 *
 *  It can be particularly onerous if you want to include portable
 *  objects, because HTML-TADS has no mechanism for overlaying
 *  images onto scenes. There's a reason why Myst and Riven, both
 *  games built around elaborate pre-rendered images, don't let you
 *  pick too much stuff up and carry it around.
 *
 *  But if you opt for a more figurative than literal approach to
 *  illustration you can simply ignore the state change problem
 *  altogether - the graphics are there to provide a mood or
 *  illustrate a feeling, not to be a realistic and literal
 *  portrayal of the current state of a virtual environment.
 *
 *  2) Elaborate text formatting
 *
 *  Second, fancy formatting. This game uses some horrible
 *  formatting simply to demonstrate what HTML-TADS can do. But
 *  just because something *can* do something doesn't mean you
 *  *have* to use it. Go lightly on the formatting. Simple bold
 *  and italic now and again make a big difference to the
 *  appearance of a game. As does something typographically
 *  appropriate like using a sans serif font for certain headers
 *  and a serif font for body text.
 *
 *  But please, don't go crazy. Especially with formatting
 *  options like colour. I'd strongly suspect that most of your
 *  players will find wacky formatting far more annoying than
 *  cool, once the initial novelty has worn off.
 *
 *  3) Fonts
 *
 *  Third, be careful with fonts. You can specify fonts in
 *  HTML-TADS, but don't forget that font choices are totally
 *  dependent on what fonts the player happens to have installed
 *  on his or her computer. If you specify a font that the
 *  player doesn't have then text will be displayed in
 *  HTML-TADS's default font, whatever that happens to be.
 *
 *  But when specifying fonts remember that you can specify a
 *  list of fonts, and HTML-TADS will pick the first font that
 *  is available on the current system. This affords you a
 *  certain degree of flexibility. For example, most Windows
 *  systems have Times New Roman installed and most Macintoshes
 *  have Times installed. So you can put in the tag:
 *
 *   <FONT NAME="Times,Times New Roman">
 *
 *  and you should get Times on either platform. Here are some
 *  Mac/Windows font mappings you could consider.
 *
 *   Basic serif font. Mac: Times. Windows: Times New Roman.
 *   Basic sans-serif font. Mac: Geneva. Windows: Arial.
 *   Typewriter font. Mac: Courier. Windows: Courier New.
 *
 *  Naturally this won't help you when HTML-TADS runs on any
 *  other platform, but at least it's a starting point.
 *
 *  And of course don't forget that using dingbat fonts (fonts
 *  that consist of little pictures rather than letters) is very
 *  dangerous. Zapf Dingbats may be available on most Macs and
 *  Wingdings on most PCs, but they have very different
 *  characters. And other platforms may not have a standard
 *  dingbats font of any kind. To avoid messiness you're best
 *  off avoiding dingbats and using graphics files instead.
 *
 *  4) Sound
 *
 *  Fifth, sound. My previous comments regarding misuses of
 *  graphic and text formatting apply to the audio feature.
 *
 *  Tasteful, professional and appropriate sound can do wonders
 *  for a game. Plug a pair of speakers into your machine and
 *  play Riven - you'll see what I mean. But if you load your
 *  game down with constant cheesy sound effects you'll simply
 *  annoy your audience, who'll probably just exercise their
 *  right to turn sound off altogether. So why even bother?
 *
 *  But I admit there are borderline examples. For instance, you
 *  might think it's cool to add the soft grunting noises of an
 *  ancient 5.25" floppy drive at certain points in the game, as
 *  if the game were loading off disk the way old Infocom games
 *  would. This will thrill a lot of people, who'll delight at
 *  the sheer retro nostalgia value of aving a brand new computer
 *  emulating an old clunker from 1981. But other people,
 *  particularly those who don't remember the old machines,
 *  might find it simply irritating. I might be inclined to
 *  include such an effect, but allow the player to disable the
 *  option. Or, of course, just rely on the "Sound effects" menu
 *  option in HTML-TADS.
 *
 *  Of course, keen-eared people will undoubtedly point to the
 *  general hypocrisy of me telling you not to include cheesy
 *  sound effects - as this game includes some very annoying and
 *  cheesy sound effects. Well, yes, but again this isn't meant
 *  to be a real game that real people will play. That's my
 *  feeble excuse. Also, please note that the sound effects in
 *  this current version of the game are sort of placeholders so
 *  that I could get it out the door in time for Mike's preview
 *  of the new authoring environment. The cave, for example, has
 *  more of a rain sound effect than anything else. Ah well.
 *
 *  This all may read like I'm trying to say "Use HTML-TADS but
 *  don't use any of the cool new HTML-TADS features." Well. Not
 *  quite. My point is that these new functions can be
 *  startlingly effective when used lightly and appropriately.
 *  Mike has implemented some extremely cool new features. But
 *  if you pile them all on it's going to be counter-productive,
 *  in my opinion.
 *
 *  SUMMARY:
 *
 *  Remember when word processors first introduced style
 *  features and people started printing posters in Helvetica 72
 *  Bold Outline Shadow Italic? Same thing here.
 *
*/


#define USE_HTML_STATUS        // Use the default TADS status line since
                               // we aren't doing anything fancy with
                               // the status line formatting.

#include <adv.t>               // load generic adventure game "adv.t"
#include <std.t>               // load standard underpinnings


/*
 *  displayImage: function
 *
 *  A simple function that displays a PNG or JPEG format
 *  image file. Note that displaying an image isn't as
 *  complicated as it seems here - most of the code below
 *  is simply to support some useful features I felt like
 *  adding. You can, of course, always display an image
 *  just by embedding the <IMG SRC="xxx"> tag in your
 *  game. You use this function, or something similar, if
 *  you want more control over the display of the image.
 *
 *  The parameters passed do three things.
 *
 *  The first parameter, imageName, is the filename for
 *  the image you want to display. This can either be a PNG
 *  or JPEG image in the same folder/directory as the TADS
 *  game itself or an image stored as a resource within the
 *  game file. This is the only parameter that's absolutely
 *  necessary.
 *
 *  The second, objectToCheck, is the name of the object
 *  which should have its imageSeen flag set. The idea
 *  behind this is so the game will be able to tell whether
 *  or not a given object's image has been displayed yet
 *  or not. If you don't want to associate the image with
 *  a particular object, just pass nil as the parameter. I
 *  implemented this parameter because I suspect most people
 *  will only want to see an object's image once, and not
 *  every time the object description appears - much like
 *  most games default to "brief" mode and not "verbose" mode.
 *
 *  The third parameter, centre, simply specifies whether or
 *  not the image should be aligned centre on the screen or
 *  aligned left. Default is align right so that text can be
 *  wrapped around it. (vertical space tends to be more
 *  valuable than horizontal space, if you know what I mean.)
 *
 */

displayImage: function( imageName, objectToCheck, centre )
{
  if ( not objectToCheck.imageSeen or ( not global.displayGraphicsOnce ) )
  {
    if ( centre )
      "<CENTER><P>";
    else
      "<BR>";

    "<IMG SRC=\"";

    /*
     *  Note that the " mark above is escaped with the \ symbol.
     *  That means that TADS will display it on-screen as is,
     *  rather than trying to interpret it as TADS source code.
     *
     *  Things get very messy if you forget to escape double
     *  quotation marks that are meant to be part of your HTML
     *  formatting. In fact, your code will probably not compile,
     *  and you'll get some random error message caused by the
     *  compiler trying to interpret your HTML as TADS code. If
     *  this happens search the lines *before* the line that the
     *  compiler flagged as being problematic.
     */

    say( imageName );

    "\"";

    if ( not centre )
      " ALIGN=RIGHT HSPACE=30";

    ">";

    if ( centre )
      "</CENTER><P>";

    if ( objectToCheck <> nil )
      objectToCheck.imageSeen := true;
  }
}

/*
 *  displayLink: function
 *
 *  Clickable links are, I expect, a feature that will invoke a
 *  lot of strong feelings amongst players. Some will love
 *  clickable links (wow, man! it's so cool - just like a Web
 *  browser!) whereas others will loathe them. (what the hell is
 *  this GUI garbage doing infecting a text adventure?)
 *  Fortunately, the player can turn off links in HTML-TADS if
 *  he or she so desires. So we can keep everyone happy.
 *
 *  However, an earlier version of HTML-TADS did not permit
 *  players to disable links, so I wrote this code to put links
 *  under the player's control. I could have removed all this
 *  junk when links became optional, but decided to leave it in.
 *  The idea behind it still stands, and you can adapt code such
 *  as this to your own needs.
 *
 *  Anyway. The game starts with links turned on, but simply
 *  typing "links" will turn them off. The idea is to provide
 *  clickable links for the player's convenience. Certain key
 *  words (eg: "rock") have commands associated with them (eg:
 *  "take rock") that will be displayed as appropriate,
 *  depending on what the user has specified as his or her
 *  preference. All the player has to do is to click the link
 *  for the command to be automatically typed in.
 *
 *  Because I wanted a preferences check to be made each time a
 *  link is displayed (or not displayed), I wrote a simple
 *  function that checks a global variable for the user's
 *  preference. Of course, this is not the simplest way to
 *  implement links. The simplest way is just to include the
 *  hypertext anchor tag (<A>) straight in the text description.
 *
 */
displayLink: function( command, text )
{
  if ( not global.displayLinks or command = '' )
    say( text );
  else
  {
    "<A HREF=\"";
    say( command );
    "\">";
    say( text );
    "</A>";
  }
}

/* 
 *  printOnOff: function
 *
 *  A very simple print function that's used later on by the
 *  compass code.
 */
printOnOff: function ( onOff )
{
  if ( onOff )
    "-on.jpg' ";
  else
    "-off.jpg' ";
}

startroom: room              /* the game always starts in "startroom" */
  sdesc = "Outside cave"       /* the "Short DESCription" of the room */

  /*
   *  enterRoom is sent to the room object when the actor
   *  enters it.
   *
   *  We override this method in order to change window
   *  colours, then pass the usual method. We also play
   *  an "outside the cave" sound. This sound is actually
   *  made up of two parts - a continuously looping
   *  background ambient sound (BGAMBIENT) along with a
   *  random bird chirping sound in the ambient layer.
   *
   *  This is a pretty cool sound feature, because it
   *  means you can have some sort of generic looping
   *  background sound and overlay a random effect over
   *  top to simulate a longer sound. In other words,
   *  instead of a really long looped background sound -
   *  long to conceal the fact that it's a loop - you can
   *  have a shorter loop without any identifiable repeating
   *  sounds, then specify a second sound (here, a chirping
   *  bird) to play at random intervals over top. The
   *  result should be a fairly realistic seamless sound
   *  that doesn't have obvious and overly annoying repeating
   *  points.
   *
   *  Sounds are one of the coolest new aspects of HTML-TADS,
   *  in my opinion. Well-done sounds can be a very powerful
   *  mood device. Of course, sounds also have one extremely
   *  significant drawback - storage space. You'll notice
   *  that the few short sounds included with this demo game
   *  eat up an awfully large amount of disk space.
   *
   *  Unfortunately that's how it is and there's not much
   *  you can do about it. HTML-TADS supports WAV format
   *  sounds, which traditionally haven't offered any useful
   *  form of compression. And I sampled the sounds at 16
   *  bits, 22 KHz stereo so as not to sacrifice too much
   *  sound quality. Hopefully in the future it'll be possible
   *  to use sounds with some form of MPEG layer 3 compression,
   *  say, once the various system sound architectures
   *  (QuickTime for Mac and DirectX for PC in this case)
   *  support them.
   *
   *  Of course, it should be noted that WAV files offer
   *  one other important advantage - they can be played on
   *  a wider range of machines than files compressed with
   *  advanced compression methods. This is relevant in the
   *  case of slower machines that lack the horsepower to
   *  decode, for instance, MP3 files on the fly.
   *
   *  Note also that we use standard HTML hexadecimal values
   *  to specify colours. See the cave room object for
   *  another way to specify page colours.
   */

   enterRoom( actor ) =
  {
    "<BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\">
    <SOUND SRC=\"outside.wav\" LAYER=BGAMBIENT REPEAT=LOOP>
    <SOUND SRC=\"bird.wav\" LAYER=AMBIENT RANDOM=\"5\">";
    pass enterRoom;
  }

  /*
   *  We turn off the sounds when the player leaves
   *  the room.
   */

  leaveRoom( actor ) =
  {
    "<SOUND CANCEL=AMBIENT>
    <SOUND CANCEL=BGAMBIENT>";
    pass leaveRoom;
  }
  north = cave
  in = cave
  imageSeen = nil

  /*
   *  Notice that TADS supports proper typographical quotation marks.
   *  (also known as smart quotes, curvy quotes, squiggly quotes, etc.)
   *
   *  This isn't an official HTML standard, but it should be! TADS
   *  uses &rsq; for a right single quote (apostrophe), &lq; for a
   *  left single quote and &ldq; and &rdq; for left and right double
   *  quotation marks, respectively. It also supports &endash; for
   *  en dashes (hyphens slightly wider than normal - the width of a
   *  letter N) and &emdash; for em dashes (hyphens the width of a
   *  letter M, equivalent to a typewriter's double-hyphens). Strike
   *  a mighty blow for classy typesetting with HTML-TADS!
   *
   *  Of course, TADS games can be played on computers that don't
   *  support typesetters' quotation marks. Runtimes that run on such
   *  computers should convert the curved quotation marks to neutral
   *  ones. And you can still put in neutral quotation marks and
   *  apostrophes as you could before in regular TADS, by using the
   *  \' and \" sequences.
   *
   */

  ldesc =
  {

    /*
     *  We display a JPEG graphic, again using a custom
     *  pre-defined function rather than hardcoding-in
     *  the image. We use the default align right, so
     *  that the text is on the left and the picture
     *  on the right.
     */

    displayImage( 'entrance.jpg', self, nil );

    "You&rsq;re standing in bright sunlight just
    outside of a large, dark, foreboding ";

    /*
     *  We make certain key words clickable. Instead
     *  of hardcoding in the <A HREF stuff we use the
     *  previously-defined function, though there isn't
     *  really any need to anymore, as noted earlier.
     */

    displayLink( 'examine cave', 'cave' );

    ", which lies to the ";

    displayLink( 'north', 'north' );

    ". To the ";

    displayLink( 'south', 'south' );

    " a winding trail leads back to civilization. ";

    "<BR CLEAR=ALL HEIGHT=0>";
  }
  south =
  {
    if ( goldSkull.isScored and goldSkull.isIn( Me ) )
    {
      "You trudge back down the trail, gold skull firmly in
      hand, and soon make it to civilization next day. Fame!
      Fortune! Riches!

      <P>

      But the store is out of milk. Rats.

      <P>";

      scoreRank();

      "<P>

      Would you like to restore a saved game, start over,
      quit, or undo the the last command? ";

      while ( 1 )
      {
        local resp;

        "Please type ";
        displayLink( 'RESTORE', 'RESTORE' ); ", ";
        displayLink( 'RESTART', 'RESTART' ); ", ";
        displayLink( 'QUIT', 'QUIT' ); " or ";
        displayLink( 'UNDO', 'UNDO' );
        ": >";

        resp := upper( input() );

        if ( resp = 'RESTORE' )
        {
          resp := askfile( 'Filename to restore' );

          if ( resp = nil )
            "Cancelled. ";
          else if ( restore( resp ) )
            "Game restore failed. ";
          else
          {
            Me.location.lookAround(true);
            scoreStatus( global.score, global.turnsofar );
            abort;
          }
        }
        else if ( resp = 'RESTART' )
        {
          scoreStatus( 0, 0 );
          restart();
        }
        else if ( resp = 'QUIT' )
        {
          terminate();
          quit();
          abort;
        }
        else if (resp = 'UNDO')
        {
          if (undo())
          {
            "(Undoing the previous command)\b";
            Me.location.lookAround(true);
            scoreStatus(global.score, global.turnsofar);
            abort;
          }
          else
            "Sorry. No more undo information is available. ";
        }
      }
    }
    else
    {
      "You briefly consider heading for the comforts of home,
      but a strange and burning compulsion to learn more about
      the wonders of ";

      displayLink( 'about', 'HTML-TADS' );

      " dissuades you. ";

      return( nil );
    }
  }

  /*
   *  Two flags used by the compass object, seen later on.
   */

  inActive = true
  nActive = true
;

fakeCave: fixeditem
  sdesc = "cave"
  location = startroom
  noun = 'cave'
  adjective = 'dark' 'foreboding'
  ldesc = "It&rsq;s a dark, foreboding cave. Well...\ somewhat
  foreboding at any rate. The path leading into it looks
  neatly swept and frequently used, mainly because I
  couldn&rsq;t be bothered to Photoshop any rocks or vines or
  whatever onto the image to make it look more overgrown and
  sinister. "
  verDoEnter( actor ) =
  {
    "Just go north. ";

    /*
     *  Just laziness. If this were a real game, of course,
     *  we'd want to permit the player to enter the cave
     *  simply by typing 'enter cave.' This, however, is not
     *  a real game, so I'm going to leave this as an Exercise
     *  for the Reader.
     */

  }
;

cave: room
  sdesc = "Cave"

  /*
   *  We change the background colour of the page to make
   *  things look more ominous when the player enters
   *  the cave. We do this in the enterRoom routine so that
   *  it gets set correctly each time the player enters the
   *  room. This is naturally one of those effects Best
   *  Used in Moderation. Though players offended by such
   *  tricks can override screen colours using the HTML-TADS
   *  runtime.
   *
   *  Note that we set the colour values to actual words
   *  rather than hexadecimal colour values, as we did with
   *  the "outside" room. You can do it either way. Using
   *  words allows you to tell at a glance what the colour
   *  is, without having to memorize obscure hexadecimal
   *  colour codes. Using the hex codes allows you to be
   *  a bit more precise with your colours. But keep in mind
   *  that there's nothing truly accurate about HTML colours
   *  on any computer. A colour that looks lovely on your
   *  machine may look rather putrid on someone else's -
   *  that's just how it is.
   *
   *  Another thing to keep in mind is that implementing
   *  page colour changes this way is somewhat fragile. There
   *  are a number of instances in which the player might
   *  find the page colours to be set incorrectly, such as
   *  after a restore or an undo or whatever. Again, if
   *  you're planning to use a similar effect in a real game
   *  you'll probably want to spend some time going through
   *  and bulletproofing things somewhat.
   *
   *  We also play a sort of dripping cavey sound. As with the
   *  outside sound, the cave sound consists of a medium-length
   *  loop for general background noise with a shorter
   *  identifiable clip (here the sound of dripping water)
   *  played randomly over top.
   */

  enterRoom( actor ) =
  {
    "<BODY BGCOLOR=BLACK TEXT=WHITE>
    <SOUND SRC=\"cave.wav\" LAYER=BGAMBIENT REPEAT=LOOP>
    <SOUND SRC=\"drip.wav\" LAYER=AMBIENT REPEAT=LOOP RANDOM=\"3\">";
    pass enterRoom;
  }
  leaveRoom( actor ) =
  {
    "<SOUND CANCEL=BGAMBIENT>
    <SOUND CANCEL=AMBIENT>";
    pass leaveRoom;
  }
  ldesc =
  {
    "You&rsq;re inside a dark, damp cave. Sunlight
    pours in from a passage to the ";

    displayLink( 'south', 'south' );

    ". Some distance from the entrance you notice a large stone ";

    displayLink( 'examine the pedestal', 'pedestal' );

    ", and there&rsq;s a big ";

    displayLink( 'read the sign', 'sign' );

    " on the wall.<P>";

    displayImage( 'cave.jpg', self, true );
  }
  south = startroom
  out = startroom
  sActive = true
;

pedestal: surface, fixeditem
  sdesc = "stone pedestal"
  noun = 'pedestal'
  adjective = 'stone'
  location = cave
;

goldSkull: item
  sdesc =
  {
    displayLink( 'examine gold skull', 'gold skull' );
  }
  noun = 'skull' 'head'
  adjective = 'gold' 'golden' 'small' 'solid'
  location = pedestal
  isScored = nil
  imageSeen = nil

  /*
   *  The original version of the gold skull game had the following code
   *  as part of the doTake() method. The problem with implementing the
   *  trap using doTake() is that the player could simply put the skull
   *  on the floor, then pick the skull up and happily walk away. Not a
   *  very secure trap. So instead of overriding doTake() we override the
   *  more basic moveInto() method, which is called every time the skull
   *  is moved from one location to another.
   */

  moveInto( obj ) =
  {
    if ( self.location = pedestal )
    {
      if ( smallRock.location = pedestal )
      {
        if ( not self.isScored )
        {
          self.isScored := true;
          incscore( 1 );
        }
        if ( self.location = pedestal )
          "<SOUND INTERRUPT SRC=\"scrape.wav\" LAYER=FOREGROUND>";
      }
      else
      {
  
        /*
         *  I coloured in the words "poisonous arrows"
         *  in red for no particular reason other than
         *  to demonstrate the fact that HTML-TADS can
         *  display coloured text.
         */
  
        "<SOUND INTERRUPT SRC=\"death.wav\" LAYER=FOREGROUND>
        As you lift the skull, a volley of
        <FONT COLOR=\"#FF0000\">poisonous arrows</FONT>
        bursts out the walls! You try to dodge the
        arrows, but they take you by surprise!

        <P>

        Shucks.

        <P>";

        die();
      }
    }
    pass moveInto;
  }
  ldesc =
  {
    "It&rsq;s a small skull, the size of your clenched fist
    and cast from solid gold. It grins back at you,
    undoubtedly well aware of its priceless value. ";

    /*
     *  Okay, so this next bit is ugly hardcoding.
     *  But this is a demo, so don't do this at home.
     *
     *  We want the black background skull image to
     *  appear when the player is in the cave; the
     *  white background image when the player is
     *  outside. So we check for that.
     *
     *  Of course, simply checking for the cave
     *  location would pose a problem if the player
     *  sat down. The player's location would then be
     *  the ground object, not the cave. So we check
     *  for that possibility as well. Note that we
     *  first check to see if Me.location actually
     *  has its own location property. If we didn't
     *  check for this then we'd get a 1010 runtime
     *  error if this code were executed when the player
     *  was in a normal room. Normal rooms do not
     *  have location properties.
     */

    if ( Me.location = cave or
    ( Me.location.location and Me.location.location = cave ) )
      displayImage( 'b-skull.jpg', self, true );
    else
      displayImage( 'w-skull.jpg', self, true );
  }
;

smallRock: item
  sdesc = "small rock"
  noun = 'rock' 'stone'
  adjective = 'small'
  location = cave
;

sign: fixeditem, readable
  sdesc = "sign"
  noun = 'sign' 'wall' 'stone'
  adjective = 'large' 'carved'
  location = cave

  /*
   *  A standard HTML table. Using a table like this may not
   *  be the most aesthetically pleasing way to do things, but
   *  it's here as a demo of how tables work. Note that we can
   *  specify fonts and even superscript text. And the table
   *  cell colour can also be specified. (the colour here is
   *  meant to be a sort of ugly brownish colour)
   *
   *  Font specification is done using the rather platform-
   *  dependent method of listing actual font names. So in the
   *  example below I specify that the font be set to either
   *  Geneva (for Macintoshes) or Arial (for Windows PCs).
   *  Those two fonts are the default sans-serif font families
   *  for the respective operating systems. If neither font
   *  is available then TADS simply defaults to whatever is
   *  defined as the global font.
   */

  ldesc = "A large sign, carved into the very living rock of
  the cave wall itself. It reads:

  <P><BR>

  <CENTER>

  <TABLE BORDER=1 CELLPADDING=15 WIDTH=\"50%\">

  <TR BGCOLOR=\"#663300\">

  <TD WIDTH=60% BGCOLOR=\"#663300\">

  <P>

  <CENTER>

  <B><FONT SIZE=\"+1\" FACE=\"Geneva,Arial\">

  Trespassers Will Be

  <BR>

  Persecuted and

  <BR>

  Probably Summarily Shot *

  </FONT></B>

  </CENTER>

  <P>

  <CENTER>

  <SUP><FONT SIZE=\"-1\" FACE=\"Geneva,Arial\">*</FONT></SUP>

  <FONT SIZE=\"-2\" FACE=\"Geneva,Arial\">

  This Sign Brought to You by the Committee for Fair Warnings
  of Sudden Death in Adventure Games.

  </FONT>

  </CENTER>

  </TD>

  </TR>

  </TABLE>

  </P>

  </CENTER>"
;


list: readable

  /*
   *  Just a silly item to demonstrate how HTML-TADS
   *  supports standard HTML lists. Note that this is
   *  an ordered list (<OL>), which means that the list
   *  items (<LI>) are numbered sequentially. You can
   *  also implement unordered lists (<UL>) in which the
   *  list items are simply marked with bullets (dots).
   *
   */

  sdesc = "to-do list"
  noun = 'list'
  adjective = 'to-do'
  location = Me
  ldesc =
  "<B>To Do Today</B>

  <OL>

  <LI>Plunder ancient civilization.

  <LI>Avoid gruesome death.

  <LI>Buy milk.

  </OL>"
;

/*
 *  Another silly item, here to demonstrate the way HTML-TADS
 *  allows you to add standard HTML ISO-Latin 1 entities to your
 *  text. That means that you can add accented characters for
 *  most Western European non-English languages. Free yourself
 *  of the cultural tyranny and language imperialism of ASCII
 *  and express yourself in exciting new multilingual ways with
 *  HTML-TADS!
 *
 *  Admittedly, though, it doesn't support Unicode or other
 *  double-byte systems for encoding characters, so users who
 *  want to write text adventures in non-Western languages are
 *  unfortunately out of luck. Still, at least you can add the
 *  words to "Jabberwocky" in French and German if you want to.
 *  Sadly it looks like ISO-Latin 1 doesn't support the correct
 *  German closing quotation mark, though it does have French
 *  guillemots. Oh well.
 *
 *  You should be able to find a table of the character entities
 *  used in HTML in any decent HTML manual. (the standard is known
 *  as ISO Latin 1 or ISO-8859-1) Commonly used entities include:
 *
 *  e with an acute accent:  &eacute;
 *  o with an umlaut:        &ouml;
 *  c with a cedilla:        &ccedil;
 *  e with a circumflex:     &ecirc;
 *  a with a grave accent:   &agrave;
 *
 *  Incidentally, HTML-TADS supports the &shy; entity, which is a
 *  timid little hyphen that doesn't get broken across line endings.
 *
 *  Note for those interested in trivia... TADS has long been
 *  8-bit transparent. That means you could code up a game using
 *  the extended ASCII character set used by a given platform.
 *  But that would need to compile a special version for Windows,
 *  another one for Mac, and so on. Not a terribly satisfactory
 *  solution. Using ISO Latin-1 means that you can write a single
 *  game and have it playable on whatever platforms HTML-TADS
 *  is ported to without problems.
 *
 *  There's also a graphical line in this example. In addition
 *  to the traditional HTML horizontal rule, implemented using
 *  the <HR> tag, HTML-TADS allows you to specify a graphical
 *  file as the basis for the line. So in this instance we use
 *  a tiny PNG (Portable Network Graphics) file, because it's
 *  really just made up of a couple solid blocks of colour. The
 *  PNG format compresses these kinds of images more efficiently
 *  and accurately than does JPEG, which was designed to compress
 *  naturalistic images well. Anyway - use of the <HR> tag in this
 *  fashion results in a chequerboard line rather than a normal
 *  one. And the width of the line is set to 90% of the window
 *  width.
 */

parchment: readable
  sdesc = "old parchment"
  adesc = "an old parchment"
  noun = 'parchment'
  adjective = 'old' 'yellowed'
  location = Me
  ldesc = "It&rsq;s an old yellowed parchment. Mysterious
  words are inscribed upon it:

  <P>

  <HR SRC=\"dots.png\" WIDTH=\"90%\">

  <P>

  <BLOCKQUOTE>

  <B>Le Jaseroque</B>

  <P>

  <BQ>

  Il brilgue: les t&ocirc;ves lubricilleux<BR>
  Se gyrent en vrillant dans le guave.<BR>
  Enm&icirc;m&eacute;s sont les gougebosqueux<BR>
  Et le m&ocirc;merade horsgrave.

  <P>

  &laquo;Garde&shy;toi du Jaseroque, mon fils!<BR>
  La gueule qui mord; la griffe qui prend!<BR>
  Garde&shy;toi de l&rsq;oiseau Jube, &eacute;vite<BR>
  Le frumieux Band&shy;&agrave;&shy;prend.&raquo;

  </BQ>

  <P>

  <B>Der Jammerwoch</B>

  <P>

  <BQ>

  Es brillig war. Die schlichten Toven<BR>
  Wirrten und wimmelten in Waben;<BR>
  Und aller&shy;m&uuml;msige Burggoven<BR>
  Die mohmen R&auml;th&rsq; ausgraben.

  <P>

  &raquo;Bewahre doch vor Jammerwoch!<BR>
  Die Z&auml;hne knirschen, Krallen kratzen!<BR>
  Bewahr&rsq; vor Jubjub&shy;Vogel, vor<BR>
  Frumi&ouml;sen Banderschn&auml;tzchen!&laquo;

  </BQ>
  </BQ>"

  /*
   *  Note the use of the <BLOCKQUOTE> tag. This was originally
   *  intended to be used to indicate sections of text that are
   *  quotations. Normally this is done by indenting the text,
   *  so blockquote inevitably is used simply as an indentation
   *  tool these days. <BQ> is a synonym for <BLOCKQUOTE> and
   *  is not meant to indicate support for a Canadian political
   *  party.
   */
;


/*
 *  I was going to make this a TimeMaster 2000, but I really don't
 *  want to push things... Anyway, this is a nifty little demo of
 *  how you can add a realtime graphical clock to your TADS game.
 *  Sort of realtime, that is - it doesn't update automatically
 *  or anything. But it does pull the time out of your computer's
 *  clock/calendar, and show the time as a picture rather than
 *  text.
 */

clock: item
  sdesc =
  {
    displayLink( 'examine the clock', 'digital clock' );
  }
  noun = 'clock'
  adjective = 'digital'
  location = Me
  ldesc =
  {

    /*
     *  We grab the current time of day from the computer's realtime
     *  clock, using the TADS gettime() function. Read the manual
     *  if you need to know the format of the value returned by this
     *  function.
     */

    local realTime := gettime();

    local realHour := realTime[ 6 ];
    local realMinute := realTime[ 7 ];

    /*
     *  Okay, I'm sure there's a much more elegant way to code this
     *  whole mess up, but I've never claimed to be an elegant coder.
     *  Nor, for that matter, a coder of elegant code. But this works,
     *  and that's the important thing from my point of view.
     *
     *  We simply extract the time from the computer in TADS time
     *  format. Then we print out a bunch of <IMG> tags, one for each
     *  digit. (and a few others for the time separator, the sides of
     *  the clock, etc.) That means that we need separate image files
     *  for each of the 10 digits possible, plus AM/PM indicators,
     *  the colon, fillers, etc. We also set the value of the BORDER
     *  attribute to be 0, so we don't get any blank spaces coming
     *  from there.
     *
     *  This is time-consuming to set up, but at least it's pretty
     *  straightforward.
     *
     *  Now it isn't all that useful to put a realtime clock like
     *  this in your game, but you might find it useful to have a
     *  watch that displays the current time in the game rather than
     *  real life. Or you could make a mini version of the graphics,
     *  and stick a clock like this into the status line, for games
     *  that display the current time of day rather than the score.
     *  (Infocom's mysteries did this - it's 8:39 PM and you have 15
     *  hours in which to solve the murder, etc.)
     *
     *  Of course, making a working analogue dial clock could present
     *  something of a challenge to the dedicated TADS hacker...
     *
     *  Note that I used single quotation marks within the <IMG> tags
     *  here. I could have used escaped double quotation marks (\")
     *  but it gets really annoying balancing all the double quote
     *  marks. If you forget to escape one of the quotation marks
     *  then the thing will fail to compile. And heaven help you if
     *  you accidentally type "\ instead of \". Using single quotation
     *  marks avoids this problem - at least, in these instances.
     *
     *  But one very very important thing - do not ever mix single and
     *  double quotation marks within the same tag attribute. Doing so
     *  invites grief and tragedy into your home. As an example, the
     *  following tag will break in nasty ways when the interpreter
     *  vainly tries to parse it:
     *
     *  <IMG SRC=\"sun.jpg'>
     *
     *  We bracket the clock image with <NOBR> tags so that the clock
     *  image shouldn't break up if the window is made very narrow.
     *
     *  Note also that the clock images are within a directory
     *  named, logically enough, "clock". So if the clock images
     *  don't appear when you view it, make sure that the directory
     *  or folder is present and named correctly. Or, if you're
     *  using a .gam file with embedded resources, make sure you
     *  put the directory string into the name properly.
    */

    "It&rsq;s a digital clock that&rsq;s displaying the current time.

    <P><BR>

    <CENTER>

    <NOBR>

    <IMG SRC='clock/left.jpg' BORDER=0><IMG SRC='clock/lead-";

    /*
     *  TADS returns the time in 24-hour format, but we just
     *  want 12.
     */

    if ( realHour > 12 )
      realHour := realHour - 12;

    if ( realHour = 0 )
      realHour := 12;

    if ( realHour > 9 )
    {
      "1.jpg' BORDER=0><IMG SRC='clock/";
      
      /*
       *  If the hour value is 10, 11 or 12 then we need a leading
       *  1, so we display that. Otherwise we display a leading
       *  blank.
       *
       *  Now in the case of hour values 10, 11 and 12, we want to
       *  know the value of the ones column, not the value of
       *  the tens column. We could process the number mathematically,
       *  but it seems to me that converting the number to a
       *  string and then printing the second character works
       *  just as well. So we do that.
       */

      say( substr( cvtstr( realHour ), 2, 1 ) );

    }
    else
    {
      "blk.jpg' BORDER=0><IMG SRC='clock/";
      say( realHour );
    }

    ".jpg' BORDER=0><IMG SRC='clock/colon.jpg' BORDER=0>";

    if ( realMinute < 10 )
    {
      "<IMG SRC='clock/0.jpg' BORDER=0><IMG SRC='clock/";
      say( realMinute );
    }
    else
    {
      "<IMG SRC='clock/";

      /*
       *  Here we take advantage of the fact that TADS handles
       *  only integer mathematics and not floating point. By
       *  dividing by 10 you get the stuff on the right side of
       *  the decimal automatically thrown out. Because we want
       *  the value of the tens column, not the whole minute
       *  value.
       *
       *  Of course, if TADS were to be upgraded to understand
       *  floating point then this code would break severely.
       *  I don't expect that's likely to happen anytime soon,
       *  though. Text adventures don't usually need floating
       *  point arithmetic.
       */

      say( ( realMinute / 10 ) );
      ".jpg' BORDER=0><IMG SRC='clock/";

      /*
       *  Once again, we just want the value of the ones
       *  column, so we convert the number to a string for
       *  simplicity's sake.
       */

      say( substr( cvtstr( realMinute ), 2, 1 ) );
    }

    ".jpg' BORDER=0><IMG SRC='clock/";

    if ( ( realTime[ 6 ] < 12 or realTime[ 6 ] = 24 ) )
      "a";
    else
      "p";

    "m.jpg' BORDER=0><IMG SRC='clock/right.jpg' BORDER=0>

    </NOBR>

    </CENTER>";

  }
;

compass: item
  sdesc =
  {
    displayLink( 'examine the compass', 'DirectionMaster 2000' );
  }
  noun = 'compass'
  adjective = 'small' 'handheld' 'electronic' 'directionmaster'

  /*
   *  Note: you can't set "2000" as a noun, because it would conflict
   *  with the number 2000. Oh well.
   */

  location = Me
  ldesc =
  {

    "It&rsq;s a DirectionMaster 2000&trade;; the top of the line model.
    In other words, it&rsq;s a small handheld electronic compass. (how
    else did you think you always know which way is north?) ";

    /*
     *  If the compass is not turned on we simply display a JPEG
     *  image of the inactive compass. We also set a clickable
     *  map so that the player can click on the compass power
     *  button to turn it on. This we do first by defining a set of
     *  clickable map coordinates, then assigning those coordinates
     *  to the image by using the USEMAP attribute.
     *
     *  Note that HTML-TADS supports only rectangles and ellipses
     *  for the coordinate areas. The power button on the compass
     *  is an odd shape, so we simply draw a rectangle that
     *  encompasses the whole thing. If we wanted to be fussy we
     *  could have built up a series of overlapping coordinates to
     *  approximate the button's shape a bit more accurately, but
     *  I really think that that would be have been a waste of time.
     *  Some Web browsers support the POLY shape for clickable maps,
     *  but HTML-TADS doesn't. (frankly I don't blame Mike one bit
     *  for not implementing POLY - the code is a lot more work.)
     *  So if you use a graphical HTML editing program to build
     *  your clickable maps, be sure you don't have any SHAPE=POLY
     *  attributes in there.
     *
     *  Don't forget that you have to set the <IMG> tag's BORDER
     *  attribute to 0. If you don't then there'll be a coloured
     *  rectangular border around the image, which is probably not
     *  what you want for a split-image picture like this. But it
     *  might be a desirable effect for some other types of images.
     *
     *  And I admit that the alleged electronic compass looks
     *  nothing at all like a compass. Perhaps it's a sort of
     *  cybercompass used by adventurers in some strange parallel
     *  universe in which there are eight compass rose directions,
     *  and no shades of grey. The other excuse is that a real
     *  compass is designed just to point north, whereas this
     *  thing can indicate possible exits in many different
     *  directions simultaneously. Of course, it's really just a
     *  modified photo of a cellular phone, since the phone
     *  happened to be lying on my desk when I was prowling
     *  around the office with a digital camera.
     */

    if ( not self.isActive )
    {
      "It&rsq;s currently switched off.
      <P><BR>
      <CENTER>
      <MAP NAME='dm-off-map'>
      <AREA SHAPE=RECT COORDS='50,52,173,72' HREF='press power button'>
      </MAP>
      <IMG USEMAP='#dm-off-map' SRC='compass/dm-off.jpg'>
      </CENTER>";
    }
    else
    {

      "It&rsq;s switched on, its gold-coloured sensor faintly glowing. ";

      /*
       *  This next bit is fairly complicated and probably looks
       *  rather daunting. So if you aren't very familiar with both
       *  HTML and TADS you may want to hold off dealing with this
       *  bit until the rest of the demo looks clear enough to you.
       *
       *  Basically it's just an HTML table, with JPEG images as the
       *  basic item filling each cell. The table is designed in such
       *  a fashion that the images touch one another and there are no
       *  visible gaps. The result is an graphic that looks like one
       *  single picture. That means we can change individual images
       *  at will, so we can switch on individual buttons (for active
       *  directions) without affecting the other buttons. This
       *  naturally necessitates a total of 18 separate JPEG images -
       *  one for each button, in one of two states, on or off.
       *
       *  Now you may be wondering why I implemented this thing as a
       *  table rather than, as in the previous example, just a load
       *  of graphics lined up side by side. Well there are a couple
       *  reasons. First, it's meant to be an Exercise to show you
       *  what's possible, and second, as a table the whole image is
       *  treated as a single entity. That means you can wrap text
       *  around the side of the table, which you couldn't do if the
       *  compass were made up of multiple <IMG>s sitting in a line.
       *
       *  In other words, this whole thing is quite a bit of work for a
       *  fairly simple effect. It may or may not be worth implementing
       *  something like this in a real game, but again this is a demo
       *  showing you some of what is possible.
       *
       *  And remember, you can use the same basic technique anywhere.
       *  For example, imagine putting an active compass like this in
       *  the status line. This game uses the default status line, but
       *  I could have implemented a fancy banner with a compass and
       *  whatnot instead. You could go all out if you wanted to -
       *  say, a status line that contains a little meter showing
       *  the energy levels remaining in the player's lamp. Or a small
       *  table containing little icons for each object in the player's
       *  possession. Whatever you like!
       *
       *  Remember that you can also implement multiple status lines
       *  by putting in more than one <BANNER>. So you could, for example,
       *  have two banners. The first would be a traditional status line
       *  with room location and score (or time of day) and the second
       *  could be a sort of button bar, like the kind found in typical
       *  office productivity (using the term loosely) software. This
       *  button bar could have a mini active compass, buttons that when
       *  clicked issue commands like "INVENTORY" or "LOOK" and so on.
       *
       *  Naturally you'd make this second status line optional at the
       *  player's behest, so as to avoid irritating players who don't
       *  like such gadgets. (for example, people with small screens
       *  might object to having their valuable real estate consumed by
       *  features they don't use.)
       *
       *  Anyway. This is just a modest weird-looking compass. And so
       *  we start by setting up the table, then defining the first
       *  row, then the first cell in the row. To make things fancier
       *  note that we also include a clickable map. That means that
       *  players can click directly on the button to have an HREF
       *  typed in, but clicking elsewhere on the image will have no
       *  effect.
       *
       *  Note also that the compass images are within a directory
       *  named "compass". If the compass images fail to show up
       *  check that the images are in the right place, as with the
       *  clock images.
       */

      "<P><BR>
      <CENTER>
      <TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0>

      <TR>

      <TD VALIGN=TOP WIDTH=91 HEIGHT=112>
      <MAP NAME='nw-map'>
      <AREA SHAPE=RECT COORDS='52,53,90,71' HREF='press power button'>
      <AREA SHAPE=RECT COORDS='49,84,85,104' HREF='northwest'>
      </MAP>
      <IMG USEMAP='#nw-map' SRC='compass/nw";

      /*
       *  Now we check to see if the player can proceed to the northwest
       *  or not. This we do by checking a binary flag in the player's
       *  current location. The value of this flag is passed through to
       *  a very simple function that just prints "on" or "off" depending
       *  on the value of the parameter passed to it. So the end result
       *  is that if the player can walk in this direction then the
       *  appropriate button is lit up green. If the player can't then
       *  the button stays dimmed. If we wanted to, we could omit the
       *  USEMAP attribute for any button that's dim, so the player
       *  wouldn't be able to click on it. But for simplicity I just
       *  left every button as a potentially clickable one.
       *
       *  Of course, pedants will note that the compass doesn't indicate
       *  the available directions relative to the compass, but to the
       *  player. But since the player is the only character in this game,
       *  I hardly think it's an issue. The other thing that's a bit on
       *  the wacky side is the whole thing about clicking on buttons.
       *  I just set it so that clicking a given button moves the player
       *  in that direction if possible, which doesn't really make much
       *  sense. I dunno. Maybe the player is really a robot.
       */

      printOnOff( Me.location.nwActive );

      "WIDTH=91 HEIGHT=112 BORDER=0 ALIGN=TOP>
      </TD>

      <TD VALIGN=TOP WIDTH=44 HEIGHT=112>
      <MAP NAME='n-map'>
      <AREA SHAPE=RECT COORDS='0,54,43,72' HREF='press power button'>
      <AREA SHAPE=RECT COORDS='3,85,37,103' HREF='north'>
      </MAP>
      <IMG USEMAP='#n-map' SRC='compass/n";

      printOnOff( Me.location.nActive );

      "WIDTH=44 HEIGHT=112 BORDER=0 ALIGN=TOP>
      </TD>

      <TD VALIGN=TOP WIDTH=82 HEIGHT=112>
      <MAP NAME='ne-map'>
      <AREA SHAPE=RECT COORDS='0,53,38,71' HREF='press power button'>
      <AREA SHAPE=RECT COORDS='5,85,39,102' HREF='northeast'>
      </MAP>
      <IMG USEMAP='#ne-map' SRC='compass/ne";

      printOnOff( Me.location.neActive );

      "WIDTH=82 HEIGHT=112 BORDER=0 ALIGN=TOP>
      </TD>

      </TR>

      <TR>

      <TD VALIGN=TOP WIDTH=91 HEIGHT=33>
      <MAP NAME='w-map'>
      <AREA SHAPE=RECT COORDS='51,7,84,26' HREF='west'>
      </MAP>
      <IMG USEMAP='#w-map' SRC='compass/w";

      printOnOff( Me.location.wActive );

      "WIDTH=91 HEIGHT=33 BORDER=0 ALIGN=TOP>
      </TD>

      <TD VALIGN=TOP WIDTH=44 HEIGHT=33>
      <MAP NAME='in-map'>
      <AREA SHAPE=RECT COORDS='5,8,39,25' HREF='in'>
      </MAP>
      <IMG USEMAP='#in-map' SRC='compass/in";

      printOnOff( Me.location.inActive );

      "WIDTH=44 HEIGHT=33 BORDER=0 ALIGN=TOP>
      </TD>

      <TD VALIGN=TOP WIDTH=82 HEIGHT=33>
      <MAP NAME='e-map'>
      <AREA SHAPE=RECT COORDS='5,7,38,24' HREF='east'>
      </MAP>
      <IMG USEMAP='#e-map' SRC='compass/e";

      printOnOff( Me.location.eActive );

      "WIDTH=82 HEIGHT=33 BORDER=0 ALIGN=TOP>
      </TD>

      </TR>

      <TR>

      <TD VALIGN=TOP WIDTH=91 HEIGHT=90>
      <MAP NAME='sw-map'>
      <AREA SHAPE=RECT COORDS='51,7,84,26' HREF='southwest'>
      </MAP>
      <IMG USEMAP='#sw-map' SRC='compass/sw";

      printOnOff( Me.location.swActive );

      "WIDTH=91 HEIGHT=90 BORDER=0 ALIGN=TOP>
      </TD>

      <TD VALIGN=TOP WIDTH=44 HEIGHT=90>
      <MAP NAME='s-map'>
      <AREA SHAPE=RECT COORDS='6,7,39,26' HREF='south'>
      </MAP>
      <IMG USEMAP='#s-map' SRC='compass/s";

      printOnOff( Me.location.sActive );

      "WIDTH=44 HEIGHT=90 BORDER=0 ALIGN=TOP>
      </TD>

      <TD VALIGN=TOP WIDTH=82 HEIGHT=90>
      <MAP NAME='se-map'>
      <AREA SHAPE=RECT COORDS='7,8,39,24' HREF='southeast'>
      </MAP>
      <IMG USEMAP='#se-map' SRC='compass/se";

      printOnOff( Me.location.seActive );

      "WIDTH=82 HEIGHT=90 BORDER=0 ALIGN=TOP>
      </TD>

      </TR>

      </TABLE>

      </CENTER>";

      /*
       *  OK. A few observations here. First of all, this isn't the
       *  most efficient way to code this up. A slicker way would be
       *  a function that's called repeatedly with the appropriate
       *  parameters for each cell, pulled out of an array or
       *  whatever. To make things a bit easier to read and because
       *  I'm lazy I just printed it all out in a linear fashion.
       *
       *  Second, having separate flags for each direction that the
       *  player can go in isn't all that efficient either. As it
       *  means that the author has to write in possible directions
       *  for each room by hand. A more interesting way to do it
       *  would be to examine each exit individually. Problem is you
       *  can't just call each exit method, because that would trigger
       *  any code in there and cause all kinds of unwanted side
       *  effects.
       *
       *  A superficial method to check safely would be to call the
       *  proptype() function on each direction method. This will
       *  let you know if the direction is nil (a returned value of
       *  5) or an object (returned value of 2) or code (returned
       *  value of 6). However, this isn't a terribly accurate way
       *  to do it. The reason I say superficial is because it doesn't
       *  help you in the case of code that returns a room location.
       *
       *  So, if you wanted to be fancy, you could rewrite direction
       *  code such that the direction code for each object can tell
       *  if it's simply being evaluated for compass purposes, or if
       *  it's really been executed for real. (ie: a player is trying
       *  to move in that direction) This, however, would involve some
       *  rewriting of the way adv.t works. Or else an adoption of
       *  WorldClass, which lets you test for this stuff more easily.
       *
       *  As it is, I just coded this thing up with flags for now. A
       *  real game I'm working on has such direction-checking code,
       *  but it involved a *lot* of changes to the adv.t libraries to
       *  cover various unusual contingencies. I'm not going to include
       *  that hacked-up code with this demo, as it's really beyond the
       *  scope of the purpose of this game.
       *
       *  You know, writing this stuff up has really given me a new
       *  perspective on the bits left as reader exercises in those
       *  programming textbooks...
       */
    }
  }

  /*
   *  A couple of synonyms for the convenience of the user.
   */

  verDoTurnon( actor ) =
  {
    if ( self.isActive )
      "The compass is already on! ";
  }
  doTurnon( actor ) =
  {
    self.isActive := true;
    "<SOUND INTERRUPT SRC='click.wav' LAYER=FOREGROUND>
    The compass goes on, and the gold sensor starts to glow. ";
  }
  verDoTurnoff( actor ) =
  {
    if ( not self.isActive )
      "The compass is already off! ";
  }
  doTurnoff( actor ) =
  {
    self.isActive := nil;
    "<SOUND INTERRUPT SRC='click.wav' LAYER=FOREGROUND>
    The compass goes off, dimming the gold sensor. ";
  }
;

powerButton: buttonitem
  sdesc = "power button"
  adjective = 'power'
  location = compass
  doPush( actor ) =
  {
    "You press the compass power button. 
    <SOUND INTERRUPT SRC='click.wav' LAYER=FOREGROUND>";

    if ( compass.isActive )
    {
      compass.isActive := nil;
      "The gold sensor dims. ";

    /*
     *  I'm not going to bother implementing the sensor
     *  as a separate object.
     */

    }
    else
    {
      compass.isActive := true;
      "The gold sensor lights up cheerily. ";
    }
  }
;

/*
 *  We take advantage of TADS' replace and modify features to alter
 *  existing bits of code to suit our nefarious requirements.
 */

replace init: function
{
  "\H+";

  /*
   *  The \H+ bit is the magical incantation that
   *  instructs the TADS interpreter that henceforth
   *  we want HTML to be parsed as HTML rather than
   *  displayed as text for the user to puzzle over.
   */

  "<TITLE>The Golden Skull</TITLE>";    // set the window title

  "<ABOUTBOX>

  <BODY BACKGROUND=\"red-bg.jpg\" BGCOLOR=RED TEXT=WHITE>

  <P>

  <CENTER>

  <IMG SRC=\"redtitle.jpg\">

  <P>

  A miniature demonstration game for HTML-TADS. Version 0.7. April, 1998.

  <P>

  Copyright &copy; 1987-1998 Michael J.\ Roberts, N.\ K.\ Guy.

  <P>

  </CENTER>

  </ABOUTBOX>";

    /*
     *  That code sets the custom about box that users can select
     *  for more information on the game. Note a few things about
     *  it. First, you can set a body tag just for the about box,
     *  to ensure it looks different from the page. In the example
     *  here I've set a background image - a repeating red background
     *  image. The title graphic is different from the one used
     *  elsewhere in the game, because in this instance the graphic
     *  is designed to be placed over top of a red graphic and not
     *  a white one. Since I used a shadowed edge rather than a
     *  hard edge, I had to use two different image files.
     *
     *  Second, HTML-TADS supports the true copyright (circle-C)
     *  symbol, so we can use it instead of the ugly (c) ASCII
     *  approximation.
     *
     *  Third, there are no links in the about box. Because the
     *  about box appears as a separate dialogue box over top of
     *  the main scrolling text entry window, it doesn't really
     *  make any sense to include links. So you could include a
     *  clickable link if you wanted to, and it'd appear underlined
     *  and everything, but it wouldn't do anything if the user
     *  were to click it.
     */

  version.sdesc;                   // display the game's name
                                   // and version number

  setdaemon( turncount, nil );     // start the turn counter daemon
  Me.location := startroom;        // move player to initial location
  startroom.lookAround( true );    // show player where he or she is
  startroom.isseen := true;        // note that we've seen the room

  "<BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\">";
                                   // set the page colour to white
                                   // w/ black text

  "<SOUND SRC=\"outside.wav\" LAYER=BGAMBIENT REPEAT=LOOP>
  <SOUND SRC=\"bird.wav\" LAYER=AMBIENT RANDOM=\"5\">";
                                   // start the "outside" sound playing.
                                   // It runs in the background ambient
                                   // layer and loops incessantly. We
                                   // also add a chirping bird to the 
                                   // ambient layer.
}

replace version: object
  sdesc =
  {

    "<P>

    <CENTER>

    <IMG SRC=\"title.jpg\">

    <P>

    A miniature demonstration game for ";
    displayLink( 'about', 'HTML-TADS' );
    ". Version 0.7.

    <P>

    Copyright &copy; 1987-1998 Michael J.\ Roberts, N.\ K.\ Guy.

    <P>

    Please read the ";

    displayLink( 'copyright', 'copyright' );

    " notice for further information.

    </CENTER>

    <P>";
  }
;

/*
 *  I just happen to like boldfaced room titles.
 *  So I, as author, hereby decree boldfaced room titles.
 */

modify room
  statusRoot =
  {
    "<B>"; self.sdesc; "</B>";
  }
;

 /*
  *  We need to make the following modification to the nested
  *  room code used by chairs, the floor, etc. Since the compass
  *  code simply checks the player's current location, it will
  *  break if the player sits on the floor. (the floor room will
  *  not have the necessary flags to indicate possible directions
  *  to the compass.) So we modify nestedroom such that each of
  *  the active flags picks up the correct value from its location.
  *
  *  Note also that we don't just return the appropriate value
  *  from the room's location, because it's always conceivable that
  *  a room hasn't got a location. (it might get moved to nil for
  *  some strange reason.) To ensure that the player never gets to
  *  see an ugly 1010 runtime error we check to see if there is,
  *  in fact, a player location before we try to evaluate the
  *  appropriate active property. And, while we're being paranoid,
  *  we also return a nil value if there's no self.location.
  *  Anything to minimize the risks of unexpected errors cropping
  *  up.
  */

modify nestedroom
  nActive =
  {
    if ( self.location )
      return( self.location.nActive );
    else
      return( nil );
  }
  sActive =
  {
    if ( self.location )
      return( self.location.sActive );
    else
      return( nil );
  }
  eActive =
  {
    if ( self.location )
      return( self.location.eActive );
    else
      return( nil );
  }
  wActive =
  {
    if ( self.location )
      return( self.location.wActive );
    else
      return( nil );
  }
  nwActive =
  {
    if ( self.location )
      return( self.location.nwActive );
    else
      return( nil );
  }
  neActive =
  {
    if ( self.location )
      return( self.location.neActive );
    else
      return( nil );
  }
  swActive =
  {
    if ( self.location )
      return( self.location.swActive );
    else
      return( nil );
  }
  seActive =
  {
    if ( self.location )
      return( self.location.seActive );
    else
      return( nil );
  }
  inActive =
  {
    if ( self.location )
      return( self.location.inActive );
    else
      return( nil );
  }
;

/*
 *  We assume that the player likes having clickable
 *  hot links all the time. The HTML value is a simple
 *  binary flag so that the game knows whether HTML
 *  parsing is on or off, and is used by the HTML verb
 *  below.
 */

modify global
  displayLinks = true
  displayGraphicsOnce = true
  maxscore = 1
  html = true
;

/*
 *  Someone was complaining on r.a.i-f the other month that
 *  TADS doesn't supply 'q' by default as a synonym for 'quit'.
 *  Well, just to show how incredibly hard it is to fix that:
 */

modify quitVerb
  verb = 'q'
;

/*
 *  We have a verb to let players choose whether they want
 *  graphics displayed once or each time. I think I'm going
 *  to change this to have a 3-mode function roughly equivalent
 *  to the brief, superbrief and verbose modes usually associated
 *  with text, rather than this simple two-mode thing.
 */

graphicsVerb: sysverb
  verb = 'graphics' 'images'
  action( actor ) =
  {
    global.displayGraphicsOnce := not global.displayGraphicsOnce;

    if ( global.displayGraphicsOnce )
      "Graphics will only ever be shown to you once. ";
    else
      "Graphics will be displayed every time the object in
      question is examined. ";
  }
;

/*
 *  We allow the player to turn off links.
 */

linksVerb: sysverb
  verb = 'links'
  action( actor ) =
  {
    global.displayLinks := not global.displayLinks;

    "Clickable hot links will n";

    if ( global.displayLinks )
      "ow";
    else
      "ever";

    " be displayed. ";
  }
;

/*
 *  A simple debugging verb that will enable or disable HTML-TADS's
 *  HTML parsing. So instead of display formatted HTML on-screen,
 *  the interpreter simply displays the raw HTML code. Note that
 *  this verb isn't the world's most elegant implementation, since
 *  it shuts off parsing immediately, and that interferes with
 *  the status line. (you end up with two status lines on-screen)
 *
 *  Still, for testing purposes, it's adequate. Basically this is
 *  useful when you want to examine the exact HTML that your code is
 *  outputting, to make sure that it makes sense. Often you'll find
 *  that some messed-up screen display simply stems from forgetting
 *  to close a " or a >.
 *
 *  Don't forget that the normal TADS escape sequences still work
 *  in HTML-TADS. So if the on-screen formatting looks a little
 *  weird, even when you have the HTML displayed and not parsed,
 *  hunt through the source code for rogue \b and \n and similar
 *  escape sequences.
 *
 *  Another trick you might want to consider when debugging your
 *  game is to go through and modify adv.t and std.t, removing
 *  any references to standard TADS escape sequences. So you'd
 *  replace \b with <P>, \n with <BR HEIGHT=0>, \t with <TAB
 *  MULTIPLE=4>. The <BR> HEIGHT attribute is a TADSism that
 *  specifies that the line break should have a height of zero.
 *  (ie: multiple <BR>s with a zero height will not add a bunch
 *  of newlines the way HTML normally does) The <TAB> MULTIPLE
 *  attribute is another TADS extension that specifies that the
 *  tab should be lined up with the next tab stop set to a
 *  multiple of 4 the way \t traditionally works.
 *
 *  Replacing all the escape sequences will mean you have a
 *  non-standard TADS library, so keep that in mind when new
 *  versions are released. However this trick is useful for
 *  testing purposes so you can see exactly what formatting is
 *  being done to your text. (thus saving time hunting through
 *  source code for escape sequences.)
 *
 *  The new global variable global.html is one we track
 *  ourselves, since there's no function call to determine
 *  whether parsing is on or off.
 *
 */

HTMLVerb: sysverb
  verb = 'html'
  action( actor ) =
  {
    if ( global.html )
    {
      "HTML parsing is now disabled.\b
      \H-";
      global.html := nil;
    }
    else
    {
      "\H+
      HTML parsing is now enabled.";
      global.html := true;
    }
    abort;
  }
;

copyrightVerb: sysverb
  verb = 'copyright'
  action( actor ) =
  {
    "<B>The Golden Skull</B> started out life as sample code included
    in the TADS Author&rsq;s Manual &emdash; copyright &copy; 1987-98
    by Michael J.\ Roberts.

    <P>

    Conversion to HTML, extensive commentary, additional material and
    original graphics and sound copyright &copy; 1996-98 by N.\ K.\ Guy,
    tela design. http://www.tela.bc.ca/tela/tads/

    <P>

    The TADS code that makes up this game may be may be copied,
    distributed, used freely in the creation of other TADS games.
    and modified. The images, however, are under copyright as
    detailed above and may <I>not</I> be used in or in conjunction
    with any other game or Web page or whatever without the prior
    permission of me, the photographer. Thanks!

    <P>";
  }
;

aboutVerb: sysverb
  verb = 'about'
  action( actor ) =
  {
    "<CENTER>

    <IMG SRC=\"title.jpg\">

    </CENTER>

    <P>

    <BLOCKQUOTE>

    <FONT SIZE=\"-1\">Welcome to <B>The Golden
    Skull</B>, a miniature game designed to demonstrate some of
    the groovy new features incorporated in HTML-TADS.

    <P>

    &ldq;Gold Skull&rdq; was originally just a few lines of sample
    code that Mike Roberts included in the TADS Author&rsq;s Manual. I
    decided to expand a little on those brief pieces and make a small
    HTML-TADS demo out of them. I also decided to name it &ldq;The
    Golden Skull&rdq; since that has a nice Conan Doyle feel to it.

    <P>

    And that&rsq;s all this thing really is &emdash; it&rsq;s a little
    demonstration of some HTML-TADS features. It therefore isn&rsq;t
    either a) an earth-shatteringly exciting game or b) the paragon of
    tasteful user-interface design. In fact, there are a couple of features
    in this game which would probably prove extremely irritating to the
    average player in a real game. Ah, well.

    <P>

    The images are all original. The cave entrance and interior are
    from photographs of the Thurston lava tube that I took on a rainy
    day in late 1996. This geological formation is near the summit of
    Kilauea, Big Island, Hawaii, USA. The skull itself is a
    life-sized ceramic skull that I noticed in the window of a rock
    &lsq;n&rsq; roll paraphernalia shop in New Westminster, BC, Canada.
    In real life it is not made of solid gold.

    <P>

    All the images were heavily altered using Adobe Photoshop on a
    Macintosh. For example, the skull was originally a dark
    bluish-green and the real cave entrance has a rather
    unadventuresome-looking handrail. The photos were taken using a
    25 year-old Pentax Spotmatic SLR and a Kodak DC-50 digital camera.
    You can guess which of the two offered vastly superior image quality.

    <P>

    The sounds are a mix of original sounds and sounds ripped off
    one of those generic royalty-free sound effects albums. I intend
    to record all-original sounds for the final version of this thing,
    but I haven&rsq;t had the time yet. Sounds were manipulated using
    Macromedia SoundEdit 16 on a Mac.

    <P>

    Oh, and I&rsq;ve added two new preference commands to the thing.
    One, <B>graphics</B>, determines whether graphic images associated
    with a given object are displayed once only or each time and the
    other, <B>links</B>, determines whether or not clickable links
    are displayed. I might rename and modify the former, though.

    <P>

    &emdash; N.\ K.\ Guy

    </BLOCKQUOTE>

    </FONT>

    ";
    abort;
  }
;

/*
 *  Finally, what self-respecting text adventure could possibly
 *  forgo an implementation of xyzzy?
 */

xyzzyVerb: sysverb
  verb = 'xyzzy'
  action( actor ) =
  {
    "You hear a hollow voice muttering &ldq;Hot damn! HTML-TADS sure
    is cool! Too bad it doesn&rsq;t support &lt;BLINK&gt;, though.&rdq; ";
  }
;

