!\---------------------------------------------------------------------------

       THE VAULT OF HUGO
       Hugo v2.5 Tutorial Game

       by Kent Tessman (c) 1995-1999

---------------------------------------------------------------------------\!

#version 2.5

#set DEBUG                              ! include HugoFix library and grammar
#set VERBSTUBS                          ! include verb stub routines

#set USE_VEHICLES                       ! from OBJLIB.H
#set USE_PLURAL_OBJECTS                 !
#set USE_ATTACHABLES                    !

#set NO_AUX_MATH                        ! don't need advanced math routines

#switches -ls                           ! print statistics to SAMPLE.LST
#ifset DEBUG
#switches -d
#endif


! The following limit setting reserves 512 extra bytes of dictionary space
! so that the play can name the unnamed object.  A maximum 512 bytes are
! required because the game needs to write the name, adjective, and misc
! properties of the object.

$MAXDICTEXTEND = 512


!----------------------------------------------------------------------------
! NEW GRAMMAR:

verb "kick", "punt", "boot"
       *                                               DoVague
       * object                                        DoPunt

verb "board"
       * (minecar)                                     DoEnter

verb "roll", "drive", "steer", "ride"
       *                                               DoVague
       * object                                        DoMoveinVehicle
       * "to" object                                   DoMoveinVehicle

! In the grammar definitions below, STRING refers to any section of the
! player's input enclosed in quotation marks.

verb "write", "scribble", "scrawl", "print"
       *                                               DoVague
       * "on" object                                   DoWriteOn
       * "on" object "with" held                       DoWriteOn
       * string                                        DoWrite
       * string "on" object                            DoWrite
       * string "on" object "with" held                DoWrite
       * string "with" held                            DoWrite

verb "name", "call", "christen"
       *                                               DoVague
       * (unnamedobject)                               DoNameWhat
       * (unnamedobject) string                        DoName

verb "stick"
       *                                               DoVague
       * (dart)                                        DoAttachObject
       * (dart) "in"/"on" (dartboard)                  DoAttachObject


#include "verblib.g"                    ! normal verb grammar

!----------------------------------------------------------------------------

#ifset PRECOMPILED_LIBRARY
#link "hugolib.hlb"
#else
#include "hugolib.h"                    ! standard library routines
#endif

! Normally, the library's PrintScore routine uses a MAX_SCORE/score
! formula to determine a ranking (if rankings are provided); the following
! global is used in the replaced PrintScore routine to ensure that rank is
! set by the game, not approximated by the library.

global rank

routine init
{
       MAX_SCORE = 50
       ranking[0] = "Amateur Adventurer"
       ranking[1] = "Competent Door-Unlocker"
       ranking[2] = "Bomb-Meddling Adventurer"
       ranking[3] = "Master Magic Wand Finder"
       ranking[4] = "The Genuine Article Sample Game Solver"
       MAX_RANK = 4

       counter = -1                    ! 1 turn before turn 0

       STATUSTYPE = 1                  ! score/turns
       TEXTCOLOR = DEF_FOREGROUND
       BGCOLOR = DEF_BACKGROUND
       SL_TEXTCOLOR = DEF_SL_FOREGROUND
       SL_BGCOLOR = DEF_SL_BACKGROUND

       prompt = ">"
       color TEXTCOLOR, BGCOLOR

       DEFAULT_FONT = PROP_ON
       Font(DEFAULT_FONT)

       cls
       "You brace yourself, check your flashlight, and, with \
       source code in hand, prepare to enter...\n"

       Font(BOLD_ON)
       "THE VAULT OF HUGO"
       Font(BOLD_OFF)
       "An Interactive Example"
       print BANNER

       player = you
       location = outsidevault
       old_location = location

       move player to location         ! initialize player location
       FindLight(location)             ! whether the player can see
       DescribePlace(location)         ! the appropriate description
       location is visited
       CalculateHolding(player)        ! total size of player contents

       Acquire(player, flashlight)     ! give the player the flashlight
       flashlight is known

       Activate(key_daemon)            ! set up initial daemons

       InitPluralObjects
}

