!-------------------------------------------------------------------------
! gue.inf -- A component of the Inform Port of Ditch Day Drifter.
!
! The file contains the source code for the underground sections of the
! CalTech campus and the Great Undergraduate Excavation Project.
! -------------------------------------------------------------------------
! -------------------------------------------------------------------------
! 
! -- Table of Contents --
!
! HALLWAYS (3)
!   Hallway 1 (3.1)
!   Hallway 2 (3.2)
!   Hallway 3 (3.3)
!   Laundry Room (3.4)
!     washing machine (3.4.1)
!       blue jeans (3.4.1.1)
!         master key (3.4.1.1.1)
!   Hallway 4 (3.5)
!   Hallway 5 (3.6)
!   Hallway 6 (3.7)
!   Storage Room (3.8)
!     guard (3.8.1)
!      attributes, name, description, initial, act (3.8.1a)
!      greet, number, tied_to (3.8.1b)
!      react_before (3.8.1c)
!      react_after, orders (3.8.1d)
!      life (3.8.1e)
!      each_turn, before (3.8.1f)
!       memo pad (3.8.1.1)
!     card table (3.8.2)
!       empty glass (3.8.2.1)
!     tunnel door (3.8.3)
!
! STEAM TUNNELS (4)
!   tunnel pipes (4.*)
!
!  TunnelRoom class (I)
!  DarkTunnelRoom class (J)
!
!   Tunnel 1 (4.1)
!   Tunnel 2 (4.2)
!   Tunnel 3 (4.3)
!   Tunnel 4 (4.4)
!   Tunnel 5 (4.4)
!   Tunnel 6 (4.6)
!   Tunnel 7 (4.7)
!     tight passage (4.7.1)
!   Tunnel 8 (4.8)
!     control unit (4.8.1)
!       control keypad (4.8.1.1)
!       control display (4.8.1.2)
!       control button (4.8.1.3)
!   Tunnel 9 (4.9)
!   Tunnel 10 (4.10)
!   Tunnel 11 (4.11)
!     chute top (4.11.1)
!   Tunnel 12 (4.12)
!   Tunnel 13 (4.13)
!   Tunnel Storage (4.14)
!     rope (4.14.1)
!   Top of Pit (4.15)
!     pit top (4.15.1)
!     railing (4.15.2)
!   
! GREAT UNDERGRADUATE EXCAVATION (5)
!   Huge Cavern (5.1)
!     pit rope (5.1.1)
!     pit plaque (5.1.2)
!   Chute Room (5.2)
!     chute bottom (5.2.1)
!   Machine Room (5.3)
!     machine (5.3.1)
!       machine button (5.3.1.1)
!   Machine Storage (5.4)
!     Mr. Happy Gear (5.4.1)
!   Bank (5.5)
!   Vault Room (5.6)
!     safe (5.6.1)
!       deposit slot (5.6.1.1)
!       DarbCard (5.6.1.2)
!   Insurance Office (5.7)
!   Tunnel (5.8)
!   Subway Station 1 (5.9)
!     rail car (5.9.1)
!       coolant guage (5.9.1.1)
!       coolant hole (5.9.1.2)
!       ignition button (5.9.1.3)
!       rail car instructions (5.9.1.4)
!     tunnel mouth (5.9-11.2)
!   Rail Tunnel (5.10)
!   Subway Station 2 (5.11)
!   Computer Center (5.12)
!     computer equipment (5.12.1)
!     A Million Random Digits (5.12.2)
!   Bio Hall 1 (5.13)
!   Bio Lab (5.14)
!     strange equipment (5.14.1)
!     lab bench (5.14.2)
!       CloneMaster (5.14.2.1)
!         CloneMaster button (5.14.2.1.1)
!       funnel (5.14.2.2)
!     cabinet (5.14.3)
!
!  ChemItem class (K)
!
!       GF-XQ3 (5.14.3.1)
!       GF-XQ9 (5.14.3.2)
!       Poly Red (5.14.3.3)
!       Poly Blue (5.14.3.4)
!       Compound T99 (5.14.3.5)
!       Compount T30 (5.14.3.6)
!   Bio Hall 2 (5.15)
!     slime creature (5.15.1)
!       slime (5.15.1.1)
!   Bio Office (5.16)
!     bio desk (5.16.1)
!       The Great Seal of the Omega (5.16.1.1)
!   Spaceship Room (5.17)
!     spaceship (5.17.1)
!       warp motivator socket (5.17.1.1)
!   Spaceship Interior (5.18)
!     launch button (5.18.1)
!
! -------------------------------------------------------------------------

! (3) HALLWAYS

! (3.1) Hallway 1

Object Hall1 "Hallway"
 has light
 with 
  description 
    "You are at the west end of a basement hallway. A stairway leads up.",
  u_to Courtyard, e_to Hall2,
;

! (3.2) Hallway 2

Object Hall2 "Hallway"
 has light
 with 
  description 
    "You are in an east-west hallway in the basement. Another hallway goes
    off to the north.",
  w_to Hall1, e_to Hall3, n_to Hall4,
;

! (3.3) Hallway 3

Object Hall3 "Hallway"
 has light
 with 
  description 
    "You are at the east end of a hallway in the basement. A passage leads
    north.",
  w_to Hall2, n_to Laundry,
;

! (3.4) Laundry Room

Object Laundry "Laundry Room"
 has light
 with 
  description 
    "You are in the laundry room. There is a washing machine against one
    wall. The exit is to the south.",
  s_to Hall3, out_to Hall3,
;

! (3.4.1) washing machine

Object washing_machine "washing machine" Laundry
 has scenery container openable
 with 
  name 'washing-machine' 'washing' 'machine' 'laundry' 'washer',
  before [;
    SwitchOn, SwitchOff: "", (The) self, " seems to be out of order.";
  ],
;

! (3.4.1.1) blue jeans

Object jeans "blue jeans" washing_machine
 has pluralname
 with 
  ! name 'pockets' 'pocket' 'blue' 'jeans' 'pants' 'pair' 'of',
  parse_name [ 
    wd count;

    wd=NextWord();
    if (wd == 'pair') {
      wd=NextWord();
      if (wd == 'of') { 
        count=count+2; wd=NextWord(); 
      }
    }
    while (wd == 'pockets' or 'pocket' or 'blue' or 'jeans' or 'pants') {
      count++; wd=NextWord(); 
    }
    return count;
  ],
  article "a pair of",
  before [; 
     Examine, Search: 
       if (master_key has moved) "It's an ordinary pair of jeans.";
       print "It looks like an ordinary pair of jeans, though not your size. As
         you inspect them, you notice a key fall out of them";
       if (jeans in player || jeans in location) {
         move master_key to real_location;
         print " and to the ground.^";
       }
       else {
         move master_key to parent(self);
         if (parent(self) has container) print " into";
         else print " onto";
         print " the ", (name) parent(self), ".^";
       }
       if (guard in location) guard.act(master_key);
       rtrue;
     Wear: "They're not your size.";
     Receive:
       if (noun == master_key) "It is too late to put it back.";
       "That won't fit in the pocket.";
  ],
;

! (3.4.1.1.1) master key

! Unlocks the tunnel door.
Object master_key "master key"
 class Crawlable
 with 
  name 'master' 'key' 'master_key',

! -------------------------------------------------------------------------
! This before routine is pretty funny considering the number of sensible
! actions this game prevents you from doing.
! -------------------------------------------------------------------------
  before [; 
     Take: 
       if (self hasnt moved) {
         print "*Some* adventure games would try to impose their authors'
           misguided sense of ethics on you at this point, telling you
           that you don't feel like picking up the key, or you don't have
           time to do that, or that it's against the rules to even possess
           a master key, much less steal one from some other student's
           pants that you happened to find in a laundry, or even more
           likely that you are unable to take the key while wearing that
           dress. However, you're the player, and you're in charge around
           here, so I'll let you make your own judgments about what's
           ethical and proper here... ";
       }

! It "falls through" to the end of the before routine - it returns false
! and the normal Take action proceeds. Imbedded routines (routines
! contained in objects) return false by default, while non-imbedded
! routines (stand-alone routines) return true by default.
  ],
;

! (3.5) Hallway 4

Object Hall4 "Hallway"
 has light
 with 
  description "You are in a north-south hallway in the basement.",
  s_to Hall2, n_to Hall5,
;

! (3.6) Hallway 5

Object Hall5 "Hallway"
 has light
 with
  description 
    "You are at a corner in the basement hallway. You can go east or
    south.",
  s_to Hall4, e_to Hall6,
;

! (3.7) Hallway 6

Object Hall6 "Hallway"
 has light
 with 
  description 
    "You are at the east end of a basement hallway. To the north is a
    ~storage room,~ which everyone knows is actually an entrance to the
    steam tunnels.",
  w_to Hall5, n_to Storage,
;

! (3.8) Storage Room

