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

Following is a fairly nifty telephone class for users of Hugo v.2.2 that
will allow you to implement any number of telephones in a game without
having to write a mountain of code for each one. I'm providing step-by-step
instructions, but they're pretty brief. You may find everything difficult
to understand at first. It's really not that difficult, considering what
a bitch telephones can be to code, but the best thing would probably be to
slap my code into a fresh SHELL.HUG file, change "emptyroom" to "apartment,"
take care of whatever other minor details need to be taken care of, and
then compile and play around with the thing. You won't hear any actual
conversations, of course, since you won't have written them yet, but you'll
at least have some idea what kind of beast you're dealing with when it comes
time to write them. Anyway, without further ado:

The first thing you need to do is type in some new verb definitions particular
to telephone usage:

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

verb "dial", "call"
       *                                               DoVague
       * object                                        DoDial

verb "answer"
       *                                               DoVague
       * object                                        DoAnswer

verb "hang"
       * "up"                                          DoHangup
       * "up" object                                   DoHangup

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

Then, before you forget, provide the default verbroutines corresponding to
the verbs you just defined. (If you're new to Hugo, or don't already have
some set place in your source where you like to put these, put 'em at the
end).

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

routine DoAnswer
{ "Sure. Ok, buddy. Whatever."
}

routine DoDial
{ "You can't dial that."
}

routine DoHangup
{ if phone_obj in location : Perform(&DoHangup, phone_obj)
 elseif not object : "There's nothing here to hang up."
 else : "You can't hang that up."
}

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