#ifset PRECOMPILED_LIBRARY
replace main
{
#else
routine main
{
#endif
       counter = counter + 1
       PrintStatusLine
       run location.each_turn
       runevents
       RunScripts
       if speaking not in location     ! in case the character being spoken
               speaking = 0            ! to leaves
}

player_character you "you"
{}


! flashlight
!
! The flashlight is an example of a light source.  The rules for
! the FindLight routine in HUGOLIB.H check to see if any light sources
! are available (starting with the room itself, then working through
! the visible contents) before deciding if the player is able to see
! in any given location.

object flashlight "flashlight"
{
       in you
       nouns "flashlight", "light", "torch", "lamp"
       adjective "flash"
       article "your"
       short_desc
       {
               CArt(self)
               " is here, ";
               if self is switchedon
                       "glowing brightly."
               else
                       "turned off."
       }
       long_desc
       {
               "It's one of those disposable kinds.  Built-in battery.  \
               $3.99 at the corner store.  That sort of thing.  At the
               moment, it is ";
               if self is switchedon
                       "on."
               else
                       "off."
       }
       before
       {
               ! The before property routine attempts to match the verb
               ! routine based on a given specifier.  In the case below,
               ! if the verbroutine global is set to DoBurn (technically
               ! &DoBurn, the address of the DoBurn routine) and the
               ! object global is set to the flashlight object, the
               ! following routine is run before (in place of) the DoBurn
               ! routine.

               object DoBurn
                       {Perform(&DoSwitchOn, self)}
       }
       after
       {
               ! The two routines below are similar to the before routine
               ! above, except that they are run after the verb routine.

               object DoSwitchOn
               {
                       "A beam of serviceable light appears from your
                       flashlight."
                       self is light
                       FindLight(location)
                       if location is not visited
                               {DescribePlace(location)
                               location is visited}
               }
               object DoSwitchOff
               {
                       "Your flashlight goes dark.  ";
                       self is not light
                       if FindLight(location)
                               print newline
                       else
                               "And so does everything else."
               }
       }
       is switchable
}

!----------------------------------------------------------------------------
! OUTSIDE THE VAULT
!----------------------------------------------------------------------------
room outsidevault "outside a vault"
{
       long_desc
               {"Kind of that 1930s, Bela Lugosi, graveyardy motif at
               work here.  It's a pretty creepy place.  Directly in
               front of you is the giant door to an even more giant
               vault.  Above the door hangs a rusty sign."}
       e_to {return vaultdoor.door_to}
       in_to {return vaultdoor.door_to}
       cant_go
               {"Vines, thorns, and bent, twisted trees bar travel in any
               direction away from the vault."}
       before
       {
               location DoDig
               {
                       if object ~= bump
                               "You can't dig in that."
                       else
                               Perform(&DoSearch, bump)
               }
       }
}


! key_daemon
!
! This basic daemon is simply a trigger that checks every turn to see
! if 10 turns have passed.  If so, it prints a brief section of prose
! before deactivating itself.  (It is also deactivated if the player
! pre-emptively searches the bump in the ground.)

daemon key_daemon
{}

event key_daemon
{
       if counter = 10
       {
               "\nAll this shuffling around outside the door has uncovered
               a little bump in the ground."

               event_flag = true
               Deactivate(key_daemon)
       }
}

scenery bump "little bump"
{
       in outsidevault
       nouns "bump", "ground"
       adjective "little"
       article "a"
       long_desc
       {
               if key is not moved
                       {"It looks like there might be something there."
                       bump is moved}
               else
                       {"You've already got the key.  What more do
                       you want?"}
       }
       before
       {
               ! More than one verb routine may be given as a potential
               ! match to a specifier in a before or after routine, as in:

               object DoSearch, DoDig
               {
                       if key is moved
                               "You already did.  There's nothing else
                               to find."
                       else
                       {
                               bump is moved
                               "You find a rusty iron key!\n(Taken.)"
                               Acquire(player, key)
                               score = score + 10
                               Deactivate(key_daemon)
                       }
               }
       }
}

object key "rusty iron key"
{
       noun "key"
       adjectives "rusty", "iron"
       article "a"
       size 20
       long_desc
               {"A skeleton key.  Rusty.  Iron.  And heavy, too.  A perfect
               match for the vault door, no?"}
       before
       {
               xobject DoUnlock
               {
                       if object = oakdoor
                               "The rusty key doesn't work on this door."
                       else
                               return false    ! library continues as usual
               }
       }
}

scenery sign "rusty sign"
{
       in outsidevault
       noun "sign"
       article "a"
       adjective "rusty"
       long_desc {"\"Here lies Hugo.\""}
       is readable
}


! vaultdoor
!
! Notice that the found_in property specifies the rooms on either side
! of the door; OBJLIB.H does the rest.  The vault door's special attribute
! is set once the player scores points for opening it.

door vaultdoor "vault door"
{
       nouns "door", "doorway"
       adjective "vault", "giant"
       article "the"
       between outsidevault, insidevault
       key_object key
       after
       {
               object DoUnlock
               {
                       if self is not special
                       {
                               self is special
                               score = score + 10
                               rank = 1
                       }
                       return false    ! library continues as usual
               }
       }
       is not open, lockable, locked
}

scenery vault "vault"
{
       in outsidevault
       noun "vault"
       article "the"
       long_desc {"Big, imposing, and complete with rusty sign."}
       door_to                         ! so a player can "go vault"
               {return vaultdoor.door_to}
       before
       {
               object DoEnter
               {
                       object = vaultdoor      ! change object before letting
                       return false            ! library continue normally
               }
       }
}

!----------------------------------------------------------------------------
! INSIDE THE VAULT
!----------------------------------------------------------------------------
room insidevault "inside the vault"
{
       long_desc
       {
               "Standing in the middle of this dimly lit chamber, you
               realize that just maybe you should've splurged on a
               more expensive flashlight.  You also realize that there
               are four ways you can go:  a marble archway to the north,
               a muddy cave opening to the east, ";
               if oakdoor is not blown_open
                       "an oak door set in a brick frame";
               else
                       "an empty brick frame where the oak door used to be";
               " to the southeast, and west back outside where you came
               from."
       }
       w_to {return vaultdoor.door_to}
       out_to {return vaultdoor.door_to}
       se_to {return oakdoor.door_to}
       n_to objectroom
       e_to characterroom
       in_to {"You'll have to be a little more specific about which way
               you want to go."}
       is not light
       after
       {
               location DoGo

                       ! changes the way the vault is refered to from
                       ! "a vault" to "the vault"--a stylistic thing

               {
                       outsidevault.name = "outside the vault"
                       return false
               }
       }
       vehicle_path minecar    ! i.e. the mine car can travel here
}


! minecar
!
! This is an excellent example of a basic vehicle from OBJLIB.H.  The
! vehicle_verbs property must mirror the valid words provided in the
! verb grammar at the start of this file.  The vehicle_move property is
! checked before the vehicle is allowed to move.  (This is where, for
! example, a car object would be checked to make sure that the ignition
! is turned on, or the tires aren't flat, etc.)  Any room in which travel
! in the mine car is permitted must have minecar in its vehicle_path
! property.

vehicle minecar "mine car"
{
       in insidevault
       nouns "car", "cart"
       adjectives "mine", "my", "old"  ! because:  synonym "mine" for "my"
                                       ! in HUGOLIB.H
       article "a"
       vehicle_verbs "roll", "drive", "steer", "ride"
       vehicle_move
       {
               ! Here, the mine car will not roll until the big rock is
               ! removed from under it.  Note that the rock is not actually
               ! under the car, but looking under the car moves it from
               ! the nothing object to the room object.

               if bigrock in nothing
                       {"Something seems to be stopping the mine car
                       from rolling."
                       return false}
       }
       initial_desc
               {"An old mine car sits abandoned to one side."}
       long_desc
               {"It was probably used to haul rocks during the
               excavation of the original Hugo.  You could probably
               get in it."}
       contains_desc
               {"The old mine car is loaded with";}
       before
       {
               object DoClimb
                       {Perform(&DoEnter, self)}
               object DoLookUnder
               {
                       ! The big rock initially begins the game in nothing;
                       ! looking under the mine car moves it inside the
                       ! vault.

                       if bigrock not in nothing
                               "You don't find anything else."
                       else
                       {
                               "You find a big rock lodged between the
                               wheels, which you manage to wrestle out of
                               the way."
                               move bigrock to insidevault
                       }
               }
       }
       after
       {
               object DoEnter
               {
                       pencil is known
                       return false
               }
       }
       capacity 100
       holding 0
       reach minecar                   ! can't reach things outside the car
       is container, open, static

       ! Because the mine car has the quiet attribute set, its contents
       ! (i.e. the pencil) are not immediately obvious--they are not
       ! listed by WhatsIn until the player specifically looks inside.

       is quiet

       ! Also, it is mobile and therefore may be pulled by the rope.

       is mobile
       attach_immobile                 ! returns false if the car is mobile
       {
               if bigrock in nothing
                       "Something seems to be stopping the mine car
                       from rolling."
               else:  return false
       }
}

object bigrock "big rock"
{
       nouns "rock", "stone"
       adjectives "big", "large", "huge"
       article "a"
       after
       {
               object DoGet
                       {"Oof.  It's a struggle, but you manage to
                       pick it up."}
       }
       size 50
}

!----------------------------------------------------------------------------
! THE OBJECT ROOM
!----------------------------------------------------------------------------
room objectroom "Object Room"
{
       article "the"
       prep "in"
       s_to insidevault
       out_to insidevault
       long_desc
       {
               "This room contains a collection of objects with different
               properties, attributes, and associated routines in order
               to give some idea of basic object design.  In addition to
               the various furnishings, you notice a dartboard hanging on
               one wall."
       }
       vehicle_path minecar
       is not light
}

! chair
!
! Try sitting in it.

object chair "wooden chair"
{
       in objectroom
       noun "chair"
       adjective "wooden"
       article "a"
       reach cardtable         ! i.e. only the chair and the card table
                               ! may be reached from the chair
       is enterable, static
}


! cardtable
!
! Try sitting on it.  (You can't--it's not enterable.)  But it can hold
! things on its surface.

object cardtable "card table"
{
       in objectroom
       nouns "table", "cardtable"
       adjective "card"
       article "a"
       capacity 50
       holding 0
       is platform, static
}


! deckofcards and playingcard
!
! A rather unimpressive example of how to extract a single object from
! a group of similar objects.  Pick a card, any card.

object deckofcards "playing cards"
{
       in cardtable
       noun "cards"
       adjective "deck", "playing"
       article "some"
       initial_desc
               {"A deck of playing cards has been placed appropriately
               on the table."}
       size 10
       is plural
}

object card "playing card"
{
       found_in deckofcards
       noun "card" , "diamonds"
       adjective "playing", "nine"
       article "a"
       size 5
       long_desc {"It's the nine of diamonds."}
       after
       {
               object DoGet
               {
                       if object.found_in ~= false
                       {
                               object.found_in = false
                               "You deal the nine of diamonds."
                               object.name = "nine of diamonds"
                               object.article = "the"
                       }
                       else
                               return false
               }
       }
}


! goldcoins
!
! A simple demonstration of identical_class from OBJLIB.H.  The coins can
! be referred to individually, by number (i.e. "two coins"), or as a
! group ("the coins").

identical_class goldcoins "shiny gold coins"
{
       article "some"
       nouns "coins"
       adjectives "shiny", "gold"
       single_noun "coin"
       long_desc
               "Shiny and gold:  both admirable qualities in a coin."
       plural_of coin1, coin2, coin3
}

object coin1 "shiny gold coin"
{
       in cardtable
       article "a"
       noun "coin"
       adjectives "shiny", "gold"
       identical_to goldcoins
}

coin1 coin2 "shiny gold coin"           ! copy coin1 to coin2
{
       in cardtable
}

coin1 coin3 "shiny gold coin"
{
       in cardtable
}


! mittens
!
! Try wearing them.  Try writing when you're wearing them.

object mittens "pair of mittens"
{
       in transparentbox
       nouns "mitten", "mittens"
       adjective "pair"
       article "a"
       size 10
       initial_desc
               {"A pair of mittens is inside the transparent box."}
       is clothing
}


! box
!
! The basic box class is used by transparentbox and opaquebox.  The boxes
! plural_class (from OBJLIB.H) exists only to allow the boxes to be referred
! to as a group.

plural_class boxes "boxes"
{
       article "some"
       noun "boxes"
       single_noun "box"
       plural_of transparentbox, opaquebox
}

class box "box"
{
       noun "box"
       article "a"
       size 20
       capacity 20
       holding 0
       long_desc
       {
               if self is open
                       "It's open."
               else
                       "It's closed."
       }
       after
       {
               ! This after routine replaces the normal library "Taken."
               ! response whenever a box object is the parent of the
               ! taken object.

               parent(object) DoGet
               {
                       print "You take "; The(object); " out of "; \
                       The(self); "."
               }
       }
       plural_is boxes
       is openable, not open, container
}


! transparentbox
!
! Try getting something out of it when it's closed, even if you can see
! the contents.  Then try putting the flashlight in here and closing it.

box transparentbox "transparent box"
{
       in objectroom
       adjective "transparent", "clear"
       is transparent
}


! opaquebox
!
! Now try putting the flashlight in here and closing it.  The library does
! all the work of checking to see if the DoClose verb routine hides the
! light source in the room.

box opaquebox "opaque box"
{
       in objectroom
       adjective "opaque"
       article "an"
}

box largedrum "large drum"
! the special attribute is set once it has been opened
{
       in objectroom
       nouns "drum", "can", "barrel"
       adjectives "large", "big", "larger"
       short_desc
       {
               "A large drum--not the musical kind--is here.  ";
               if warningnote is hidden
               {
                       "Attached to it is a warning note."
                       warningnote is known
                       warningnote is already_listed
               }
               print newline
       }
       long_desc
               {"It's one of those big barrels used for storing and shipping
               oil, chemicals, and other hazardous materials.  Hint."}
       before
       {
               object DoGet
                       {"It's much too heavy to take."}
       }
       after
       {
               object DoOpen
               {
                       ! if drum hasn't been opened the first time
                       if self is not special
                       {
                               "Ignoring all warnings to the contrary, you
                               open the drum.  Inside is another, smaller
                               drum, as well as a second warning note."
                               self is special
                               smalldrum is known
                               warningnote.name = "first warning note"
                       }
                       else
                               return false
               }
       }
}

plural_class notes "notes"
{
       nouns "notes", "paper"
       adjectives "warning", "pieces"
       single_noun "note"
       plural_of warningnote, secondnote
}

object warningnote "warning note"
{
       in objectroom
       nouns "note", "paper"
       adjectives "warning", "first", "piece"
       article "a"
       long_desc
               {"\"Do not open this drum.  Whatever you do, don't open
               this drum.  Do not.  Open.  This drum.\""}
       before
       {
               object DoGet
                       {self is not hidden
                       return false}
       }
       plural_is notes
       is readable, hidden
}

box smalldrum "smaller drum"
! the special attribute is set once the bomb has been found
{
       in largedrum
       nouns "drum", "can", "barrel"
       adjectives "small", "smaller", "little"
       long_desc
       {
               "It's a smaller version of the first drum";
               if secondnote is hidden
               {
                       " (with a second warning note attached, of course)";
                       secondnote is known
                       secondnote is already_listed
               }
               print "."
       }
       before
       {
               object DoGet
                       {"Small is a relative term here.  It's still too
                       big to pick up."}
       }
       after
       {
               object DoOpen
               {
                       if self is not special   ! if bomb hasn't been found
                       {
                               "You find a bomb.  What luck."
                               self is special
                               bomb is known
                               Activate(bomb_fuse, 10)
                               score = score + 10
                               rank = 2
                       }
                       else
                               return false
               }
       }
}

object secondnote "second warning note"
{
       in largedrum
       nouns "note", "paper"
       adjectives "warning", "second", "piece"
       article "a"
       long_desc
               {"\"You listen well.  But this time we mean it.  Don't open
               this drum.\""}
       before
       {
               object DoGet
               {
                       self is not hidden
                       return false
               }
       }
       plural_is notes
       is readable, hidden
}

object bomb "bomb"
{
       in smalldrum
       nouns "bomb"
       article "a"
       long_desc
               {"Just your typical, garden-variety bomb."}
}


! bomb_fuse
!
! This fuse begins running as soon as the player opens the small drum.
! It prints a message only when it is within earshot or view of the player,
! but keeps ticking regardless.

fuse bomb_fuse
{}

event bomb_fuse
{
       if bomb in player                       ! player is holding it
               {"\nThe bomb you're holding is ticking."
               event_flag = true}
       elseif FindObject(bomb, location)       ! bomb is visible in the room
               {"\nThe bomb is ticking."
               event_flag = true}
       elseif Contains(location, bomb)         ! bomb is otherwise in room
               {"\nYou hear a ticking noise."
               event_flag = true}

       if not self.tick                        ! when self.timer = 0
       {
               if Contains(location, bomb)     ! if in player's location
               {
                       "\nKABOOM!\n\n\
                       (Right next to the bomb was not, as they say, such
                       a great place to be as it went off.  You're dead now.)"

                       endflag = 2     ! when endflag is non-false, it
                                       ! immediately triggers the end of the
                                       ! game
               }
               else
               {
                       "\nYou hear a muffled kaboom."
                       event_flag = true
                       if bomb in insidevault
                       {
                               oakdoor is blown_open
                               oakdoor is not openable
                               oakdoor is not hidden
                               score = score + 10

                               ! The following activates the dwarf's
                               ! script with eleven steps; the DwarfDropBall
                               ! ensures that she drops whatever she was
                               ! holding before going anywhere.

                               setscript[script(dwarf,11)] = \
                                       &CharMove, s_obj,
                                       &CharMove, w_obj,
                                       &CharWait, nothing,
                                       &CharShakeHead, oakdoor,
                                       &CharWait, nothing,
                                       &CharMove, n_obj,
                                       &CharWait, nothing,
                                       &CharShakeHead, largedrum,
                                       &CharMove, s_obj,
                                       &CharMove, e_obj,
                                       &CharMove, n_obj
                               DwarfDropBall
                       }
                       remove bomb
                       Deactivate(bomb_fuse)
               }
       }
}


attribute written alias special         ! for the pad only
array writing[65]                       ! up to 64 characters of writing

! pad
!
! Try:  write "something" on paper.

object pad "pad of paper"
{
       in cardtable
       article "a"
       nouns "paper"
       adjective "pad", "regular", "writing"
       long_desc
       {
               "It's a regular pad of writing paper.  ";
               if self is written
               {
                       "Written on it is:  \"";
                       print StringPrint(writing); "\"."
               }
               else:  "It's blank."
               print newline
       }
       is readable
}

object pencil "pencil"
{
       in minecar
       article "a"
       noun "pencil"
       adjective "wooden"
       long_desc
               "Not just a wooden pencil, but a magical wooden pencil,
               which one might use, perhaps, to name a hitherto unnamed
               object."
       size 5
}


! unnamedobject
!
! The unnamed object can be given a name by the player--i.e. have a word
! written on it by which the object may be referred to--in order to
! demonstrate the DICT command.

object unnamedobject "unnamed object"
! the special attribute is set once the player has given it a name
{
       in objectroom
       article "an"
       noun "object"
       adjective "unnamed", "non-descript", "nondescript"
       misc 0                          ! will eventually contain the non-
                                       ! case-altered version of the name
       initial_desc
               "Lying in the corner of the room is a non-descript,
               unnamed object."
       short_desc
               print "The "; self.name; " is here."
       long_desc
       {
               "Nothing special about it.  You can't even tell what it
               might be for.";
               if self is special
                       {"  Written on the side of it is:  \"";
                       print object.misc; "\".";}
               print newline
       }
       is openable, clothing, switchable
}

scenery dartboard "old dartboard"
{
       in objectroom
       article "a"
       noun "dartboard", "board"
       adjective "old", "dart"
       short_desc
               "Hanging on one wall is an old dartboard."
       is static
}


! dart
!
! The dart can be attached to the dartboard either by sticking it in or
! throwing it.  Since the attach_take property is true, the dart is released
! when attached and taken when detached.

attachable dart "green dart"
{
       in objectroom
       article "a"
       noun "dart"
       adjective "green"
       size 5
       attach_verb "stick", "throw"
       detach_verb "get"
       attach_prep "in"
       attached_desc "sticking out of"
       attach_take true
       attach_drop true
       attached_to dartboard           ! space for one attachment
       attachable_to dartboard
       before
       {
               object DoThrowAt
               {
                       if xobject is living
                               "Trying to start something, are we?"
                       else
                               Perform(&DoAttachObject, object, xobject)
               }
       }
}


! rope
!
! The rope is another attachable--but unlike the dart, because attach_take
! is not set to true, it may still be carried after being attached to another
! object.  Since the minecar has the mobile attribute set, it may be pulled
! around; the chair and cardtable, however, may not.

attachable rope "heavy rope"
{
       in objectroom
       article "a"
       nouns "rope", "twine"
       adjective "heavy", "thick"
       attach_verbs "tie", "attach"
       detach_verbs "untie", "detach"
       attached_to chair, 0            ! space for two attachments
       attachable_to chair, cardtable, minecar
}


!----------------------------------------------------------------------------
! THE CHARACTER ROOM AND THE BALL ROOM
!----------------------------------------------------------------------------
room characterroom "Character Room"
{
       noun "room"
       adjective "character"
       article "the"
       prep "in"
       w_to insidevault
       out_to insidevault
       n_to ballroom
       in_to ballroom
       long_desc
               {"The Character Room provides a couple of good examples of
               character scripts and events.  Exits are north and west."}
       vehicle_path minecar
}


! guard
!
! Ask him about things in the game.  Try:
!
!       ask guard about the minecar
!       guard, tell me about the minecar
!       guard, what about the minecar?
!
! Or, once you've begun talking to him, simply:
!
!       tell me about...
!       what about...

character guard "burly guard"
{
       in characterroom
       noun "guard"
       adjective "burly"
       article "a"
       long_desc
               {"He's wearing a button that reads:  \"Just ask me.\""}
       before
       {
               ! The guard is the object, since the question is asked as:
               ! "ask <object> about <xobject>".

               object DoAsk
               {
                       select xobject
                       case minecar
                               "\"You bring that in here, and you're asking
                               for trouble.\""
                       case ballroom
                               "\"Don't let me catch you taking none of them
                               there balls out of the Ball Room.\""
                       case bomb
                               "\"I don't know what kind of loopy nut
                               would want to be carting a bomb in here.\""
                       case dwarf
                               {"\"She's a short little one.  Kinda strange,
                               I have to say.  Spends all her time in there
                               just a-kickin' away.  I think she's mad
                               'cause she lost her magic wand.\""
                               wand is known}
                       case wand
                               "\"Wish I had one.\""
                       case oakdoor
                               "\"I have no idea how to get that thing
                               open.  The only way would be to blast it,
                               if you had something to blast it with...\""
                       case you
                               "The guard doesn't think too much of you."
                       case guard
                               "I wouldn't pry if I were you."
                       case else
                               return false
               }
       }
}


! This object-linked event is checked only when the guard is in the player's
! location.

event guard
{
       if minecar in location
       {
               "\nThe guard lifts his big boot up to the mine car and gives
               you a firm shove back out the door.  \"Not in that thing,
               you don't, pal!\""
               if player in minecar
               {
                       move minecar to insidevault
                       location = insidevault
                       PrintStatusLine
               }
               else
               {MovePlayer(insidevault)
               MoveAllAttachables(player, characterroom, insidevault, true)
               }
       }
       if Contains(player, bomb)
       {
               "\nThe guard grabs you and throws you back out the door.  \
               \"Get out of here with that bomb, pal!\"  An unsubtle
               approach, yes, but one that works."
               MovePlayer(insidevault)
       }
       if Contains(player, soccerball) or Contains(player, basketball)
       {
               "\nThe guard grabs you and throws you back out the door.  \
               \"Read the sign, pal!  They call it the Ball Room for a
               reason.  Keep 'em in there!\""
               MovePlayer(ballroom)
       }
}

room ballroom "Ball Room"
{
       noun "room", "ballroom"
       adjective "ball"
       article "the"
       prep "in"
       s_to characterroom
       out_to characterroom
}


! This event runs whenever the player is in the ballroom.

event ballroom                          ! the dwarf plays with the balls
{
       local a

       if dwarf in ballroom
       {
               a = random(6)           ! 1 to 6
               select a
                       case 1
                               DwarfGetBall(soccerball)
                       case 2
                               DwarfGetBall(basketball)
                       case 3, 4
                               DwarfDropBall
                       case else
                       {
                               if child(dwarf)
                               {
                                       "\nThe dwarf winds up and gives the ";
                                       print child(dwarf).name;
                                       " a kick.  It ricochets off the wall
                                       and bounces back to her."
                                       event_flag = true
                               }
                       }
       }
}

routine DwarfDropBall
{
       if child(dwarf)
       {
               "\nThe dwarf drops the ";
               print child(dwarf).name; "."
               move child(dwarf) to ballroom
               event_flag = true
       }
}

routine DwarfGetBall(obj)
{
       if obj in ballroom
       {
               DwarfDropBall
               move obj to dwarf
               "\nThe dwarf picks up the ";
               print obj.name; "."
               event_flag = true
       }
       else                            ! player must have ball obj
       {
               if obj = basketball     ! so try to choose the other ball
                       obj = soccerball
               else
                       obj = basketball

               if obj not in ballroom  ! player must have both balls
                       "\nThe dwarf looks at you impatiently and more than
                       a little accusingly, waiting for you to give her
                       back her balls."
       }
}

plural_class balls "balls"
{
       article "some"
       noun "balls"
       single_noun "ball"
       plural_of soccerball, basketball
}

object soccerball "checkered soccer ball"
{
       type balls                      ! for identification as a ball
       in ballroom
       nouns "ball", "soccerball"
       adjective "soccer", "checkered"
       article "a"
       before
       {
               object DoGet
               {
                       if self in dwarf        ! if she's holding it
                               {"The dwarf shakes a fist at you and
                               mutters, \"Get your own, kid.\""}
                       else
                               return false
               }
       }
       plural_is balls
}

soccerball basketball "orange basketball"       ! copy the other ball object
{
       in ballroom
       nouns "ball", "basketball"
       adjective "basket", "orange"
       article "an"
}

female_character dwarf "little dwarf"
{
       in ballroom
       noun "dwarf"
       adjective "little"
       article "a"
       order_response          ! i.e. "dwarf, (do something)", such as
       {                       ! "dwarf, kick ball"

               if verbroutine = &DoPunt
               {
                       if object.type ~= balls
                               {"The dwarf looks at you like you're nuts."
                               return true}
                       if object in player
                               {"(first giving the ball to her)"
                               if child(dwarf)
                                       move child(dwarf) to location
                               move object to dwarf}

                       if object not in dwarf
                               {"The dwarf shrugs.  \"I would, but I don't
                               have ";
                               print The(object); ".\""}
                       else
                               {"The dwarf winds up and gives the ";
                               print object.name;
                               " a kick.  It ricochets off the wall and
                               bounces back to her."}
               }
               else
                       return false
       }
       after
       {
               object DoAsk
               {
                       if xobject = wand
                               "\"I'd like to have it back.\""
                       else
                               return false
               }
               object DoTell
               {
                       if xobject = wand
                               "\"I'd like to have it back.\""
                       else
                               return false
               }

               ! In this case, the dwarf is the xobject, since the command
               ! is given as:  "show <object> to <xobject>".

               xobject DoShow
               {
                       if object = wand
                               "\"Give that to me!\""
                       else
                               return false
               }
               xobject DoGive
               {
                       if object = wand
                       {
                               "\"Thank you!  I've been looking for
                               that.\"  The dwarf takes the wand and bonks
                               you a little roughly on the head with it,
                               transporting you back to your nice, warm bed."
                               rank = 4
                               score = score + 10
                               endflag = 1
                       }
                       else
                               return false
               }
       }
}

routine CharShakeHead
{
       local char, obj
       if char in location
               print CThe(char); " shakes her head at "; The(obj); "."
}

!----------------------------------------------------------------------------
! BRICK ROOM
!----------------------------------------------------------------------------

! Special attribute for the oak door:
attribute blown_open alias special

object oakdoor "oak door"       ! a little more complicated door object
{
       in insidevault
       noun "door", "doorway"
       adjective "oak"
       article "an"
       short_desc
               {"Lying on the floor is the oak door."}
       door_to
       {
               if self is not blown_open
                       "The oak door is locked up tight as a drum."
               else
                       return brickroom
       }
       vehicle_path minecar

       ! Setting key_object to a non-zero value means the door is not
       ! openable without a key.  In this case, the ! key is
       ! technically object 1, which doesn't exist in the game.  So
       ! for all intents and purposes, the player can never unlock
       ! this door.  (It has to be blown open.)

       key_object 1

       is static, openable, not open, lockable, locked

       ! Since the door is hidden at the outset, its short_desc is
       ! not printed (until the door is blown open).

       is hidden
}

room brickroom "Brick Room"
{
       noun "room"
       adjective "brick"
       article "the"
       prep "in"
       long_desc
               {"This room is finished entirely in brick masonry.  Good,
               solid workmanship.  You can head back out to the northwest."}
       nw_to insidevault
       out_to insidevault
}

object trophy "shining golden trophy"
{
       in brickroom
       nouns "award", "trophy", "inscription"
       adjectives "shining", "golden"
       article "a"
       initial_desc
               {"A shining golden trophy--an award for your efforts--is
               here.  It bears an inscription."}
       long_desc
               {"Congratulations for solving this sample game's one and
               only major puzzle.  (Although it really wasn't that hard,
               was it?  And you probably don't deserve such a nice shining
               golden trophy.)"}
       after
       {
               object DoGet
               {
                       if parent(letter) = nothing
                               {"As you pick up the trophy, a magic wand
                               falls to the ground, and a small piece of
                               paper flutters down after it."
                               move wand to brickroom
                               move letter to brickroom
                               rank = 3}

                       else
                               return false
               }
       }
       is readable
}

object letter "handwritten letter"
{
       nouns "paper", "letter"
       adjective "handwritten", "piece"
       article "a"
       long_desc
               {"It's a letter from the author of this sample game.  Goes
               something like this:\n\n\"Give this to the dwarf to solve
               the game.\"  Nothing fancy, but I'm sure it was late
               when he was writing this."}
       is readable
}

object wand "magic wand"
{
       noun "wand"
       adjective "magic", "twinkling"
       article "a"
       short_desc {"A magic wand is twinkling on the floor here."}
       long_desc
               {"\"The official magic wand of social democrats
               everywhere.\""}
       before
       {
               object DoWave
               {
                       "You wave the magic wand, a cloud of orange mist
                       appears, and...\n\n...Aw, forget it.  I'm just
                       kidding.  What makes you think you know what to
                       do with a magic wand, anyway?"
               }
       }
}

!----------------------------------------------------------------------------
! NEW VERB ROUTINES
!----------------------------------------------------------------------------

routine DoPunt
{
       if object is living
               "Oh, good.  Real good.  Pick a fight, now.  That's really
               going to get you places."
       elseif object.type ~= balls
               "You won't get very far trying to kick that around."
       else
       {
               "You wind up and give ";
               The(object)
               " a good boot.  ";
               if dwarf in ballroom
                       "The dwarf nods approvingly."
               else
                       print newline
               move object to ballroom
               player.holding = player.holding - object.size
       }
       return true
}

routine DoWriteOn       ! response to an improperly phrased command
{
       if xobject and xobject ~= pencil
               {"You can't write with ";
               print The(xobject); "!"}
       elseif object ~= pad and object ~= unnamedobject
               {"There's not much point in defacing ";
               print The(object); "."}
       else
               "You'll have to be a little more specific about exactly
               what you'd like to write.  Try:  'write \"something\".'"
}

routine DoWrite
{
       local len

       if not xobject
       {
               if pencil not in player
                       {"You're not holding anything to write with."
                       return false}
               else
                       xobject = pencil
       }
       if not object
       {
               if FindObject(pad, location) ~= 1
                       {"Nothing to write on."
                       return false}
               else
                       object = pad
       }

       if xobject ~= pencil or (object ~= pad and object ~= unnamedobject)
               {DoWriteOn
               return}
       elseif mittens is worn
               "Good luck writing with those mittens on."
       elseif object = unnamedobject
               return Perform(&DoName, unnamedobject)
       else
       {
               if pad is written
                       {"You scratch out \"";
                       print StringPrint(writing); "\" and ";}
               else:  "You ";

               ! Read the engine parse$ into the writing[] array, to a
               ! maximum of 64 characters

               len = string(writing, parse$, 64)

               print word[1]; " \""; StringPrint(writing); "\"";
               " on the pad."
               pad is written
       }
       return true
}


! Notice that the DoName routine only allows the player to create one new
! entry in order to avoid overrunning MAXDICTEXTEND.

array name_array[50]

routine DoName
{
       if object is special
               {"You already named it ";
               The(object)
               "--don't go changing your mind now."}
       elseif pencil not in player
               "Would help if you were holding something to write that
               on the object, so you'll remember it."
       else
       {
               local i, len

               len = string(name_array, parse$, 49)    ! maximum 49 char.
               for (i=0; i<len; i=i+1)
               {
                       ! Because the parser cannot recognize multiple
                       ! words...
                       if name_array[i] = ' '          ! a space
                               {"Better keep it to one word."
                               return}

                       ! ...or non-alphanumeric characters (a table of
                       ! ASCII values will show why these are the
                       ! boundaries)

                       if name_array[i] < '0' or name_array[i] > 'z' or
                         (name_array[i] > '9' and name_array[i] < 'A') or
                         (name_array[i] > 'Z' and name_array[i] < 'a'):
                               {"Better to keep the fancy punctuation
                               out of it."
                               return}
               }

               "You write \"";
               StringPrint(name_array)
               "\" on the object."

               ! The misc property contains the non-case-corrected version
               ! of the name.

               object.misc = dict(name_array, 49)

               ! The name is converted to '"<string>" object':

               ! initial quote first...
               name_array[0] = '\"'

               ! then read parse$ into name_array (after the first quote)...
               len = string(name_array+1, parse$, 49)

               ! and append the last part to name_array...
               string(name_array+len+1, "\" object")

               ! ...before turning name_array into a dictionary entry
               object.name = dict(name_array, 49)

               ! Since the adjective will be referred to by the parser,
               ! it must be lowercase--name_array must also be reloaded
               ! with parse$ since it has been modified above.

               len = string(name_array, parse$, 49)
               for (i=0; i<len; i=i+1) ! the actual case-conversion loop
               {
                       if name_array[i] >= 'A' and name_array[i] <= 'Z'
                               name_array[i] = name_array[i] + ('a'-'A')
               }

               ! then write the word as a dictionary entry
               object.adjective #1 = dict(name_array, 49)

               object.article = "the"  ! i.e. 'the "<string>" object'
               object is special
               object is moved
       }
}

routine DoNameWhat
{
       "Try:  name object \"(something)\"."
}

!----------------------------------------------------------------------------
! REPLACE LIBRARY ROUTINES:
!----------------------------------------------------------------------------

global already_warned

replace DarkWarning
{
       if not already_warned           ! player is only warned once...
       {
               "It's pitch black in here.  Stumbling around in the dark
               isn't such a hot idea:  you're liable to be eaten by a grue."
               already_warned = true
       }
       else                            ! ...and gets three safe moves before
       {                               ! becoming a snack for a grue
               already_warned = already_warned + 1
               if already_warned > 4
                       {"You stumble around in the dark...and are eaten
                       by a grue!  Bad move.  Should've used a light."
                       endflag = 2}
               else
                       "You stumble around in the dark."
       }
}

! Below is the new PrintScore routine.  Note that it differs from the
! library routine in that it uses the new global rank to print the ranking.

replace PrintScore(end_of_game)
{
       "You ";
       if not end_of_game
               "have ";
       "scored a total of ";
       print number score; " out of "; number max_score;
       print ", giving you the rank of "; ranking[rank]; "."
}