Object Storage "Storage Room"
 has light ! general if Lloyd has visited.
 with 
  description [; 
     print "You are in a large storage room. There really hasn't been 
       anything stored here for a long time (at least, not anything that
       anybody wants to ever see again). The exit is to the south. To
       the north lies a door, which is ";
     if (tunnel_door has open) "open. ";
     else print "closed. ";
     "A small card table is sitting in front of the door.";
  ],
  s_to Hall6, n_to tunnel_door,
;

! (3.8.1) guard

Object guard "guard" Storage
! -------------------------------------------------------------------------
! The guard is transparent so you can see his memo pad.
! -------------------------------------------------------------------------
 ! (3.8.1a)
 has animate transparent ! general if he is asleep
 with 
  name 'caltech' 'cop' 'pig' 'fuzz' 'guard' 'security' 'man',
  description [; 
    print "The guard is a member of the CalTech Cops, the elite 
      corps of dedicated men and women that keeps the campus
      safe from undesirables, e.g., the students. ";
    if (self has general)
      "Currently, the guard is fast asleep, which is
      quite typical.";
    else "";
  ],
  initial [; 
    if (self hasnt general)
      "A guard is sitting at the card table in front of the door. He
      watches you carefully, evidently thinking that you might be
      planning to try to go through the door.";
    "A guard is slumped over a small card table in front of the steam
    tunnel entrance, evidently fast asleep. How typical.";
  ],
  act [ obj;
    switch (obj) {
      master_key:
        if (self hasnt general)
        move master_key to card_table;
        self.number=1;
        "^Spotting the key, the guard snatches it up and drops it on the
        card table. ~I've been wondering where that was!~ he snorts.";
      default:
        "^The guard doesn't know the security measures required under
        these circumstances."; 
    } 
  ],
  ! (3.8.1b)
  greet [;
    if (self has general)
      "The guard's sleeping form does not reply.";
    else {
      self.number=1;
      "~Hi,~ says the guard, with no enthusiasm.";
    }
  ],
  ! The number property will hold:
  !   1 - The guard has already done something interesting this turn.
  !   0 - The guard hasnt done anything interesting this turn.
  number 0,
  tied_to [;
    if (self has general) "That hardly seems necessary.";
    "The guard grins at you. ~You're that type, eh? Well, okay, maybe
    after my shift is over. Not! Now quit bothering me.~";
  ],
  ! (3.8.1c)
  react_before [; 
     ! The guard won't let players near the door to the tunnels.
     Enter, Open, Unlock:
       if (noun == tunnel_door && self hasnt general) {
         self.number=1;
         "The guard won't let you near the door.";
       }
     ! The guard prevents players from taking some things (unless he is
     ! asleep).
     Go:
       if (noun == n_obj && self hasnt general) {
         self.number=1;
         "The guard won't let you near the door.";
       }
     Take:
       if (noun == empty_glass && self hasnt general) {
         self.number=1;
         "The guard won't let you. ~Get your own,~ he says.";
       }
       if (noun == memo_pad && self has general)
         "The guard is passed out on top of his memo pad, so you can't
         budge it.";
       ! The guard only prevents players from taking the master key if he
       ! already found it and stuck it on the card table for safe keeping.
       if (master_key in card_table && 
           noun == master_key && self hasnt general) {
         self.number=1;
         "~This key is for authorized personnel only,~ says the guard,
         temporarily thwarting you.";
       }
     ! I think the memo pad makes a nice red herring.
     Push, Pull, Turn:
       if (noun == memo_pad && self has general)
         "The guard is passed out on top of the memo pad, so you can't
         move it.";
     Examine:
       if (noun == memo_pad && self has general)
         "The guard is passed out on top of his memo pad, so you can't
         see it.";
     ! The guard doesn't let players pour liquid nitrogen into his empty 
     ! glass.
     PourInto:
       if (second == empty_glass && 
           noun ofclass LiquidNitrogen && 
           self hasnt general)            {
         self.number=1;
         "The guard glowers at you until you desist.";
       }
     ! The guard will occasionally interpret the player placing things on
     ! the table to mean that the player intends to give the object to him.
     PutOn:
       if (self hasnt general && second == card_table && 
           noun == cup && toxicola in cup)
         <<Give cup self>>;
       if (self hasnt general && second == card_table && noun == master_key)
         <<Give master_key self>>;
     PourOnto:
       if (second == self && noun ofclass LiquidNitrogen) <<Attack self>>;
     Search:
       ! So the comatose guard appears to be slumped on the table.
       if (self has general && noun == card_table)
         print "The guard is slumped over the card table. ";
     Hello:
       return self.greet();
  ],
  ! (3.8.1d)
  ! If the player drops the master key in front of the guard, he may snatch
  ! it away.
  react_after [; 
     Drop:
       if (self hasnt general && noun == master_key) {
         print "You drop the master key on the floor.^";
         self.act(master_key);
         rtrue;
       }
  ],
  orders [;
    Hello:
      return self.greet();
    Give:
      switch(noun) {
        memo_pad:
         "~It's mine,~ he says, clutching the memo pad to his chest.";
        master_key:
          if (master_key notin card_table) "The guard looks up sharply, but 
            does not reply.";
          "~Since my job is to keep you out of the steam tunnels, I can't
          very well give you this key,~ says the guard.";
      }
    Unlock:
      if (noun == tunnel_door && second == master_key) {
        self.number=1;
        if (master_key in card_table)
          "He looks at you in disbelief. ~You must be joking! No students
          are allowed in the steam tunnels, including you.~";
        "~I'd love to help you,~ says the guard, ~but I've lost my key.~";
      }
  ],
  ! (3.8.1e)
  life [; 
     Give: 
       ! Players can't give things to a sleeping guard.
       if (self has general) "The guard appears to be fast asleep.";
       ! Players can give the master key back to the guard and it is
       ! stupid, though not fatal, to do so.
       if (noun == master_key) {
         self.number=1;
         move master_key to card_table;
         "The guard looks chagrined. ~I've been wondering where that thing
         was!~ he exclaims. ~I'll just leave it here on the table where it
         will be safe.~";
       }
       ! Bribing an NPC? Shocking!
       if (noun == one_dollar) {
         self.number=1;
         "The guard looks at you sternly. ~You should be ashamed of
         yourself -- trying to bribe a member of the elite CalTech Cops!~
         he admonishes you, refusing your offer.";
       }
       ! He doesn't want an empty coffee cup. He already has an empty
       ! glass, after all.
       if (noun~=cup || toxicola notin cup) {
         self.number=1;
         "The guard doesn't appear interested.";
       }
       ! An interesting exercise for the reader might be to allow the
       ! coffee to be poured into the empty glass, and having that work
       ! just as well.
       if (noun==cup) {
         give self general; ! The guard falls asleep.
         self.each_turn=NULL; ! Get rid of the guard's each_turn routine.
         remove toxicola;
         move cup to card_table; 
         score=score + 10;
         "The guard happily accepts your offer. ~ToxiCola(tm)! My
         favorite!~ he says appreciatively, not knowing the evil deed
         that you have in mind. He quickly drinks the entire cup of
         ToxiCola(tm). ~Wow! Just the caffeine pickup I needed,~ he
         says happily.^^After a few moments, though, he looks rather
         queasy. ~That caffeine just doesn't last long enough,~ he
         says, just before he passes out, slumping over the card
         table.";
       }
   WakeOther:
     if (self has general) "The guard is in a caffeine-deprivation induced
       stupor. He won't be waking up any time soon.";
   Attack:
     if (self has general) "You've done enough harm to the guard.";
     else "If you want to harm the guard, you'll need to be sneakier than
       that.";
   ThrowAt:
     if (noun == flask) <<Attack guard>>;
     if (((noun == cup && toxicola in cup) || noun == master_key) && 
         self hasnt general)                                         {
       print "The guard catches it out of the air. ";
       <<Give noun self>>;
     }
   Ask:
     if (self has general) rfalse;

     ! A crude way to parse out discussion topics.
     switch (second) {
       'key', 'master_key':
          if (master_key in card_table) "He puts his hand over the key 
            protectively. ~Try to put it out of your mind,~ he urges you.";
          else "The guard looks up sharply, but does not reply.";
       'caltech', 'cops', 'cop', 'himself', 'guard', 'guards':
          "~We're just your average, everyday, ordinary kind of Cops,~ he
          explains. ~Prick us, and we smack some whup-ass down on ya.~";
       'steam', 'tunnels', 'door', 'tunnel':
          "The guard sighs and says, ~Nobody's allowed in there...
          especially nosey Ditch Day revellers.~";
       'me', 'myself', 'students':
          "~College students can be really annoying,~ he
          says, glaring meaningfully in your direction.";
       'drink', 'toxicola', 'thirst', 'thirsty', 'thermos', 'empty', 'glass':
          "~I forgot my thermos,~ he says. ~And this stupid empty glass is
          making me thirsty.~";
       'memo', 'pad', 'notes':
          "~It's mine,~ he says, clutching the memo pad to his chest.";
       'ditch', 'day':
          "~I hate it. We're already over-worked, what with the Pope's
          visit next week.~";
       'pope', 'pope^s', 'visit':
          "~I'm hoping for some small dispensation.~";
       'jeans', 'pants':
          if (jeans in player) <<Show jeans self>>;
          "~Leave me out of your life's plan,~ says the guard.";
       default:
         "~I don't feel like discussing that right now.~";
     }
   Answer:
     if (noun == 'hello' or 'hi' or 'greetings' or 'salutations')
       return self.greet();
     self.number=1;
     "~I'll make a note of it,~ says the guard.";
   Show:
     self.number=1;
     switch(noun) {
       master_key:
         print "You show the master key to the guard.^";
         self.act(master_key); rtrue;
       jeans:
         "~Those are clearly not your size,~ says the guard. ~You college
         kids are always trying to get into each other's pants!~";
       default:
         "The guard ignores you and your ", (name) noun, "."; 
     }
  ],
  ! (3.8.1f)
  ! The guard's number property is used as a flag to prevent him from doing
  ! too many interesting things in one turn. If it is set to 1, he has
  ! already done something interesting this turn and the each_turn routine
  ! won't print anything.
  each_turn [; 
     if (self.number == 1) {
       self.number=0;
       return;
     }
     switch (random(5)) {
       1: "^The guard eyes you warily.";
       2: "^The guard looks at his empty glass, probably wishing he had 
          something to drink.";
       3: "^The guard flips purposefully through the pages of his memo 
          pad.";
       4: "^The guard writes something down on his memo pad, glancing up 
          from time to time to eye you suspiciously.";
       5: "^The guard picks up his empty glass and starts to drink, then 
          realizes it is empty and puts it back down.";
     }
  ],
  before [; 
     Push, Take, Turn:
       if (self has general) "The CalTech Cop is much too heavy for you to 
         move.";
       else "~Fat chance,~ says the guard.";
     LookUnder:
       if (self has general) "He's lying on his memo-pad.";
  ],