Next, back up toward the beginning of your code, type or paste in the
following new variables and attribute. (If you're not sure where to put
these, put 'em right after the lines that link in the Hugo library.)

Here's what these new critters are for:

"someone_on_line" is a variable intended to be used as a true/false
switch. In your own code, when you write your actual phone call events,
you will want to set this switch to true to signify that someone is actually
on the other end of the phone. If you fail to set this switch, when the
player answers or picks up the phone, he will be told that there's no one
there. Also, you will need to manually set it to false in the case where the
player stays on the line throughout the entire conversation so that the
other party finishes and hangs up first. In the case where the player hangs
up in the middle of a conversation, my code sets it to false automatically.

"phone_number" holds the object number of the phone number being dialed.
I've implemented telephone numbers as actual game objects, since that's so
much easier than trying to parse input strings of numbers and dashes. This
method has its drawbacks, but all in all it's not so bad. More about this
later.

"phone_obj" holds the object number of the particular telephone being used.
This is necessary because there is only one handset object, which must be
passed around from phone to phone as needed. We'll see how to do this
in a moment.

Finally, "off_hook" means just what it says: it indicates whether the
handset is currently on or off the telephone's hook. Generally speaking,
unless you really start fiddling with the phone class code, it's not one you
need to worry about. You will, however, want to check this attribute when
you do your "ring" events, since phones that are off the hook shouldn't ring
(and the call shouldn't come through at all).
NOTE: It is not possible with this code for a player to walk away and leave
a receiver off the hook. If a phone is not hung up (i.e. if it is off_hook),
it's because the player is standing there holding it.

---------------------------------------------------------------------------/!

global someone_on_line
global phone_number
global phone_obj
attribute off_hook

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

Ok. Remember how I just said you need to set "phone_obj" so that the
handset object gets moved around properly? How you do this will depend
upon your story. If you have more than one phone in a room, it'll be up
to you to figure it out. However, if you're not going to have more than a
single phone in any given room, put lines like the following in the main()
routine, so that your phones are checked and handled every turn (you
should end up with one "if" or "elseif" line for each location that has a
phone in it, with phone_obj set to the phone that's in it):

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

       if location = apartment
         phone_obj = red_phone
     ! elseif location = airport
     !   phone_obj = white_phone
     ! etc...

       move hook to phone_obj     ! don't change these three lines
       if receiver not in player
         move receiver to hook

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

Wow. Now you get to see the actual class definition. Aren't you excited?

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

class phone "telephone_class"
{
 is open, platform
 nouns "telephone", "phone"
 article "a"
 long_desc { "It's just an ordinary telephone. ";
             if self is off_hook
               "The receiver is off the hook."
             else : ""
           }
 before { object DoAnswer { if self is off_hook
                              "The phone is already off the hook."
                            elseif not someone_on_line
                            { self is off_hook
                              move receiver to player
                              receiver is not hidden
                              "You pick up the phone, but there's no
                               one on the line."
                            }
                            else
                            { self is off_hook
                              move receiver to player
                              receiver is not hidden
                              AnswerThePhone()
                            }
                          }
          object DoGet { if self is off_hook
                           "The phone is already off the hook."
                         elseif not someone_on_line
                         { self is off_hook
                           move receiver to player
                           receiver is not hidden
                           "You pick up the phone."
                         }
                         else
                           Perform(&DoAnswer, self)
                       }
          object DoListen { if self is not off_hook and someone_on_line
                              "The phone is ringing."
                            elseif self is not off_hook
                              "The phone is silent."
                            elseif someone_on_line
                              "The other party is speaking to you."
                            else
                              "You hear a dial tone."
                          }
          object DoHangup { if self is not off_hook
                              "The phone is already hung up."
                            else
                            { self is not off_hook
                              move receiver to hook
                              receiver is hidden
                              someone_on_line = false
                              "You hang up the phone."
                            }
                          }
          object DoDial { if self is not off_hook
                            "You'd better pick up the phone first."
                          elseif someone_on_line
                            "That would be rude."
                          else
                          { if phone_number = glorias_number   ! AN EXAMPLE
                              "You dial 555-1212."
                            else
                              "You dial randomly until an operator comes
                               on the line telling you to cut it out."
                          }
                        }
           xobject DoPutIn { if object = receiver
                               Perform(&DoPutIn, receiver, hook)
                             else : return false
                           }
           xobject DoGet { if object = receiver
                             Perform(&DoGet, receiver, hook)
                           else : return false
                         }
        }
}

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

Next come the receiver and hook. Note that the receiver is of the attachable
class. This will prevent the player from moving off to another location
while he's holding it. He'll also get a nice little inventory description
telling him that the receiver he's holding is attached to the telephone,
which impresses the hell out of people from Estonia.

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

attachable receiver "telephone receiver"
{ is hidden
 in_scope { if phone_obj in location : return player
            else : return 0
          }
 nouns "receiver", "handset"
 article "a"
 attached_to { return phone_obj }
 attached_desc "attached to"
 long_desc { if phone_obj is not off_hook: "The receiver is on the hook."
             else : "The receiver is off the hook."
           }
 before { object DoGet { Perform(&DoGet, phone_obj) }
          object DoDrop, DoHangup { Perform(&DoHangup, phone_obj) }
          object DoListen { Perform(&DoListen, phone_obj) }
        }
}

scenery hook "phone hook"
{ is open, platform
 nouns "hook", "cradle"
 article "the"
 long_desc { if phone_obj is not off_hook: "There's a receiver on the hook."
             else : "The hook is empty."
           }
 before { xobject DoPutIn { if object = receiver
                              Perform(&DoDrop, receiver)
                            else : "You can't put that on the hook."
                          }
          xobject DoGet { if object = receiver
                            Perform(&DoGet, receiver)
                          else : "That's not on the hook."
                        }
          object DoPush { if phone_obj is off_hook
                          { if someone_on_line
                            { someone_on_line = false
                              "You press the cradle, breaking the
                               connection."
                            }
                            else : "You press the cradle."
                          }
                          else : "The receiver is in the way."
                        }
        }
}

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

Finally, an actual telephone object which inherits from the phone class
defined above. If you want sixteen phones in your game just make sixteen
objects similar to this one and put 'em where you want 'em (remembering,
of course, to do the necessary housekeeping in the main() routine for each
one).

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

phone red_phone "red telephone"
{
 in apartment
 adjectives "red"
 short_desc { "A red telephone hangs beside your bed." }
}

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

The following has been broken out of the phone class before()
routine for convenience's sake. If you go back up and look, it is simply
called whenever a phone is successfully answered (i.e. when a phone is
picked up and there's someone on the line). How you code up all your
telephone conversations will depend upon the number and nature of them, so
I can't give any detailed guidance here, but in any case it will be
easier to keep track of everything if you don't try to do it in the
before() routine.

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

routine AnswerThePhone
{ "You answer the phone."
}

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

Lastly, phone numbers. Following is a rough example showing how to
implement them as game objects. Again, if you're into pain, feel free to
dump this approach and parse the input strings yourself. Oh? You're still
here? Well, then, throw this little guy into your code, compile it, and
run your game. Type "call <or dial> 555-1212 <or any of the other names>"
and you'll see quickly enough what you need to do to make it fit your
own story.

Remember the "phone_number" variable I talked about before? Look at DoDial
below and you'll see what it's good for. We want the phone to be checked
first to see if it can be dialed, so we're going to call the phone class'
DoDial routine where all that is done. But we also need to pass the phone
number (object). The simplest, least confusing way to "pass" the number in
this case is to use a global variable, and so that's the reason for
"phone_number". This method also gives us access to the number (object) at
any time we might need it in other routines, so all in all its not a bad
use of a global.

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

object glorias_number "Gloria's number"
{ is known
 in_scope { return player }
 nouns "555-1212", "5551212", "number"
 adjectives "gloria's"
 before { object DoDial { phone_number = self
                          Perform(&DoDial, phone_obj)
                        }
          object DoLook { "Gloria's number is 555-1212." }
          object { "You can't do that with Gloria's phone number." }
        }
}

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

That's it! Enjoy!

This document is provided as-is, with no warranty whatsoever express or
implied, by Cardinal Teulbachs, Archbishop of Frith. It is also copyright
(c) 1996.

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