;

! (3.8.1.1) memo pad

Object memo_pad "guard's memo pad" guard
 with 
  name 'memo' 'pad' 'guard^s' 'corner',
  article "the",
  description "The guard won't let you see it.",
;

! (3.8.2) card table

Object card_table "card table" Storage
 has scenery supporter
 with 
  name 'card' 'table',
  description [;
    if (children(self) == 0) rfalse;
    ShowCont(self);
    new_line; rtrue;
  ],
;

! (3.8.2.1) empty glass

Object empty_glass "empty glass" card_table
 with 
  name 'empty' 'glass' 'emptiness',
  ! Some interpreters cannot successfully guess between 'an' and 'a' for an
  ! indirect article, so it is best to specify 'an' when it is necessary.
  article "an",
  description "You see nothing special about the empty glass (unless you
    you admire emptiness).",
  invent [; if (inventory_stage == 2) rtrue; ],
  poured_into "If you did that the empty glass wouldn't be empty any more.",
  react_before [;
    Insert, Transfer:
      if (second == self)
        "If you did that the empty glass wouldn't be empty any more.";
    Search:
      "It's empty.";
  ],
;

! (3.8.3) tunnel door

! A simple lockable two-way door.
Object tunnel_door "tunnel door"
 has door ~open scenery openable lockable locked
 with 
  name 'tunnel' 'door',
  with_key master_key,
  door_dir [; 
     if (location == Storage) return n_to;
     else return s_to;
  ],
  door_to [; 
     if (location == Storage) return Tunnel1;
     else return Storage;
  ],
  found_in Storage Tunnel1,
;

! (4) STEAM TUNNELS

! (4.*) tunnel pipes

! -------------------------------------------------------------------------
! This object is similar to the orange trees ["surface.inf":2.1-2.1]. It
! is a single object, which, through the found_in property, seems to be
! present in several locations. In addition, it uses a timer to print the
! random messages that appear from time to time in the steam tunnels, as
! well as provides something for players to manipulate.
! -------------------------------------------------------------------------
Object tunnel_pipes "pipes"
 has scenery pluralname
 with 
  name 'pipe' 'pipes',
  description
    "The pipes range from very small copper tubes, only an inch around, to huge
    asbestos-covered cylinders, over two feet in diameter. Many of the larger
    pipes are marked ~STEAM - 300 PSI.~",

  ! An object with a timer must provide a time_left property, and a time_out
  ! property. The time_left property, maintained by the library, holds the
  ! number of turns before the timer goes off. The time_out property will
  ! be called on the turn that the timer reaches 0.
  time_left 0,

  ! This will start the timer when players enter the steam tunnels.
  react_after [; 
    Go:
      if ((location == Tunnel1 && noun == n_obj or tunnel_door) ||
          (location == Tunnel13 && noun == s_obj))
        StartTimer(self, 0); 
  ],
  ! The time_out property is called when the timer runs out.
  time_out [; 
       new_line;
       ! This resets the timer to a random number between 1 and 5.
       ! This way, one of the messages below will appear randomly every 1
       ! to 5 turns.
       StartTimer(self, random(5));
       switch (random(5)) {
         1: "The rumbling sound suddenly becomes very loud, then, after a few
             moments, dies down to background levels again.";
         2: "A series of clanking noises, like marbles rolling through the
             steam pipes, starts in the distance, then comes closer and
             closer, until it seems to pass right overhead. It disappears into
             the distance.";
         3: "A very loud bang suddenly reverberates through the tunnel.";
         4: "One of the pipes starts to hiss wildly. After a few moments, it
             fades back into the background sounds.";
         5:  "A loud buzzing sound, like an overloaded electrical circuit,
             emanates from somewhere nearby. After a few moments it is gone.";
       }
  ],
  found_in [; 
     if (location ofclass TunnelRoom) rtrue;

     ! If you leave the steam tunnels, the messages stop appearing.
     else {
       StopTimer(self);
       rfalse;
     }
  ],
;

! (I) TunnelRoom class

Class TunnelRoom 
 has light 
 with 
  short_name "Steam Tunnel",
  before [;
    Listen: "There's a low rumbling sound.";
  ],
;

! (J) DarkTunnelRoom class

Class DarkTunnelRoom 
 class TunnelRoom 
 has ~light;

! (4.1) Tunnel 1

Object Tunnel1
 class TunnelRoom
 with 
  description 
    "You are in a steam tunnel. It is very hot and dry in here. The place
    has a strange musty odor; the air is very still, but there are distant
    sounds of all sorts that vibrate through the pipes. The pipes all seem
    to be hissing quietly, and a low rumbling sound constantly reverberates
    through the tunnel. Occasionally a distant clang or thud or crack
    emanates from the pipes.^^The steam tunnel runs east and west. A small
    passage leads south.",
  s_to tunnel_door, e_to Tunnel2, w_to Tunnel3,
;

! (4.2) Tunnel 2

Object Tunnel2
 class TunnelRoom
 with 
  description "You are at the east end of the steam tunnel.",
  w_to Tunnel1,
;
! (4.3) Tunnel 3

Object Tunnel3
 class TunnelRoom
 with 
  description "You are in an east-west section of the steam tunnels.",
  e_to Tunnel1, w_to Tunnel4,
;

! (4.4) Tunnel 4

Object Tunnel4
 class TunnelRoom
 with 
  description "You are at a T-intersection of two sections of steam tunnel;
    tunnels go off to the north, south, and east.",
  e_to Tunnel3, n_to Tunnel5, s_to Tunnel6,
;

! (4.5) Tunnel 5

Object Tunnel5
 class DarkTunnelRoom
 with 
  description "You are at a corner in the steam tunnel. You can go west and
    south.",
  w_to Tunnel7, s_to Tunnel4,
;

! (4.6) Tunnel 6

Object Tunnel6
 class TunnelRoom
 with 
  description "You are at a corner in the steam tunnel. You can go west and
    north.",
  w_to Tunnel8, n_to Tunnel4,
;

! (4.7) Tunnel 7

Object Tunnel7
 class DarkTunnelRoom
 with 
  description "You are in an east-west section of the steam tunnel. A very
    small passage between some steam pipes leads north, but it would be a
    tight squeeze.",
  e_to Tunnel5, w_to Tunnel9, ! n_to tight_passage,
  n_to [ just_checking;
    if (just_checking) return tight_passage;
    if (tight_passage.cant_crawl_through()) rtrue;
    else {
      tight_passage.crawl_message();
      return tight_passage;
    }
  ],
  before [; 
     Enter:
       if (noun == tight_passage) <<Go n_obj>>;
  ],
;

! (4.7.1) tight passage

Object tight_passage "tight passage"
 has scenery door open
 with
  name 'tight' 'passage' 'narrow' 'crawl' 'very' 'small',
  description "It's fairly tight, but it looks like you'll fit. Barely.",

  ! Checks the player's possessions and prints a helpful refusal and returns
  ! true if any of them are not crawlable. This routine is a global one since
  ! it must be called from both Tunnel7 and Tunnel12.
  cant_crawl_through [
    obj;

    objectloop (obj in player) {
      if (~~ obj ofclass Crawlable) "You'll never get through carrying ", 
        (a) obj, "."; ! rtrue
    }
    rfalse;
  ],
  crawl_message [;
    if (real_location == Tunnel7)
      print "You lay down on one of the pipes and start to snake through 
        the passage. For a moment, you think you're stuck, but you manage
        to wriggle your way through. You emerge on the north side of the
        narrow crawl.^";
    else 
      print "Going through the crawl southbound is just as difficult
        as it was coming north, you observe.^";
  ],
  door_dir [;
    if (real_location == Tunnel7) return n_to;
    else return s_to;
  ],
  door_to [;
    if (real_location == Tunnel7) return Tunnel12;
    else return Tunnel7;
  ],
  found_in Tunnel7 Tunnel12,
;

! (4.8) Tunnel 8

Object Tunnel8
 class TunnelRoom
 has general ! if the control for this room is on
 with 
  description [; 
     print "You are in an east-west section of the steam tunnel. On the
       wall is a control unit";
     if (self hasnt general) {
       print ". It is quite dark in this section of the tunnel; the only
         illumination is coming from the control unit's display";
       if (TestScope(flashlight) && flashlight has light)
       print " (and from the flashlight, of course)";
     }
     ".";
  ],
  e_to Tunnel6, w_to Tunnel10,
;

! (4.8.1) control unit

Object control_unit "control unit" Tunnel8
 has scenery
 with 
  name 'control' 'unit',
  description [; 
     print "The control unit is quite modern and high-tech looking, in
       stark contrast to the tunnels around it. It consists of a keypad
       (which allows entry of arbitrary numbers), a large green button
       and a display screen. The unit is labeled ~Station 2.~ ";
     return control_display.description();
  ],   
  ! Displayed on the screen, and entered using the keypad.
  number 322,
  ! To discover what object the control unit number refers to.
  objref [; 
     switch(self.number) {
       322: return Tunnel8;
       612: return mazeequip;
       293: return Tunnel9;
       default: return 0;
     }
  ],
;

! (4.8.1.1) control keypad

Object control_pad "keypad" Tunnel8
 has scenery
 with 
  name 'key' 'pad' 'keypad' 'cheesy' 'membrane',
  description
    "It's one of those cheesy membrane keypads like on a microwave
    oven or the new Enterprise's control panels. It allows you to type
    numbers made up of digits from 0 to 9.",
  typed_on [;
    ! inp1 is set to 1 if a number was entered by the player. If so, the
    ! number is stored in the 'noun' variable.
    if (inp1 ~= 1) "The keypad only allows entry of the digits 0-9.";

    ! Numbers higher than 999 have the highest order digit dropped since
    ! the display has only three places.
    if (noun > 999) noun=noun%1000;
    control_unit.number=noun;
    print "As you type the number sequence, the display screen is
      updated. ";
    return control_display.description();
  ],
  before [;
    LookUnder: "You can't do that without breaking it.";
  ],
;

! (4.8.1.2) control display
            
Object control_display "display screen" Tunnel8
 has scenery
 with 
  name 'screen' 'display',
  description [ 
    i j; 

    ! Get the control unit number and what it refers to.
    i=control_unit.number;
    j=control_unit.objref();
    print "The screen is currently displaying: ~";
    EmphasisStyleText(); ! ["misc.inf":12.6]
    ! Print leading zeroes if necessary.
    if (i <= 99) print "0";
    if (i <= 9) print "0";
    print i;
    NormalStyleText(); ! ["misc.inf":12.7]
    print " : ";
    EmphasisStyleText();
    ! If the control unit number refers to nothing print '???' instead of
    ! "ON" or "OFF".
    if (j ~= 0) {
      if (j has general) print "ON";
      else print "OFF";
    }
    else print "???";
    NormalStyleText();
    "~.";
  ],
  before [;
    LookUnder: "You can't do that without breaking it.";
  ],
;

! (4.8.1.3) control button

Object control_button "green button" Tunnel8
 has scenery
 with 
  name 'green' 'button',
  before [ 
    i; 

    Push:
      ! Pushing the button toggles the 'general' attribute of whichever
      ! object is referred to by the control unit number.
      !
      ! Tunnel8: Light control for Tunnel8.
      ! Tunnel9: Light control for the DarkTunnelRoom class.
      ! mazeequip: Toggles the 'confuse the maze' machine on and off.
      i=control_unit.objref();
      if (i ~= 0) {
        print "The display is updated as you press the button. ";
        ! general == ON, ~general == OFF.
        ! Toggle the general attribute.
        if (i has general) give i ~general;
        else give i general;
        control_display.description();
        if (i == Tunnel8) {
          print "^The lights in the tunnel ";
          if (i has general) "come on.";
          else {
            print "go out, leaving only the display screen's light ";
            if (TestScope(flashlight) && flashlight has light)
            print "(and the flashlight of course) ";
            "for illumination.";
          }
        }
        if (i == Tunnel9)
          ! Toggle the lights in all the dark tunnel rooms. You can't just
          ! say "give DarkTunnelRoom" general, since attributes of class
          ! objects are not dynamically inherited. Attributes are only
          ! inherited when a new instance of a class is created.
          objectloop(i ofclass DarkTunnelRoom)
            if (i has light) give i ~light;
            else give i light;
        rtrue;
      }
      else "The unit beeps. Nothing else appears to happen.";
    LookUnder:
      "Under the button is the control panel, which it is firmly attached to.";
  ],
;
          
! (4.9) Tunnel 9

Object Tunnel9
 class DarkTunnelRoom
 ! has general if the control unit reference 293 is ON. All the lights in 
 ! the DarkTunnelRoom class rooms are on if this room has general.
 with 
  description "You are at a corner in the steam tunnel. You can go east
    or south.",
  e_to Tunnel7, s_to Tunnel11,
;

! (4.10) Tunnel 10

Object Tunnel10
 class TunnelRoom
 with 
  description "You are at a corner in the steam tunnel. You can go east
    or north.",
  e_to Tunnel8, n_to Tunnel11,
;

! (4.11) Tunnel 11

Object Tunnel11
 class TunnelRoom
 with 
  description "You are in a north-south section of the steam tunnels. Set
    into one of the walls is a large chute.",
  n_to Tunnel9, s_to Tunnel10,
  before [; 
     Go:
       if (noun == w_obj or d_obj or in_obj) <<Enter chute>>;
  ],
;

! (4.11.1) chute top

Object -> chute "chute"
 has scenery container open
 with 
  name 'large' 'chute' 'top',
  description "The chute is large enough for anything you're carrying,
    but not nearly big enough for you. You can't tell where it goes except
    down.",
  poured_into [;
    switch (noun) {
      bottled_ln:
        remove bottled_ln;
        "You empty the bottle into the chute. The liquid nitrogen 
        evaporates into a fleeting cloud of steam.";
      original_ln:
        "You pour some liquid nitrogen into the chute, but the liquid 
         evaporates before it can flow very far down the chute.";
    }
  ],  
  before [; 
     Receive:
       move noun to ChuteRoom;
       print "You put ", (the) noun, " into the chute, and it slides away
         into the darkness";
       ! To prevent things like "a feather" from creating "a soft thud".
       if (~~ noun ofclass Crawlable) print ". After a few moments you hear a
         soft thud";
       ".";
     Search: <<Examine self>>;
     Enter:
       "The chute is too small for you.";
  ],
;

! (4.12) Tunnel 12

Object Tunnel12
 class TunnelRoom
 with 
  description [; 
     if (self has visited) "You are in an east-west section of the steam
       tunnels. A narrow passage between some steam pipes might allow you
       to go south.";
     else {
       "You are in another steam tunnel, but this one is substantially 
       different from the tunnels you have been in so far. This tunnel is
       much wider, less cluttered; it looks like it was built more recently
       than the south tunnels. The tunnel itself runs east and west, and
       passing back to the south is evidently possible, given your presence
       here.";
     }
  ],
  e_to Tunnel13, w_to PitTop, ! s_to tight_passage,
  s_to [ just_checking;
    if (just_checking) return tight_passage;
    if (tight_passage.cant_crawl_through()) rtrue;
    else {
      tight_passage.crawl_message();
      return tight_passage;
    }
  ], 
  before [; 
     Enter:
       if (noun == tight_passage) <<Go s_obj>>;
  ],
;

! (4.13) Tunnel 13

Object Tunnel13
 class TunnelRoom
 with 
  description "You are at the east end of a steam tunnel. A passage leads 
    north, and another leads south.",
  w_to Tunnel12, n_to OutsideMaze, s_to StorageRoom,
;

! (4.14) Tunnel Storage

Object StorageRoom "Storage Room"
 has light
 with 
  description
    "You are in a small storage room. The exit lies north.",
  n_to Tunnel13,
;

! (4.14.1) rope

! -------------------------------------------------------------------------
! The rope isn't very thoroughly implemented. It can only be tied to one
! thing in the entire game. After you have climbed down the rope it cannot
! even be untied again -- this hopefully helps mask its lack of
! interactivity.
! -------------------------------------------------------------------------
Object -> rope "rope"
 with 
  name 'rope' 'true', ! 'true' is for easier debugging.
  number 0,
  describe [; if (self.number ~= 0) rtrue; ],
  description [; 
     if (self.number ~= 0) "It's tied to ", (the) self.number, ".";
     "You see nothing special about the rope.";
  ],
  before [; 
     Tie:
       if (self.number ~= 0) "It's already tied to ", (the) second, ".";
     Take:
       if (self.number ~= 0) "You'll have to untie it first.";
     Climb:
       if (self.number == 0) "Climbing the rope, in its present configuration,
         would get you nowhere.";
       if (self.number == railing) {
         switch (location) {
           PitTop: <<Go d_obj>>;
           PitBottom: <<Go u_obj>>;
         }
       }
     ClimbDown:
       <<Climb self>>;
     ClimbUp:
       if (self.number == railing) "You can't climb up the rope from here."; 
       <<Climb self>>;
     Untie:
       if (self.number == 0) "The rope isn't tied to anything.";
       else {
         if (PitBottom has visited)
           "The knot has become too tight for you to untie.";
         print "You untie the rope and pick it up.^";
         self.number=0;
         SilentAction(##Take, self);
         rtrue;
       }
     Pull:
       if (self.number ~= 0)
         "You give the rope a firm pull. It appears to be safely attached.";
  ],
;

! (4.15) Top of Pit

Object PitTop
 class TunnelRoom
 with 
  short_name "Top of Pit",
  description [; 
     print "You are in a large open area in the steam tunnels. In the center
       of the room is a large pit, around which is a protective railing. A
       steam tunnel is to the east. ";
     if (rope.number == railing) print "A rope is tied to the railing and 
       extends down into the pit.";
     new_line;
     rtrue;
  ],
  d_to [ just_checking;
    if (just_checking) return PitBottom;
    if (rope.number ~= railing)
      "You'd probably break your neck if you tried that.";
    else {
      print "You climb down the rope...^";
      return PitBottom;
    }
  ],
  before [; 
     Jump:
       "You'd probably break your neck.";
     Climb:
       if (noun == d_obj) <<Go d_obj>>;
  ],
  e_to Tunnel12, ! d_to PitBottom
;

! (4.15.1) pit top

Object pit "pit" PitTop
 has scenery container open enterable
 with 
  name 'pit',
  description "The pit is large and deep.",
  poured_into [;
    if (noun == bottled_ln) {
      remove bottled_ln;
      print "You empty the bottle into the pit, but the liquid nitrogen
        evaporates";
    }
    else 
      print "You pour some liquid nitrogen into the pit, but it appears 
        to evaporate";
    " before it reaches the bottom.";
  ], 
  before [; 
     Receive:
       move noun to PitBottom;
       print_ret (The) noun, " rapidly falls out of sight.";
     Enter:
       <<Go d_obj>>;
     JumpInto:
       "Suicide isn't the answer.";
     JumpOver:
       "The pit is much too large and deep for that.";
     Take:
       "That doesn't seem likely.";
     Push, Pull, Turn:
       "A ~pit~ is really just nomenclature for the idea that signifies an 
       arbitrary sector of empty space. So you can't manipulate
       it.";
     LookUnder:
       "There's no such place.";
     Search:
       if (rope.number == railing) "There's a rope dangling down into the
       pit.";
       "The pit is quite deep and you can't see to the bottom.";
  ],
  put_under [;
    <<LookUnder self>>;
  ],
;

! (4.15.2) railing

Object railing "rail" PitTop
 has scenery
 with 
  name 'rail' 'railing',
  tied_to [;
    move rope to PitTop;
    rope.number=self;
    "You tie one end of the rope to the railing, and lower the other end
    into the pit. It appears to extend to the bottom of the pit.";
  ],
  before [; 
     JumpOver:
       "You'd probably break your neck.";
  ],
;

! (5) GREAT UNDERGRADUATE EXCAVATION

! (5.1) Huge Cavern

Object PitBottom "Huge Cavern"
 has light
 with 
  description
    "You are in a huge and obviously artificial cavern. The cave has
    apparently been dug out over a long period of time; some parts look very
    old, and other areas look comparatively recent. A small bronze plaque
    affixed to one of the older walls reads, ~Great Undergraduate Excavation
    - 1982.~ From high above, a small opening in the ceiling casts a dim glow
    over the vast chamber. A rope extends from the opening above. Passages
    of various ages lead north, south, east, west, southeast, and 
    southwest.",
  before [; 
     Climb:
       if (noun == u_obj) <<Go u_obj>>;
  ],
  u_to [ just_checking;
    if (just_checking) return PitTop;
    print "It's a long climb, but you somehow manage it.^";
    if (pit_rope in player) move pit_rope to PitBottom;
    return PitTop;
  ],
  w_to MachineShop, sw_to InsuranceOffice, ! u_to PitTop,
  n_to Cave, e_to BioHall1, se_to ChuteRoom, s_to Bank,
;

! (5.1.1) pit rope

Object pit_rope "rope" PitBottom
 has scenery
 with 
  name 'dangling' 'rope' 'substance',
  description "It's dangling down from the chamber above.",
  react_before [; 
     Go:
       if (pit_rope in player && noun == s_obj or e_obj or se_obj or n_obj or 
           sw_obj or w_obj) "You'll have to drop the rope first.";
  ],
  put_under [;
    <<Drop noun>>;
  ],
  before [; 
     Tie:
       "This end of the rope is coated with an experimental polymer
       that prevents you from making any knots.";
     Untie:
       "You can't untie it from down here.";
     Pull:
       "You pull the rope. It seems sturdy enough.";
     Insert, PutOn, Transfer:
       "You'll have to untie the rope first.";
     Climb:
       <<Go u_obj>>;
     ClimbDown: 
       "You can only climb up the rope from here.";
     ClimbUp: 
       <<Go u_obj>>;
     Take:
       move pit_rope to player;
       "You grab the rope.";
     LookUnder:
       print "Under the rope is... everything in this room.^";
       LookSub();
       rtrue;
  ],
;

! (5.1.2) pit plaque

Object pit_plaque "plaque" PitBottom
 has scenery
 with 
  name 'plaque' 'bronze',
  description
    "Great Undergraduate Excavation - 1982",
;

! (5.2) Chute Room

Object ChuteRoom "Chute Room"
 has light
 with 
  description "You are in a small room with exits to the northwest and 
    south. The bottom of a large chute opens into the room.",
  nw_to PitBottom, s_to ShipRoom,
  before [; 
     Go:
       if (noun == e_obj or in_obj or u_obj) <<Enter chute_bottom>>;
  ],
;

! (5.2.1) chute bottom

Object -> chute_bottom "chute"
 has scenery container open
 with 
  name 'chute' 'bottom',
  poured_into "This is the bottom of the chute; you can't pour things into it.",
  before [; 
     Receive:
       "This is the bottom of the chute; you can't put objects into it.";
     Search:
       "You can't quite see to the top of the chute.";
     Enter:
       "This is the bottom of the chute; you can't enter it. Besides, it's 
       too small for you.";
  ],
;

! (5.3) Machine Shop

Object MachineShop "Machine Shop"
 has light
 with 
  description
    "You are in the machine shop. It appears that this huge chamber was
    once used to build and maintain the equipment that was used to create
    the Great Undergraduate Excavation. Though most of the equipment is
    gone now, one very large and strange machine dominates the center of
    the room. The exit is east, and a narrow passage leads north.",
  e_to PitBottom, out_to PitBottom, n_to MachineStorage,
;

! (5.3.1) machine

Object -> machine "machine"
 has scenery
 with 
  name 'machine',
  description
    "The machine is unlike anything you've seen before. It's not at all clear
    what its purpose is. The only feature that looks like it might do
    anything useful is a large red button labeled ~DANGER!~",
;

! (5.3.1.1) machine button

Object -> machine_button "red button"
 has scenery
 with  
  name 'red' 'button',
  before [; 
     Push:
       print "As you push the button, the machine starts making horrible 
         noises and flinging huge metal rods in all directions. Enormous
         clouds of smoke rise from the machine as it flails about. After a
         few minutes of this behavior, you think to step back from the
         machine. You're not fast enough, though. Before you can escape it,
         a stray metal bar flings itself against your thumb, creating a
         sensation not unlike intense pain. ";
       if (lloyd in location) lloyd.act(machine);
       new_line;
       rtrue;
     LookUnder:
       "~DANGER!~";
  ],
;

! (5.4) Machine Storage
       
Object MachineStorage "Storage Closet"
 with 
  description
    "You are in a small storage closet off the machine shop. The exit is
    south.",
  s_to MachineShop, out_to MachineShop,
;

! (5.4.1) Mr. Happy Gear

Object -> happy_gear "gear"
 class Treasure
 with 
  name 'happy' 'mister' 'gear',
  description
    "It's an ordinary gear, about an inch in diameter. The only notable
    feature is that it has holes cut in such a manner that it looks like a
    happy face.",
;

! (5.5) Bank
   
Object Bank "Bank"
 has light
 with 
  description
    "You're in what was once the Great Undergraduate Excavation's bank. It
    doesn't appear to get much use any more. The exit is north, and a small
    passage leads south.",
  n_to PitBottom, s_to BankVault,
;

! (5.6) Vault Room

Object BankVault "Vault Room"
 has light
 with 
  description
    "The feature dominating this room is the bank's safe. The only exit is
    north.",
  n_to Bank,
;

! (5.6.1) safe

Object bank_safe "safe" BankVault
 has container ~open scenery ! general if it is blasted open
 with 
  name 'safe' 'vault' 'door',
  description [; 
     if (self has general) {
       print "The safe looks as though it has suffered some sort of 
         intense trauma lately; the door is just barely hanging on its
         hinges, leaving the contents of the safe quite exposed. ";
       ShowCont(self);
       new_line;
       rtrue;
     }
     else
       "The safe is huge, like the type you might find in a bank. The only
       notable features are a huge metal door (quite closed), and a large
       slot labeled ~Night Deposit slot.~";
  ],
  before [; 
     Open:
       if (self hasnt general)
         "You can't open such a secure safe without resorting to some sort
         of drastic action.";
       else
         "The safe is already open and likely to stay that way.";
     Close:
       if (self has general)
         "You close the safe but the door falls back open again.";
       else 
         "The safe is closed and likely to stay that way.";
     Receive:
       if (self hasnt open)
         "The safe is closed. You might try the slot.";
     LookUnder, Push, Pull, Take:
       "The huge safe is much too heavy.";
  ],
;

! (5.6.1.1) deposit slot

Object bank_slot "night deposit slot" BankVault
 has scenery container open
 with 
  name 'slot' 'night' 'deposit',
  description
    "The slot is very large, big enough to put a large sack of money into.
    Unfortunately, you won't have much luck extracting anything from the
    slot, since it has been carefully constructed to allow items to enter,
    but not to leave.",
  poured_into [;
    switch (noun) {
      bottled_ln:
        remove noun;
        print "You empty the bottle ";
      original_ln:
        print "You pour some liquid nitrogen ";
    }
    "into the slot. Shortly, a cloud of chilly steam emerges and floats away.";
  ],
  before [; 
     Receive:
       move noun to bank_safe;
       print (The) noun, " disappears into the deposit slot";
       if (bank_safe has open) " and pops out the other side, landing
         softly in the safe.";
       else ".";
     Search:
       if (bank_safe has open)
         "The slot designed in a cunning fashion so that items can only be 
         inserted from the outside.";
       else
         "You can't see anything in the slot.";
  ],
;
! (5.6.1.2) DarbCard

Object darbcard "card" bank_safe
 class Crawlable Treasure
 with 
  name 'darbcard' 'darb' 'card',
  description "You see nothing special about the DarbCard."
;

! (5.7) Insurance Office

Object InsuranceOffice "Insurance Office"
 has light
 with 
  description [; 
     print "You are in an insurance office. Like most insurance offices, the 
       area is rather nondescript. The exit is northeast.";
     if (lloyd.number == 0) lloyd.act(InsuranceOffice);
     new_line;
     rtrue;
  ],
  ne_to PitBottom, out_to PitBottom,
;

! (5.8) Tunnel

Object Cave "Tunnel"
 has light
 with 
  description
    "You're in a north-south tunnel. The tunnel slopes steeply downward to
    the north.",
  n_to SubwayStation1, d_to SubwayStation1, s_to PitBottom, u_to PitBottom,
;

! (5.9) Subway Station 1

Object SubwayStation1 "Subway Station"
 has light
 with 
  description
    "You're in a very large musty chamber deep underground. In the center of
    the room is a small rail car. Strangely, the car is sitting on the floor;
    there are no rails under the car, or, indeed, in the station at all. You
    look around, and notice about three meters up the east wall is a round
    tunnel. A passage leads south.",
  s_to Cave,
  before [; 
     Go: if (noun == e_obj) <<Enter tunnel_mouth>>;
  ],
;

! (5.9.1) rail car

Object railcar "rail car" SubwayStation1
 has scenery container open enterable ! general if it is broken
 with 
  name 'rail' 'car' 'railcar' 'rail-car',
  description [; 
     print "This is a small rail car, big enough for a couple of people.
       It has a small control panel, which consists of a green button,
       a gauge, and a small hole labeled ~Coolant.~ ";
     if (funnel in rail_hole)
       print "The hole seems to contain a funnel. ";
     rail_meter.description();

     ! Since the player can enter the car, I take care not to provide
     ! useless information, e.g., "In the car you can also see yourself."
     ! However, I wanted to make the 'note' as easy to find as possible, so
     ! the rail car divulges its contents upon examination, unless the only
     ! thing to see is the player. The CONCEALED_BIT is used for the
     ! WriteListFrom call to prevent the player from seeing himself, e.g.,
     ! "In the car you can see yourself and a small note."
     if ((children(self) && player notin self) || children(self) > 1) {
       print "^In the rail car you can also see ";
       WriteListFrom(child(self), 
         CONCEAL_BIT+ENGLISH_BIT+RECURSE_BIT+PARTINV_BIT);
       ".";
     }
  ],
  react_before [; 
     Exit:
       if (player notin self || rail_button hasnt general) rfalse;
       else 
         "Please wait until the rail car has come to a complete and final
         stop, and the captain has turned off the ~Fasten Seat Belt~ sign.
         (Actually, I made up the part about the ~Fasten Seat Belt~ sign,
         but you'll have to wait until the car has stopped nonetheless.";
  ],
  number 0,
  destination 0,
  daemon [; 
     if (location ~= RailTunnel) {
       

       ! The next three lines, which move the rail car, were copied from the
       ! part of the GoSub routine in "verblibm.h" that actually moves the
       ! player when it is in a vehicle. I couldn't use the PlayerTo
       ! routine here because there was no easy way to get the rail car to
       ! move along with the player using PlayerTo. MoveFloatingObjects()
       ! had to be called to make sure that the tunnel is correctly in
       ! place.

       ! move railcar to RailTunnel;
       ! location=RailTunnel;
       ! MoveFloatingObjects();

       PlayerTo(RailTunnel, 1);
       move railcar to RailTunnel;
       move player to railcar;

       "^The car rises to about three meters off the floor. It then starts
       to accelerate toward the tunnel, and plunges into the tunnel with a
       rush of air.";
     }
     else if (self.number > 0) {
       self.number--;
       "^The car races down the tunnel at terrifying speed.";
     }
     else {
       ! move railcar to self.destination;
       ! location=self.destination;
       ! MoveFloatingObjects();

       PlayerTo(self.destination, 1);
       move railcar to self.destination;
       move player to railcar;

       StopDaemon(self);
       give rail_button ~general;
       "^The car starts to decelerate sharply. After a few more seconds,
       it emerges into a station and glides to a halt. It slowly
       descends to the ground; once settled, the hum of its engine
       gradually disappears.";
     }
  ],

! -------------------------------------------------------------------------
! I'm using add_to_scope here so that the rail_hole, the rail_button, and
! the rail_meter will be part of the railcar. I can't make them children of
! the rail car because the rail car is a container. The parser would
! incorrectly assume that the meter, the hole, and the button were "in" the
! rail car.
! -------------------------------------------------------------------------
  add_to_scope rail_hole rail_meter rail_button,
;

! (5.9.1.1) coolant gauge
    
Object rail_meter "gauge"
 has scenery
 with 
  name 'gauge' 'guage' 'meter',
  description [; 
     print "The gauge is not labeled with any units you recognize, but the
       arc is divided into regions colored green, yellow, and red. The
       needle is currently in the ";
     if (rail_hole has general) print "green";
     else print "red";
     " section of the scale.";
  ],
  ! There's a bug in AttemptToTakeObject (verblibm.h) that causes an object
  ! zero error if you try to take an object with no parent (like this one).
  before [;
   Take: print_ret (The) self, " is firmly attached to the control panel."; 
  ],
;

! (5.9.1.2) coolant hole 

Object rail_hole "hole"
 has scenery container open ! general if filled with liquid nitrogen
 with 
  name 'hole' 'tank',
  description [; 
     if (funnel in self) "A funnel is in the hole.";
     if (self has general) "Wisps of water vapor rise from the hole.";
     "The hole is labeled ~Coolant.~ It's about an inch or so in diameter.";
  ],
  poured_into [;
    if (self has general) "The tank is already full.";
    switch (noun) {
      original_ln:
        if (funnel notin self)
          "The hole is too small; most if not all of the liquid nitrogen
          you pour spills all around, rather than into the hole.";
        else {
          give self general;
          "You carefully pour some liquid nitrogen into the funnel.
          It doesn't take very much before the tank is full.";
        }
      bottled_ln:
        give self general;
        remove bottled_ln;
        "You carefully pour the contents of the bottle into the hole.";
    }
  ], 
  before [; 
     Receive:
       if (noun == funnel) {
         move funnel to self;
         "A perfect fit.";
       }
       if (noun == bottlecap) "You could put it in there, but you could never
         get it back out again.";
       print_ret (The) noun, " won't fit in the hole.";
    Take: "It is very difficult to hold a hole.";
  ],
;

! (5.9.1.3) ignition button

Object rail_button "green button"
 has scenery ! general if it has been pushed and the car is still active
 with 
  name 'green' 'button' 'ignition',
  before [; 
     Push:
       ! An "if - else if - else" structure works like a switch statement,
       ! but it can have more complicated mutually exclusive dependencies
       ! than a regular switch statement. For a generic switch statement to
       ! be applicable, all the conditions must result from the state of
       ! one calculation, which sometimes isn't powerful enough.

       ! This is to help players who have entered this unwinnable state to
       ! see the error of their ways.
       if (railcar has general) {
         print "Nothing happens."; 

         ! A hint for the doomed...
         if (random_book in ComputerCenter)
           print " The rail car is toast, and so are your chances of 
             winning this game.";
         new_line; rtrue;
       }

       ! This is a little cop-out to avoid having to code the rail car
       ! moving by itself into the tunnel. It also helps avoid another
       ! unwinnable state.
       else if (player notin railcar) "It is hard to reach the button from
         outside the rail car.";

       ! A tiny little cop-out. What *should* the button do after the car
       ! has taken off?
       else if (self has general) "Nothing happens. Perhaps that is
         because you have already pushed the button quite recently.";
       else if (rail_hole has general) {
         ! Set the trip timer.
         railcar.number=3;
         ! Set the destination.
         if (location == SubwayStation1) railcar.destination=SubwayStation2;
         else railcar.destination=SubwayStation1;
         ! Set the daemon running.
         StartDaemon(railcar);
         ! Alert the button that it has been pushed and that it hasn't yet 
         ! reset.
         give self general;
         "A low-frequency hum sounds from within the rail car. After a few
         moments, the car starts to levitate off the track.";
       }
       else {
       ! How's this for an unwinnable state? It will inconvenience rash 
       ! button-pushers.
         give railcar general;
         "A low-frequency hum sounds from within the rail car. It grows
         in strength, and soon starts to vibrate the whole car. You smell
         the familiar odor of burning electronic components. Suddenly, a
         bright light flashes underneath the rail car, a cloud of thick
         black smoke rises, and the humming stops. It appears you have
         toasted the rail car.";
       }
    LookUnder: "A rail car. Yup. That's it.";
    Turn: "Um, you might try pushing it instead.";
    Take: print_ret (The) self, " is firmly attached to the control panel."; 
  ],
;

! (5.9.1.4) rail car instructions

Object small_note "small note" railcar
 class Crawlable
 with
  name 'small' 'note',
  description [;
    font off;
    print
    "   !!!! CalTach Floating Car Company !!!!^
    ^  Hello, Drifter!^
    ^  Instructions for use:
    ^^   Be sure to check your coolant level.
    ^   Push the ignition to initiate lift-off.^
    ^   Please keep your hands and other 
    ^   extremities in the vehicle at all times.^";
    font on;
    rtrue;
  ],
;

! (5.9-11.2) tunnel mouth

Object tunnel_mouth "tunnel"
 has scenery
 with 
  name 'round' 'tunnel',
  before [; 
     Enter:
       "The tunnel is too high up the wall. You won't be able to enter it
       without benefit of the rail car.";
     Search:
       "You aren't tall enough to see inside the tunnel.";
  ],
  ! Since the tunnel_mouth is not a container, it doesn't get benefit of
  ! the Receive fake action. Using a react_before routine avoids the bother
  ! of making the tunnel_mouth a container.
  react_before [; 
     Insert, PourInto, Transfer:
       if (second == self) "The tunnel is too high up the wall.";
  ],
  found_in SubwayStation1 SubwayStation2,
;

! (5.10) Rail Tunnel

Object RailTunnel "Tunnel"
 has light
 with description "The tunnel is rather nondescript.",
;

! (5.11) Subway Station 2

Object SubwayStation2 "Subway Station"
 has light
 with 
  description
    "You're in a subway station. About three meters up the west wall is a
    tunnel; a passage (at ground level) leads south. A rail car is sitting
    on the floor in the center of the room.",
  before [; 
     Go:
       if (noun == w_obj) <<Enter tunnel_mouth>>;
  ],
  s_to ComputerCenter,
;

! (5.12) Computer Center

Object ComputerCenter "Computer Center"
 has light
 with 
  description
    "You're in the computer room. Unfortunately, all the equipment here is
    hopelessly out of date and doesn't interest you in the least. The exit is
    north.",
  n_to SubwayStation2, out_to SubwayStation2,
;

! (5.12.1) computer equipment

Object -> computer_equipment "computer equipment"
 has scenery
 with 
  description
    "The equipment is all very outdated. It's not the least bit
    interesting.",
  article "some",
  ! This before routine rejects every action except Examine.
  before [; 
     Examine: rfalse;
     default: "The computer equipment isn't important.";
  ],
;

! (5.12.2) A Million Random Digits

Object -> random_book "book"
 class Treasure
 with 
  name 'book' 'million' 'random' 'digits',
  description
    "The book is entitled ~A Million Random Digits.~ In flipping through
    the book, you find that it is, in fact, a million random digits,
    nicely tabulated and individually numbered from 0 to 999,999 (computer
    people always start numbering at 0).",
;

! (5.13) Bio Hall 1

Object BioHall1 "Hall"
 has light
 with 
  description
    "You are in an east-west hallway. A passage labeled ~Bio Lab~ leads
    south.",
  w_to PitBottom, e_to BioHall2, s_to BioLab, in_to BioLab,
;

! (5.14) Bio Lab

Object BioLab "Bio Lab"
 has light
 with 
  description [; 
     print "You are in the Biology Lab. All sorts of strange equipment is
       scattered around the room. A lab bench is in the center of the room,
       and on one wall is a cabinet. ";
     if (cabinet has open) ShowCont(cabinet); ! ["misc.inf":12.4]
     "A passage leads north.";
  ],
  n_to BioHall1, out_to BioHall1,
;

! (5.14.1) strange equipment

Object strange_equipment "strange equipment" BioLab
 has scenery
 with 
  name 'strange' 'equipment',
  article "some",
  description "The equipment is entirely unfamiliar to you.",
  before [; 
     Examine: rfalse;
       default: "The strange equipment isn't important.";
  ],
;

! (5.14.2) lab bench

Object lab_bench "lab bench" BioLab
 has scenery supporter
 with 
  name 'bench' 'lab',
  description [; 
     print "The bench is topped with one of those strange black rubber
       surfaces that seemingly all scientific lab benches have. ";
     ShowCont(self); ! ["misc.inf":12.4]
     new_line; rtrue;
  ],
;

! (5.14.2.1) CloneMaster

Object clone_master "CloneMaster" lab_bench
 has container open
 with 
  name 'master' 'clone' 'clonemaster' 'clone-master' 'receptacle',
  description [; 
     print "The CloneMaster is a simple machine. It consists of a button
       marked ~Clone~ and a small receptacle. ";
     ShowCont(self); ! ["misc.inf":12.4]
     new_line; rtrue;
  ],
  before [;
    Receive:
      if (~~ noun ofclass Crawlable) "", (The) noun, " won't fit
        in the CloneMaster.";
  ],
  add_to_scope clone_button,
;

! (5.14.2.1.1) CloneMaster button

Object clone_button "clone button"
 with 
  name 'clone' 'button',
  before [; 
     Push:
       if (slime in clone_master) {
        
         remove slime;
         print "The CloneMaster clicks and whirs for several seconds. ";
         ! The components necessary to make a female slime creature are...
         if (gfxq3 in clone_master && 
             polyblue in clone_master &&
             compoundT99 in clone_master && 
             children(clone_master) == 3) {
           print "A monstrous female version (again, don't ask how you know
             it's female) leaps from the tiny machine";
           ! Note that the bio_creature is immobile, so this quick test
           ! will suffice to see if he is in scope.
           if (location == BioHall2) {
             remove bio_creature;
             ". The two monsters look at each other with passion in their
             mutant eyes. They run to each other with open arms, seemingly
             in slow motion. They embrace, engage in some mushy behavior,
             and then run away together to elope.";
           }
           else ", looks around, and, seeing nothing of interest, runs off.";
         }
         ! All other possible chemical combinations result in a male slime
         ! creature.
         else
           "An exact duplicate of the monstrous creature whose slime you
           placed in the CloneMaster leaps forth from the tiny machine. He
           looks at you menacingly for a moment, then runs off into the
           distance, never to be seen again.";
       }
       else "Nothing happens.";
     Take:
       "The button is a part of the CloneMaster.";
  ],
;

! (5.14.2.2) funnel

Object funnel "funnel" lab_bench
 with 
  name 'funnel', 
  react_before [;
    Insert, Transfer:
      if (second == self && 
          (~~ (noun ofclass LiquidNitrogen || noun == toxicola)))
        "The funnel is for liquids only.";
  ],
  poured_into [ 
    i;

    ! The funnel routs anything poured into it to its parent. Note that
    ! the only two liquids in this game are the cola and the liquid
    ! nitrogen. The cola can never be poured out of the cup, so the funnel
    ! doesn't need to concern itself with the cola.
    i=parent(self);
    if (i hasnt container) {
      if (noun == bottled_ln) remove noun;
      "The liquid nitrogen pours through the funnel, lands nowhere in 
      particular, and evaporates.";
    }
    else <<PourInto noun i>>;
  ], 
;

! (5.14.3) cabinet

Object cabinet "cabinet" BioLab
 has scenery container openable
 with name 'cabinet',
;

! (K) ChemItem class

Class ChemItem
 class Crawlable
 has proper
 with 
  ! The '//p' suffix in a dictionary word (a word in single quotes) denotes
  ! a word that is considered plural by the parser.
  name 'lump' 'lumps//p' 'label' 'goo' 'chemical' 'chemicals//p',
  ! The list_together property will list all objects with the same
  ! list_together property together in inventories and room listings.
  list_together "chemicals",
  description [; 
     "It's a small lump of goo. The only identification is a label reading
     ~", (name) self, ".~";
  ],
;

! (5.14.3.1) GF-XQ3

Object gfxq3 "GF-XQ3" cabinet
 class ChemItem
 with name 'genetic' 'factor' 'gf-xq3' 'gf' 'xq3',
;

! (5.14.3.2) GF-XQ9

Object gfxq9 "GF-XQ9" cabinet
 class ChemItem
 with name 'genetic' 'factor' 'gf-xq9' 'gf' 'xq9',
;

! (5.14.3.3) Poly Red

Object polyred "Poly Red" cabinet
 class ChemItem
 with name 'polymerase' 'poly' 'red',
;

! (5.14.3.4) Poly Blue

Object polyblue "Poly Blue" cabinet
 class ChemItem
 with name 'polymerase' 'poly' 'blue',
;

! (5.14.3.5) Compound T99

Object compoundT99 "Compound T99" cabinet
 class ChemItem
 with name 'compounds//p' 'compound' 'T99',
;

! (5.14.3.6) Compound T30

Object compoundT30 "Compound T30" cabinet
 class ChemItem
 with name 'compounds//p' 'compound' 'T30',
;

! (5.15) Bio Hall 2

Object BioHall2 "Hall"
 has light
 with 
  description
    "You are at the east end of an east-west hallway. A doorway leads east.",
  w_to BioHall1, e_to BioOffice, in_to BioOffice,
;

! (5.15.1) slime creature

Object -> bio_creature "creature"
 has animate
 with 
  ! This parse_name routine is intended to allow "creature" or "monster" to
  ! refer to the bio_creature, but "slime", "slimy", "leathery", can only be 
  ! prepositional modifiers. This will help differentiate the monster from
  ! the glob of slime that will shortly appear.
  !
  ! This is a good prototype of a common parse_name routine that implements,
  ! in a sense, adjectives and nouns. Adjectives must come first, and must
  ! be followed by at least one noun.
  parse_name [ 
    wd adj_count noun_count;

    wd=NextWord();
    while (wd == 'slime' or 'slimy' or 'slimey' or 'leathery' or 'green' or 
                 'bright') {
      wd=NextWord(); adj_count++; }
    while (wd == 'creature' or 'monster') {
      wd=NextWord(); noun_count++; }
    if (noun_count > 0) return adj_count + noun_count;
    else return 0;
  ],
  description
    "It looks like the result of a biological experiment that failed (or
    succeeded, depending on who performed the experiment).",
  describe
    "^An enormous creature is blocking the hallway to the east. He
    (please don't press for details as to how you know, but ~he~ is the
    appropriate pronoun here) appears to be part human, but exactly
    what part is not clear. The creature's leathery skin is a bright
    green and is largely covered with a thick translucent slime.",
  react_before [; 
     Go:
       if (noun == e_obj) {
         if (parent(slime) == 0) {
           move slime to player;
           give slime worn;
           "The creature grabs you and pushes you back, depositing a huge
           glob of slime on you in the process.";
         }
         else "The creature won't let you pass.";
       }
  ],
  each_turn [; 
     new_line;
     switch (random(5)) {
       1: "The creature roars a huge roar in your general direction.";
       2: "The creature menaces you.";
       3: "In a tender moment, the creature produces a magazine and opens up
           centerfold. He looks longingly at the picture. After a few
           moments, he notices you again, and puts away the magazine; as
           he's putting it away, you see that it's a copy of
           ~Playmutant.~";
       4: "The creature looks at you warily.";
       5: "The creature growls at you, showing his enormous pointy fangs.";
     }
  ],
;

! (5.15.1.1) slime

Object slime "glob of slime"
 class Crawlable
 ! The slime is clothing even though it isn't actually 'worn' in the
 ! typical sense. It is convenient to let the library routines take care of
 ! the 'worn' state of the slime.
 has clothing
 with 
  name 'glob' 'slime',
  ! It had to have a parse name routine to keep it distinguishable from the
  ! slime creature. It was also convenient to allow the word 'of' without
  ! having it appear in a name property.
  parse_name [ 
     wd;

     wd=NextWord();
     if (wd == 'slime') return 1;
     if (wd == 'glob') {
       if (NextWord() ~= 'of' && NextWord() ~= 'slime') return 1;
       else return 3;
     }
     return 0;
  ],
  before [; 
     Wear: "No, thank you.";
  ],
;

! (5.16) Bio Office

Object BioOffice "Bio Office"
 has light
 with 
  description
    "You are in the Biology Office. A large desk dominates the room. The
    exit is west.",
  w_to BioHall2, out_to BioHall2,
;

! (5.16.1) bio desk

Object -> bio_desk 
 class SimpleDesk
 with 
  name 'large',
;

! (5.16.1.1) The Great Seal of the Omega

Object ->-> omega "rubber stamp"
 class Treasure
 with 
  ! The phrase 'the great seal of the omega" is troublesome enough that I 
  ! used a parse_name routine. I wanted to avoid putting 'of' and
  ! 'the' into an item's name property.
  parse_name [ 
    wd count;
    
    wd=NextWord();
    while(wd == 'seal' or 'omega' or 'stamp' or 'great' or 
                'rubber' or 'approved' or 'treasure' or 'treasures') {
      if (wd == 'seal') {
        if (NextWord() == 'of') {
          count++;
          if (NextWord() == 'the') count++; else wn--;
        }
        else wn--;
      }
      if (wd == 'treasures') parser_action=##PluralFound;
      count++;
      wd=NextWord();
    }
    return count;
  ],
  description
    "The Great Seal is a large rubber stamp about an inch and a half square.
    The stamp consists of a large circle that is filled by a giant capital
    omega, under which is the word ~Approved.~ Around the outside of the
    circle, the words ~The Great Seal of the Omega~ are inscribed.",
;

! (5.17) Spaceship Room

Object ShipRoom "Spaceship Room"
 has light
 with 
  description
    "This is a very large cave dominated by a tall spaceship. High above, a
    vertical tunnel leads upward; it is evidently a launch tube for the
    spaceship. The exit is north.",
  n_to ChuteRoom, in_to ShipInterior,
  u_to "The tunnel is far too high above to climb.",
;

! (5.17.1) spaceship

Object -> space_ship "spaceship"
 has static
 with 
  name 'spaceship' 'space' 'ship' 'door' 'tall' 'gray' 'metal' 'cylinder',
  description [; 
     print "The spaceship is a tall gray metal cylinder with a pointed
       nosecone high above, and three large fins at the bottom. A large 
       socket ";
     if (motivator in ship_receptacle) print "on the side contains a warp
       motivator. ";
     else print "is on the side (the socket is currently empty). The
       socket is labeled ~insert warp motivator here.~ ";
     "^^You can enter the spaceship through an open door.";
  ],
  before [; 
    Enter:
       <<Go in_obj>>;
  ],
;

! (5.17.1.1) warp motivator socket

Object -> ship_receptacle "socket"
 has scenery container open
 with 
  name 'socket',
  before [; 
    Receive:
       if (noun == motivator) {
         move motivator to self;
         "It fits snugly.";
       }
       else "It doesn't fit.";
  ],
;

! (5.18) Ship Interior

Object ShipInterior "Spaceship"
 has light
 with 
  description
    "You are in the cockpit of the spaceship. The control panel is quite
    simple; the only feature that interests you at the moment is a button
    labeled ~Launch~.",
  out_to ShipRoom,
;

! (5.18.1) launch button

Object -> launch_button "launch button"
 has scenery
 with 
  name 'button' 'launch',
  before [; 
     Push:
       if (motivator in ship_receptacle) {
         print "The ship's engines start to come to life. ~Launch sequence
           engaged,~ the mechanical computer voice announces. ";
         if (lloyd in location) lloyd.act(launch_button);
         deadflag=2;
         score=score + 10;
         "^^The hatch closes automatically, sealing you into the space
         vessel.  The engines become louder and louder.  The computer voice
         announces, ~Launch in five... four... three... two... one...
         liftoff!~ The engines blast the ship into orbit.^^You realize that
         the time has come to set course for ~Deep Space Drifter,~ another
         fine TADS adventure, by Mike Roberts and Scott McAdams.";
       }
       "The ship's computer voice announces from a hidden speaker,
       ~Error: no warp motivator installed.~";
  ],
;