home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tads2os2.zip / ADV.T next >
Text File  |  1995-09-05  |  124KB  |  4,343 lines

  1. /* Copyright (c) 1988, 1994 by Michael J. Roberts.  All Rights Reserved. */
  2. /*
  3.    adv.t  - standard adventure definitions for TADS games
  4.    Version 2.2
  5.  
  6.    This file is part of TADS:  The Text Adventure Development System.
  7.    Please see the file LICENSE.DOC (which should be part of the TADS
  8.    distribution) for information on using this file, and for information
  9.    on reaching High Energy Software, the developers of TADS.
  10.  
  11.    This file defines the basic classes and functions used by most TADS
  12.    adventure games.  It is generally #include'd at the start of each game
  13.    source file.
  14. */
  15.  
  16. /* parse adv.t using normal TADS operators */
  17. #pragma C-
  18.  
  19. /*
  20.  *   Define compound prepositions.  Since prepositions that appear in
  21.  *   parsed sentences must be single words, we must define any logical
  22.  *   prepositions that consist of two or more words here.  Note that
  23.  *   only two words can be pasted together at once; to paste more, use
  24.  *   a second step.  For example,  'out from under' must be defined in
  25.  *   two steps:
  26.  *
  27.  *     compoundWord 'out' 'from' 'outfrom';
  28.  *     compoundWord 'outfrom' 'under' 'outfromunder';
  29.  *
  30.  *   Listed below are the compound prepositions that were built in to
  31.  *   version 1.0 of the TADS run-time.
  32.  */
  33. compoundWord 'on' 'to' 'onto';           /* on to --> onto */
  34. compoundWord 'in' 'to' 'into';           /* in to --> into */
  35. compoundWord 'in' 'between' 'inbetween'; /* and so forth */
  36. compoundWord 'down' 'in' 'downin';
  37. compoundWord 'down' 'on' 'downon';
  38. compoundWord 'up' 'on' 'upon';
  39. compoundWord 'out' 'of' 'outof';
  40. compoundWord 'off' 'of' 'offof';
  41. ;
  42.  
  43. /*
  44.  *   Format strings:  these associate keywords with properties.  When
  45.  *   a keyword appears in output between percent signs (%), the matching
  46.  *   property of the current command's actor is evaluated and substituted
  47.  *   for the keyword (and the percent signs).  For example, if you have:
  48.  *
  49.  *      formatstring 'you' fmtYou;
  50.  *
  51.  *   and the command being processed is:
  52.  *
  53.  *      fred, pick up the paper
  54.  *
  55.  *   and the "fred" actor has fmtYou = "he", and this string is output:
  56.  *
  57.  *      "%You% can't see that here."
  58.  *
  59.  *   Then the actual output is:  "He can't see that here."
  60.  *
  61.  *   The format strings are chosen to look like normal output (minus the
  62.  *   percent signs, of course) when the actor is Me.
  63.  */
  64. formatstring 'you' fmtYou;
  65. formatstring 'your' fmtYour;
  66. formatstring 'you\'re' fmtYoure;
  67. formatstring 'youm' fmtYoum;
  68. formatstring 'you\'ve' fmtYouve;
  69. formatstring 's' fmtS;
  70. formatstring 'es' fmtEs;
  71. formatstring 'have' fmtHave;
  72. formatstring 'do' fmtDo;
  73. formatstring 'are' fmtAre;
  74. formatstring 'me' fmtMe;
  75. ;
  76.  
  77. /*
  78.  *   Special Word List: This list defines the special words that the
  79.  *   parser needs for input commands.  If the list is not provided, the
  80.  *   parser uses the old defaults.  The list below is the same as the old
  81.  *   defaults.  Note - the words in this list must appear in the order
  82.  *   shown below.
  83.  */
  84. specialWords
  85.     'of',                        /* used in phrases such as "piece of paper" */
  86.     'and',             /* conjunction for noun lists or to separate commands */
  87.     'then',                              /* conjunction to separate commands */
  88.     'all' = 'everything',               /* refers to every accessible object */
  89.     'both',      /* used with plurals, or to answer disambiguation questions */
  90.     'but' = 'except',                      /* used to exclude items from ALL */
  91.     'one',                       /* used to answer questions:  "the red one" */
  92.     'ones',                        /* likewise for plurals:  "the blue ones" */
  93.     'it' = 'there',              /* refers to last single direct object used */
  94.     'them',                             /* refers to last direct object list */
  95.     'him',                       /* refers to last masculine actor mentioned */
  96.     'her',                        /* refers to last feminine actor mentioned */
  97.     'any' = 'either'         /* pick object arbitrarily from ambiguous list */
  98. ;
  99.  
  100. /*
  101.  *   Forward-declare functions.  This is not required in most cases,
  102.  *   but it doesn't hurt.  Providing these forward declarations ensures
  103.  *   that the compiler knows that we want these symbols to refer to
  104.  *   functions rather than objects.
  105.  */
  106. checkDoor: function;
  107. checkReach: function;
  108. itemcnt: function;
  109. isIndistinguishable: function;
  110. sayPrefixCount: function;
  111. listcont: function;
  112. listcontcont: function;
  113. turncount: function;
  114. addweight: function;
  115. addbulk: function;
  116. incscore: function;
  117. darkTravel: function;
  118. scoreRank: function;
  119. terminate: function;
  120. goToSleep: function;
  121. initSearch: function;
  122. reachableList: function;
  123. initRestart: function;
  124. ;
  125.  
  126. /*
  127.  *   initRestart - flag when a restart has occurred by setting a flag
  128.  *   in global.
  129.  */
  130. initRestart: function(parm)
  131. {
  132.     global.restarting := true;
  133. }
  134.  
  135. /*
  136.  *   checkDoor:  if the door d is open, this function silently returns
  137.  *   the room r.  Otherwise, print a message ("The door is closed.") and
  138.  *   return nil.
  139.  */
  140. checkDoor: function( d, r )
  141. {
  142.     if ( d.isopen ) return( r );
  143.     else
  144.     {
  145.     setit( d );
  146.     caps(); d.thedesc; " is closed. ";
  147.     return( nil );
  148.     }
  149. }
  150.  
  151. /*
  152.  *   checkReach: determines whether the object obj can be reached by
  153.  *   actor in location loc, using the verb v.  This routine returns true
  154.  *   if obj is a special object (numObj or strObj), if obj is in actor's
  155.  *   inventory or actor's location, or if it's in the 'reachable' list for
  156.  *   loc.  
  157.  */
  158. checkReach: function( loc, actor, v, obj )
  159. {
  160.     if ( obj=numObj or obj=strObj ) return;
  161.     if ( not ( actor.isCarrying( obj ) or obj.isIn( actor.location )))
  162.     {
  163.     if (find( loc.reachable, obj ) <> nil ) return;
  164.     "%You% can't reach "; obj.thedesc; " from "; loc.thedesc; ". ";
  165.     exit;
  166.     }
  167. }
  168.  
  169. /*
  170.  *  isIndistinguishable: function(obj1, obj2)
  171.  *
  172.  *  Returns true if the two objects are indistinguishable for the purposes
  173.  *  of listing.  The two objects are equivalent if they both have the
  174.  *  isEquivalent property set to true, they both have the same immediate
  175.  *  superclass, and their other listing properties match (in particular,
  176.  *  isworn and (islamp and islit) match for both objects).
  177.  */
  178. isIndistinguishable: function(obj1, obj2)
  179. {
  180.     return (firstsc(obj1) = firstsc(obj2)
  181.             and obj1.isworn = obj2.isworn
  182.             and ((obj1.islamp and obj1.islit)
  183.                  = (obj2.islamp and obj2.islit)));
  184. }
  185.  
  186.  
  187. /*
  188.  *  itemcnt: function( list )
  189.  *
  190.  *  Returns a count of the "listable" objects in list.  An
  191.  *  object is listable (that is, it shows up in a room's description)
  192.  *  if its isListed property is true.  This function is
  193.  *  useful for determining how many objects (if any) will be listed
  194.  *  in a room's description.  Indistinguishable items are counted as
  195.  *  a single item (two items are indistinguishable if they both have
  196.  *  the same immediate superclass, and their isEquivalent properties
  197.  *  are both true.
  198.  */
  199. itemcnt: function( list )
  200. {
  201.     local cnt, tot, i, obj, j;
  202.     tot := length(list);
  203.     cnt := 0;
  204.     i := 1;
  205.     for (i := 1, cnt := 0 ; i <= tot ; ++i)
  206.     {
  207.     /* only consider this item if it's to be listed */
  208.     obj := list[i];
  209.     if (obj.isListed)
  210.     {
  211.         /*
  212.          *   see if there are other equivalent items later in the
  213.          *   list - if so, don't count it (this ensures that each such
  214.          *   item is counted only once, since only the last such item
  215.          *   in the list will be counted) 
  216.          */
  217.         if (obj.isEquivalent)
  218.         {
  219.         local sc;
  220.         
  221.         sc := firstsc(obj);
  222.         for (j := i + 1 ; j <= tot ; ++j)
  223.         {
  224.             if (isIndistinguishable(obj, list[j]))
  225.             goto skip_this_item;
  226.         }
  227.         }
  228.         
  229.         /* count this item */
  230.         ++cnt;
  231.  
  232.     skip_this_item: ;
  233.     }
  234.     }
  235.     return cnt;
  236. }
  237.  
  238. /*
  239.  *  sayPrefixCount: function( cnt )
  240.  *
  241.  *  This function displays a count (suitable for use in listcont when
  242.  *  showing the number of equivalent items.  We display the count spelled out
  243.  *  if it's a small number, otherwise we just display the digits of the
  244.  *  number.
  245.  */
  246. sayPrefixCount: function(cnt)
  247. {
  248.     if (cnt <= 20)
  249.     say(['one' 'two' 'three' 'four' 'five'
  250.          'six' 'seven' 'eight' 'nine' 'ten'
  251.          'eleven' 'twelve' 'thirteen' 'fourteen' 'fifteen'
  252.          'sixteen' 'seventeen' 'eighteen' 'nineteen' 'twenty'][cnt]);
  253.     else
  254.     say(cnt);
  255. }
  256.  
  257. /*
  258.  *  listcont: function( obj )
  259.  *
  260.  *  This function displays the contents of an object, separated by
  261.  *  commas.  The thedesc properties of the contents are used.
  262.  *  It is up to the caller to provide the introduction to the list
  263.  *  (usually something to the effect of "The box contains" is
  264.  *  displayed before calling listcont) and finishing the
  265.  *  sentence (usually by displaying a period).  An object is listed
  266.  *  only if its isListed property is true.  If there are
  267.  *  multiple indistinguishable items in the list, the items are
  268.  *  listed only once (with the number of the items).
  269.  */
  270. listcont: function( obj )
  271. {
  272.     local i, count, tot, list, cur, disptot, prefix_count;
  273.  
  274.     list := obj.contents;
  275.     tot := length( list );
  276.     count := 0;
  277.     disptot := itemcnt( list );
  278.     for (i := 1 ; i <= tot ; ++i)
  279.     {
  280.         cur := list[i];
  281.         if ( cur.isListed )
  282.         {
  283.         /* presume there is only one such object */
  284.         prefix_count := 1;
  285.         
  286.         /*
  287.          *   if this is one of more than one equivalent items, list
  288.          *   it only if it's the first one, and show the number of
  289.          *   such items along with the first one 
  290.          */
  291.         if (cur.isEquivalent)
  292.         {
  293.         local before, after;
  294.         local j;
  295.         local sc;
  296.  
  297.         sc := firstsc(cur);
  298.         for (before := after := 0, j := 1 ; j <= tot ; ++j)
  299.         {
  300.             if (isIndistinguishable(cur, list[j]))
  301.             {
  302.             if (j < i)
  303.             {
  304.                 /*
  305.                  *   note that objects precede this one, and
  306.                  *   then look no further, since we're just
  307.                  *   going to skip this item anyway
  308.                  */
  309.                 ++before;
  310.                 break;
  311.             }
  312.             else
  313.                 ++after;
  314.             }
  315.         }
  316.  
  317.         /*
  318.          *   if there are multiple such objects, and this is the
  319.          *   first such object, list it with the count prefixed;
  320.          *   if there are multiple and this isn't the first one,
  321.          *   skip it; otherwise, go on as normal 
  322.          */
  323.         if (before = 0)
  324.             prefix_count := after;
  325.         else
  326.             continue;
  327.         }
  328.  
  329.             if ( count > 0 )
  330.             {
  331.                 if ( count+1 < disptot )
  332.                     ", ";
  333.                 else if (count = 1)
  334.                     " and ";
  335.                 else
  336.                     ", and ";
  337.             }
  338.  
  339.         /* list the object, along with the number of such items */
  340.         if (prefix_count = 1)
  341.         cur.adesc;
  342.         else
  343.         {
  344.         sayPrefixCount(prefix_count); " ";
  345.         cur.pluraldesc;
  346.         }
  347.  
  348.         /* show any additional information about the item */
  349.             if ( cur.isworn ) " (being worn)";
  350.             if ( cur.islamp and cur.islit ) " (providing light)";
  351.             count := count + 1;
  352.         }
  353.     }
  354. }
  355.  
  356. /*
  357.  *   showcontcont:  list the contents of the object, plus the contents of
  358.  *   an fixeditem's contained by the object.  A complete sentence is shown.
  359.  *   This is an internal routine used by listcontcont and listfixedcontcont.
  360.  */
  361. showcontcont: function( obj )
  362. {
  363.     if (itemcnt( obj.contents ))
  364.     {
  365.         if (obj.issurface)
  366.         {
  367.         if (obj.isqsurface)
  368.         {
  369.         "Sitting on "; obj.thedesc;" is "; listcont( obj );
  370.         ". ";
  371.         }
  372.         }
  373.         else if ( obj.contentsVisible and not obj.isqcontainer )
  374.         {
  375.             caps();
  376.             obj.thedesc; " seems to contain ";
  377.             listcont( obj );
  378.             ". ";
  379.         }
  380.     }
  381.     if ( obj.contentsVisible and not obj.isqcontainer )
  382.         listfixedcontcont( obj );
  383. }
  384.  
  385. /*
  386.  *  listfixedcontcont: function( obj )
  387.  *
  388.  *  List the contents of the contents of any fixeditem objects
  389.  *  in the contents list of the object obj.  This routine
  390.  *  makes sure that all objects that can be taken are listed somewhere
  391.  *  in a room's description.  This routine recurses down the contents
  392.  *  tree, following each branch until either something has been listed
  393.  *  or the branch ends without anything being listable.  This routine
  394.  *  displays a complete sentence, so no introductory or closing text
  395.  *  is needed.
  396.  */
  397. listfixedcontcont: function( obj )
  398. {
  399.     local list, i, tot, thisobj;
  400.  
  401.     list := obj.contents;
  402.     tot := length( list );
  403.     i := 1;
  404.     while ( i <= tot )
  405.     {
  406.         thisobj := list[i];
  407.         if ( thisobj.isfixed and thisobj.contentsVisible and
  408.       not thisobj.isqcontainer )
  409.             showcontcont( thisobj );
  410.     i := i + 1;
  411.     }
  412. }
  413.  
  414. /*
  415.  *  listcontcont: function( obj )
  416.  *
  417.  *  This function lists the contents of the contents of an object.
  418.  *  It displays full sentences, so no introductory or closing text
  419.  *  is required.  Any item in the contents list of the object
  420.  *  obj whose contentsVisible property is true has
  421.  *  its contents listed.  An Object whose isqcontainer or
  422.  *  isqsurface property is true will not have its
  423.  *  contents listed.
  424.  */
  425. listcontcont: function( obj )
  426. {
  427.     local list, i, tot;
  428.     list := obj.contents;
  429.     tot := length( list );
  430.     i := 1;
  431.     while ( i <= tot )
  432.     {
  433.         showcontcont( list[i] );
  434.     i := i + 1;
  435.     }
  436. }
  437.  
  438. /*
  439.  *  scoreStatus: function(points, turns)
  440.  *
  441.  *  This function updates the score on the status line.  This implementation
  442.  *  simply calls the built-in function setscore() with the same information.
  443.  *  The call to setscore() has been isolated in this function to make it
  444.  *  easier to replace with a customized version; to replace the status line
  445.  *  score display, simply replace this routine.
  446.  */
  447. scoreStatus: function(points, turns)
  448. {
  449.     setscore(points, turns);
  450. }
  451.  
  452. /*
  453.  *  turncount: function( parm )
  454.  *
  455.  *  This function can be used as a daemon (normally set up in the init
  456.  *  function) to update the turn counter after each turn.  This routine
  457.  *  increments global.turnsofar, and then calls setscore to
  458.  *  update the status line with the new turn count.
  459.  */
  460. turncount: function( parm )
  461. {
  462.     incturn();
  463.     global.turnsofar := global.turnsofar + 1;
  464.     scoreStatus( global.score, global.turnsofar );
  465. }
  466.  
  467. /*
  468.  *  addweight: function( list )
  469.  *
  470.  *  Adds the weights of the objects in list and returns the sum.
  471.  *  The weight of an object is given by its weight property.  This
  472.  *  routine includes the weights of all of the contents of each object,
  473.  *  and the weights of their contents, and so forth.
  474.  */
  475. addweight: function( l )
  476. {
  477.     local tot, i, c, totweight;
  478.  
  479.     tot := length( l );
  480.     i := 1;
  481.     totweight := 0;
  482.     while ( i <= tot )
  483.     {
  484.         c := l[i];
  485.         totweight := totweight + c.weight;
  486.         if (length( c.contents ))
  487.             totweight := totweight + addweight( c.contents );
  488.         i := i + 1;
  489.     }
  490.     return( totweight );
  491. }
  492.  
  493. /*
  494.  *  addbulk: function( list )
  495.  *
  496.  *  This function returns the sum of the bulks (given by the bulk
  497.  *  property) of each object in list.  The value returned includes
  498.  *  only the bulk of each object in the list, and not of the contents
  499.  *  of the objects, as it is assumed that an object does not change in
  500.  *  size when something is put inside it.  You can easily change this
  501.  *  assumption for special objects (such as a bag that stretches as
  502.  *  things are put inside) by writing an appropriate bulk method
  503.  *  for that object.
  504.  */
  505. addbulk: function( list )
  506. {
  507.     local i, tot, totbulk, rem, cur;
  508.  
  509.     tot := length( list );
  510.     i := 1;
  511.     totbulk := 0;
  512.     while( i <= tot )
  513.     {
  514.         cur := list[i];
  515.         if ( not cur.isworn )
  516.             totbulk := totbulk + cur.bulk;
  517.         i := i + 1;
  518.     }
  519.     return( totbulk );
  520. }
  521.  
  522. /*
  523.  *  incscore: function( amount )
  524.  *
  525.  *  Adds amount to the total score, and updates the status line
  526.  *  to reflect the new score.  The total score is kept in global.score.
  527.  *  Always use this routine rather than changing global.score
  528.  *  directly, since this routine ensures that the status line is
  529.  *  updated with the new value.
  530.  */
  531. incscore: function( amount )
  532. {
  533.     global.score := global.score + amount;
  534.     scoreStatus( global.score, global.turnsofar );
  535. }
  536.  
  537. /*
  538.  *  initSearch: function
  539.  *
  540.  *  Initializes the containers of objects with a searchLoc, underLoc,
  541.  *  and behindLoc by setting up searchCont, underCont, and
  542.  *  behindCont lists, respectively.  You should call this function once in
  543.  *  your preinit (or init, if you prefer) function to ensure that
  544.  *  the underable, behindable, and searchable objects are set up correctly.
  545.  *  
  546.  *  As a bonus, we take this opportunity to initialize global.floatingList
  547.  *  with a list of all objects of class floatingItem.  It is necessary to
  548.  *  initialize this list, so that validDoList and validIoList include objects
  549.  *  with variable location properties.  Note that, for this to work,
  550.  *  all objects with variable location properties must be declared
  551.  *  to be of class floatingItem.
  552.  */
  553. initSearch: function
  554. {
  555.     local o;
  556.     
  557.     o := firstobj(hiddenItem);
  558.     while (o <> nil)
  559.     {
  560.     if (o.searchLoc)
  561.         o.searchLoc.searchCont := o.searchLoc.searchCont + o;
  562.     else if (o.underLoc)
  563.         o.underLoc.underCont := o.underLoc.underCont + o;
  564.     else if (o.behindLoc)
  565.         o.behindLoc.behindCont := o.behindLoc.behindCont + o;
  566.     o := nextobj(o, hiddenItem);
  567.     }
  568.     
  569.     global.floatingList := [];
  570.     for (o := firstobj(floatingItem) ; o ; o := nextobj(o, floatingItem))
  571.     global.floatingList += o;
  572. }
  573.  
  574. /*
  575.  *  reachableList: function
  576.  *
  577.  *  Returns a list of all the objects reachable from a given object.
  578.  *  That is, if the object is open or is not an openable, it returns the
  579.  *  contents of the object, plus the reachableList result of each object;
  580.  *  if the object is closed, it returns an empty list.
  581.  */
  582. reachableList: function(obj)
  583. {
  584.     local ret := [];
  585.     local i, lst, len;
  586.     
  587.     if (not isclass(obj, openable)
  588.     or (isclass(obj, openable) and obj.isopen))
  589.     {
  590.     lst := obj.contents;
  591.     len := length(lst);
  592.     ret += lst;
  593.     for (i := 1 ; i <= len ; ++i)
  594.         ret += reachableList(lst[i]);
  595.     }
  596.  
  597.     return(ret);
  598. }
  599.  
  600. /*
  601.  *  visibleList: function
  602.  *
  603.  *  This function is similar to reachableList, but returns the
  604.  *  list of objects visible within a given object.
  605.  */
  606. visibleList: function(obj)
  607. {
  608.     local ret := [];
  609.     local i, lst, len;
  610.     
  611.     if (not isclass(obj, openable)
  612.     or (isclass(obj, openable) and obj.isopen)
  613.     or obj.contentsVisible)
  614.     {
  615.     lst := obj.contents;
  616.     len := length(lst);
  617.     ret += lst;
  618.     for (i := 1 ; i <= len ; ++i)
  619.         ret += visibleList(lst[i]);
  620.     }
  621.  
  622.     return(ret);
  623. }
  624.  
  625. /*
  626.  *  nestedroom: room
  627.  *
  628.  *  A special kind of room that is inside another room; chairs and
  629.  *  some types of vehicles, such as inflatable rafts, fall into this
  630.  *  category.  Note that a room can be within another room without
  631.  *  being a nestedroom, simply by setting its location property
  632.  *  to another room.  The nestedroom is different from an ordinary
  633.  *  room, though, in that it's an "open" room; that is, when inside it,
  634.  *  the actor is still really inside the enclosing room for purposes of
  635.  *  descriptions.  Hence, the player sees "Laboratory, in the chair."
  636.  *  In addition, a nestedroom is an object in its own right,
  637.  *  visible to the player; for example, a chair is an object in a
  638.  *  room in addition to being a room itself.  The statusPrep
  639.  *  property displays the preposition in the status description; by
  640.  *  default, it will be "in," but some subclasses and instances
  641.  *  will want to change this to a more appropriate preposition.
  642.  *  outOfPrep is used to report what happens when the player
  643.  *  gets out of the object:  it should be "out of" or "off of" as
  644.  *  appropriate to this object.
  645.  */
  646. class nestedroom: room
  647.     statusPrep = "in"
  648.     outOfPrep = "out of"
  649.     islit =
  650.     {
  651.         if ( self.location ) return( self.location.islit );
  652.         return( nil );
  653.     }
  654.     statusLine =
  655.     {
  656.     "<<self.location.sdesc>>, <<self.statusPrep>> <<self.thedesc>>\n\t";
  657.     }
  658.     lookAround( verbosity ) =
  659.     {
  660.         self.statusLine;
  661.     self.location.nrmLkAround( verbosity );
  662.     }
  663.     roomDrop( obj ) =
  664.     {
  665.         if ( self.location = nil or self.isdroploc ) pass roomDrop;
  666.     else self.location.roomDrop( obj );
  667.     }
  668. ;
  669.  
  670. /*
  671.  *  chairitem: fixeditem, nestedroom, surface
  672.  *
  673.  *  Acts like a chair:  actors can sit on the object.  While sitting
  674.  *  on the object, an actor can't go anywhere until standing up, and
  675.  *  can only reach objects that are on the chair and in the chair's
  676.  *  reachable list.  By default, nothing is in the reachable
  677.  *  list.  Note that there is no real distinction made between chairs
  678.  *  and beds, so you can sit or lie on either; the only difference is
  679.  *  the message displayed describing the situation.
  680.  */
  681. class chairitem: fixeditem, nestedroom, surface
  682.     reachable = ([] + self) // list of all containers reachable from here;
  683.                             //  normally, you can only reach carried items
  684.                             //  from a chair, but this makes special allowances
  685.     ischair = true          // it is a chair by default; for beds or other
  686.                             //  things you lie down on, make it false
  687.     outOfPrep = "out of"
  688.     roomAction( actor, v, dobj, prep, io ) =
  689.     {
  690.         if ( dobj<>nil and v<>inspectVerb )
  691.             checkReach( self, actor, v, dobj );
  692.         if ( io<>nil and v<>askVerb and v<>tellVerb )
  693.             checkReach( self, actor, v, io );
  694.     pass roomAction;
  695.     }
  696.     enterRoom( actor ) = {}
  697.     noexit =
  698.     {
  699.         "%You're% not going anywhere until %you%
  700.         get%s% <<outOfPrep>> <<thedesc>>. ";
  701.         return( nil );
  702.     }
  703.     verDoBoard( actor ) = { self.verDoSiton( actor ); }
  704.     doBoard( actor ) = { self.doSiton( actor ); }
  705.     verDoSiton( actor ) =
  706.     {
  707.         if ( actor.location = self )
  708.         {
  709.             "%You're% already on "; self.thedesc; "! ";
  710.         }
  711.     }
  712.     doSiton( actor ) =
  713.     {
  714.         "Okay, %you're% now sitting on "; self.thedesc; ". ";
  715.         actor.travelTo( self );
  716.     }
  717.     verDoLieon( actor ) =
  718.     {
  719.         self.verDoSiton( actor );
  720.     }
  721.     doLieon( actor ) =
  722.     {
  723.         self.doSiton( actor );
  724.     }
  725. ;
  726.  
  727. /*
  728.  *  beditem: chairitem
  729.  *
  730.  *  This object is the same as a chairitem, except that the player
  731.  *  is described as lying on, rather than sitting in, the object.
  732.  */
  733. class beditem: chairitem
  734.     ischair = nil
  735.     isbed = true
  736.     sdesc = "bed"
  737.     statusPrep = "on"
  738.     outOfPrep = "out of"
  739.     doLieon(actor) =
  740.     {
  741.         "Okay, %you're% now lying on <<self.thedesc>>.";
  742.     actor.travelTo(self);
  743.     }
  744. ;
  745.     
  746. /*
  747.  *  floatingItem: object
  748.  *
  749.  *  This class doesn't do anything apart from mark an object as having a
  750.  *  variable location property.  It is necessary to mark all such
  751.  *  items by making them a member of this class, so that the objects are
  752.  *  added to global.floatingList, which is necessary so that floating
  753.  *  objects are included in validDoList and validIoList values (see
  754.  *  the deepverb class for a description of these methods).
  755.  */
  756. class floatingItem: object
  757. ;
  758.  
  759. /*
  760.  *  thing: object
  761.  *
  762.  *  The basic class for objects in a game.  The property contents
  763.  *  is a list that specifies what is in the object; this property is
  764.  *  automatically set up by the system after the game is compiled to
  765.  *  contain a list of all objects that have this object as their
  766.  *  location property.  The contents property is kept
  767.  *  consistent with the location properties of referenced objects
  768.  *  by the moveInto method; always use moveInto rather than
  769.  *  directly setting a location property for this reason.  The
  770.  *  adesc method displays the name of the object with an indefinite
  771.  *  article; the default is to display "a" followed by the sdesc,
  772.  *  but objects that need a different indefinite article (such as "an"
  773.  *  or "some") should override this method.  Likewise, thedesc
  774.  *  displays the name with a definite article; by default, thedesc
  775.  *  displays "the" followed by the object's sdesc.  The sdesc
  776.  *  simply displays the object's name ("short description") without
  777.  *  any articles.  The ldesc is the long description, normally
  778.  *  displayed when the object is examined by the player; by default,
  779.  *  the ldesc displays "It looks like an ordinary sdesc."
  780.  *  The isIn(object) method returns true if the
  781.  *  object's location is the specified object or the object's
  782.  *  location is an object whose contentsVisible property is
  783.  *  true and that object's isIn(object) method is
  784.  *  true.  Note that if isIn is true, it doesn't
  785.  *  necessarily mean the object is reachable, because isIn is
  786.  *  true if the object is merely visible within the location.
  787.  *  The moveInto(object) method moves the object to be inside
  788.  *  the specified object.  To make an object disappear, move it
  789.  *  into nil.
  790.  */
  791. class thing: object
  792.     weight = 0
  793.     bulk = 1
  794.     isListed = true         // shows up in room/inventory listings
  795.     contents = []           // set up automatically by system - do not set
  796.     verGrab( obj ) = {}
  797.     Grab( obj ) = {}
  798.     adesc =
  799.     {
  800.         "a "; self.sdesc;   // default is "a <name>"; "self" is current object
  801.     }
  802.     pluraldesc =            // default is to add "s" to the sdesc
  803.     {
  804.     self.sdesc; "s";
  805.     }
  806.     thedesc =
  807.     {
  808.         "the "; self.sdesc; // default is "the <name>"
  809.     }
  810.     multisdesc = { self.sdesc; }
  811.     ldesc = { "It looks like an ordinary "; self.sdesc; " to %me%."; }
  812.     readdesc = { "%You% can't read "; self.adesc; ". "; }
  813.     actorAction( v, d, p, i ) =
  814.     {
  815.         "You have lost your mind. ";
  816.         exit;
  817.     }
  818.     contentsVisible = { return( true ); }
  819.     contentsReachable = { return( true ); }
  820.     isIn( obj ) =
  821.     {
  822.         local myloc;
  823.  
  824.         myloc := self.location;
  825.         if ( myloc )
  826.         {
  827.             if ( myloc = obj ) return( true );
  828.             if ( myloc.contentsVisible ) return( myloc.isIn( obj ));
  829.         }
  830.         return( nil );
  831.     }
  832.     moveInto( obj ) =
  833.     {
  834.         local loc;
  835.  
  836.     /*
  837.      *   For the object containing me, and its container, and so forth,
  838.      *   tell it via a Grab message that I'm going away.
  839.      */
  840.     loc := self.location;
  841.     while ( loc )
  842.     {
  843.         loc.Grab( self );
  844.         loc := loc.location;
  845.     }
  846.  
  847.         if ( self.location )
  848.             self.location.contents := self.location.contents - self;
  849.         self.location := obj;
  850.         if ( obj ) obj.contents := obj.contents + self;
  851.     }
  852.     verDoSave( actor ) =
  853.     {
  854.         "Please specify the name of the game to save in double quotes,
  855.         for example, SAVE \"GAME1\". ";
  856.     }
  857.     verDoRestore( actor ) =
  858.     {
  859.         "Please specify the name of the game to restore in double quotes,
  860.         for example, RESTORE \"GAME1\". ";
  861.     }
  862.     verDoScript( actor ) =
  863.     {
  864.         "You should type the name of a file to write the transcript to
  865.         in quotes, for example, SCRIPT \"LOG1\". ";
  866.     }
  867.     verDoSay( actor ) =
  868.     {
  869.         "You should say what you want to say in double quotes, for example,
  870.         SAY \"HELLO\". ";
  871.     }
  872.     verDoPush( actor ) =
  873.     {
  874.         "Pushing "; self.thedesc; " doesn't do anything. ";
  875.     }
  876.     verDoWear( actor ) =
  877.     {
  878.         "%You% can't wear "; self.thedesc; ". ";
  879.     }
  880.     verDoTake( actor ) =
  881.     {
  882.         if ( self.location = actor )
  883.         {
  884.             "%You% already %have% "; self.thedesc; "! ";
  885.         }
  886.         else self.verifyRemove( actor );
  887.     }
  888.     verifyRemove( actor ) =
  889.     {
  890.       /*
  891.      *   Check with each container to make sure that the container
  892.      *   doesn't object to the object's removal.
  893.      */
  894.         local loc;
  895.  
  896.         loc := self.location;
  897.         while ( loc )
  898.         {
  899.             if ( loc <> actor ) loc.verGrab( self );
  900.             loc := loc.location;
  901.         }
  902.     }
  903.     isVisible( vantage ) =
  904.     {
  905.         local loc;
  906.  
  907.         loc := self.location;
  908.         if ( loc = nil ) return( nil );
  909.  
  910.     /*
  911.      *   if the vantage is inside me, and my contents are visible,
  912.      *   I'm visible 
  913.      */
  914.     if (vantage.location = self and self.contentsVisible)
  915.         return true;
  916.  
  917.         /* if I'm in the vantage, I'm visible */
  918.         if ( loc = vantage ) return( true );
  919.  
  920.         /*
  921.          *   if its location's contents are visible, and its location is
  922.          *   itself visible, it's visible
  923.          */
  924.         if ( loc.contentsVisible and loc.isVisible( vantage )) return( true );
  925.  
  926.         /*
  927.          *   If the vantage has a location, and the vantage's location's
  928.          *   contents are visible (if you can see me I can see you), and
  929.          *   the object is visible from the vantage's location, the object
  930.          *   is visible
  931.          */
  932.         if ( vantage.location <> nil and vantage.location.contentsVisible and
  933.          self.isVisible( vantage.location ))
  934.             return( true );
  935.  
  936.         /* all tests failed:  it's not visible */
  937.         return( nil );
  938.     }
  939.     cantReach( actor ) =
  940.     {
  941.         if ( self.location = nil )
  942.         {
  943.             if ( actor.location.location )
  944.                "%You% can't reach that from << actor.location.thedesc >>. ";
  945.             return;
  946.         }
  947.         if ( not self.location.isopenable or self.location.isopen )
  948.             self.location.cantReach( actor );
  949.         else "%You%'ll have to open << self.location.thedesc >> first. ";
  950.     }
  951.     isReachable( actor ) =
  952.     {
  953.         local loc;
  954.  
  955.         /* if the object is in the room's 'reachable' list, it's reachable */
  956.         if (find( actor.location.reachable, self ) <> nil )
  957.             return( true );
  958.  
  959.         /*
  960.          *   If the object's container's contents are reachable, and the
  961.          *   container is reachable, the object is reachable.
  962.          */
  963.         loc := self.location;
  964.     if (find( actor.location.reachable, self ) <> nil )
  965.         return( true );
  966.     if ( loc = nil ) return( nil );
  967.     if ( loc = actor or loc = actor.location ) return( true );
  968.     if ( loc.contentsReachable )
  969.         return( loc.isReachable( actor ));
  970.     return( nil );
  971.         return( nil );
  972.     }
  973.     doTake( actor ) =
  974.     {
  975.         local totbulk, totweight;
  976.  
  977.         totbulk := addbulk( actor.contents ) + self.bulk;
  978.         totweight := addweight( actor.contents );
  979.         if ( not actor.isCarrying( self ))
  980.             totweight := totweight + self.weight + addweight(self.contents);
  981.  
  982.         if ( totweight > actor.maxweight )
  983.             "%Your% load is too heavy. ";
  984.         else if ( totbulk > actor.maxbulk )
  985.             "%You've% already got %your% hands full. ";
  986.         else
  987.         {
  988.             self.moveInto( actor );
  989.             "Taken. ";
  990.         }
  991.     }
  992.     verDoDrop( actor ) =
  993.     {
  994.         if ( not actor.isCarrying( self ))
  995.         {
  996.             "%You're% not carrying "; self.thedesc; "! ";
  997.         }
  998.         else self.verifyRemove( actor );
  999.     }
  1000.     doDrop( actor ) =
  1001.     {
  1002.         actor.location.roomDrop( self );
  1003.     }
  1004.     verDoUnwear( actor ) =
  1005.     {
  1006.         "%You're% not wearing "; self.thedesc; "! ";
  1007.     }
  1008.     verIoPutIn( actor ) =
  1009.     {
  1010.         "%You% can't put anything into "; self.thedesc; ". ";
  1011.     }
  1012.     circularMessage(io) =
  1013.     {
  1014.         local cont;
  1015.  
  1016.     "%You% can't put <<thedesc>> in <<io.thedesc>>, because
  1017.     <<io.thedesc>> is <<io.location = self ? "already" : ""
  1018.         >> <<io.location.issurface ? "on" : "in">> <<io.location.thedesc>>";
  1019.     for (cont := io.location ; cont <> self ; cont := cont.location)
  1020.     {
  1021.         ", which is ";
  1022.             if (cont.location = self) "already ";
  1023.             "<<cont.location.issurface ? "on" : "in"
  1024.             >> <<cont.location.thedesc>>";
  1025.     }
  1026.     ".";
  1027.     }
  1028.     verDoPutIn( actor, io ) =
  1029.     {
  1030.         if ( io = nil ) return;
  1031.  
  1032.         if ( self.location = io )
  1033.         {
  1034.             caps(); self.thedesc; " is already in "; io.thedesc; "! ";
  1035.         }
  1036.         else if (io = self)
  1037.         {
  1038.             "%You% can't put "; self.thedesc; " in itself! ";
  1039.         }
  1040.         else if (io.isIn(self))
  1041.         self.circularMessage(io);
  1042.         else
  1043.             self.verifyRemove( actor );
  1044.     }
  1045.     doPutIn( actor, io ) =
  1046.     {
  1047.         self.moveInto( io );
  1048.         "Done. ";
  1049.     }
  1050.     verIoPutOn( actor ) =
  1051.     {
  1052.         "There's no good surface on "; self.thedesc; ". ";
  1053.     }
  1054.     verDoPutOn( actor, io ) =
  1055.     {
  1056.         if ( io = nil ) return;
  1057.  
  1058.         if ( self.location = io )
  1059.         {
  1060.             caps(); self.thedesc; " is already on "; io.thedesc; "! ";
  1061.         }
  1062.     else if (io = self)
  1063.         {
  1064.             "%You% can't put "; self.thedesc; " on itself! ";
  1065.         }
  1066.     else if (io.isIn(self))
  1067.         self.circularMessage(io);
  1068.         else
  1069.         self.verifyRemove( actor );
  1070.     }
  1071.     doPutOn( actor, io ) =
  1072.     {
  1073.         self.moveInto( io );
  1074.         "Done. ";
  1075.     }
  1076.     verIoTakeOut( actor ) = {}
  1077.     ioTakeOut( actor, dobj ) =
  1078.     {
  1079.         dobj.doTakeOut( actor, self );
  1080.     }
  1081.     verDoTakeOut( actor, io ) =
  1082.     {
  1083.         if ( io <> nil and not self.isIn( io ))
  1084.         {
  1085.             caps(); self.thedesc; " isn't in "; io.thedesc; ". ";
  1086.         }
  1087.     self.verDoTake(actor);         /* ensure object can be taken at all */
  1088.     }
  1089.     doTakeOut( actor, io ) =
  1090.     {
  1091.         self.doTake( actor );
  1092.     }
  1093.     verIoTakeOff( actor ) = {}
  1094.     ioTakeOff( actor, dobj ) =
  1095.     {
  1096.         dobj.doTakeOff( actor, self );
  1097.     }
  1098.     verDoTakeOff( actor, io ) =
  1099.     {
  1100.         if ( io <> nil and not self.isIn( io ))
  1101.         {
  1102.             caps(); self.thedesc; " isn't on "; io.thedesc; "! ";
  1103.         }
  1104.     self.verDoTake(actor);         /* ensure object can be taken at all */
  1105.     }
  1106.     doTakeOff( actor, io ) =
  1107.     {
  1108.         self.doTake( actor );
  1109.     }
  1110.     verIoPlugIn( actor ) =
  1111.     {
  1112.         "%You% can't plug anything into "; self.thedesc; ". ";
  1113.     }
  1114.     verDoPlugIn( actor, io ) =
  1115.     {
  1116.         "%You% can't plug "; self.thedesc; " into anything. ";
  1117.     }
  1118.     verIoUnplugFrom( actor ) =
  1119.     {
  1120.         "It's not plugged into "; self.thedesc; ". ";
  1121.     }
  1122.     verDoUnplugFrom( actor, io ) =
  1123.     {
  1124.         if ( io <> nil ) { "It's not plugged into "; io.thedesc; ". "; }
  1125.     }
  1126.     verDoLookin( actor ) =
  1127.     {
  1128.         "There's nothing in "; self.thedesc; ". ";
  1129.     }
  1130.     thrudesc = { "%You% can't see much through << thedesc >>.\n"; }
  1131.     verDoLookthru( actor ) =
  1132.     {
  1133.         "%You% can't see anything through "; self.thedesc; ". ";
  1134.     }
  1135.     verDoLookunder( actor ) =
  1136.     {
  1137.         "There's nothing under "; self.thedesc; ". ";
  1138.     }
  1139.     verDoInspect( actor ) = {}
  1140.     doInspect( actor ) =
  1141.     {
  1142.         self.ldesc;
  1143.     }
  1144.     verDoRead( actor ) =
  1145.     {
  1146.         "I don't know how to read "; self.thedesc; ". ";
  1147.     }
  1148.     verDoLookbehind( actor ) =
  1149.     {
  1150.         "There's nothing behind "; self.thedesc; ". ";
  1151.     }
  1152.     verDoTurn( actor ) =
  1153.     {
  1154.         "Turning "; self.thedesc; " doesn't have any effect. ";
  1155.     }
  1156.     verDoTurnWith( actor, io ) =
  1157.     {
  1158.         "Turning "; self.thedesc; " doesn't have any effect. ";
  1159.     }
  1160.     verDoTurnTo( actor, io ) =
  1161.     {
  1162.         "Turning "; self.thedesc; " doesn't have any effect. ";
  1163.     }
  1164.     verIoTurnTo( actor ) =
  1165.     {
  1166.         "I don't know how to do that. ";
  1167.     }
  1168.     verDoTurnon( actor ) =
  1169.     {
  1170.         "I don't know how to turn "; self.thedesc; " on. ";
  1171.     }
  1172.     verDoTurnoff( actor ) =
  1173.     {
  1174.         "I don't know how to turn "; self.thedesc; " off. ";
  1175.     }
  1176.     verIoAskAbout( actor ) = {}
  1177.     ioAskAbout( actor, dobj ) =
  1178.     {
  1179.         dobj.doAskAbout( actor, self );
  1180.     }
  1181.     verDoAskAbout( actor, io ) =
  1182.     {
  1183.         "Surely, %you% can't think "; self.thedesc; " knows anything
  1184.         about it! ";
  1185.     }
  1186.     verIoTellAbout( actor ) = {}
  1187.     ioTellAbout( actor, dobj ) =
  1188.     {
  1189.         dobj.doTellAbout( actor, self );
  1190.     }
  1191.     verDoTellAbout( actor, io ) =
  1192.     {
  1193.         "It doesn't look as though "; self.thedesc; " is interested. ";
  1194.     }
  1195.     verDoUnboard( actor ) =
  1196.     {
  1197.         if ( actor.location <> self )
  1198.         {
  1199.             "%You're% not in "; self.thedesc; "! ";
  1200.         }
  1201.         else if ( self.location=nil )
  1202.         {
  1203.             "%You% can't get out of "; self.thedesc; "! ";
  1204.         }
  1205.     }
  1206.     doUnboard( actor ) =
  1207.     {
  1208.         if ( self.fastenitem )
  1209.     {
  1210.         "%You%'ll have to unfasten "; actor.location.fastenitem.thedesc;
  1211.         " first. ";
  1212.     }
  1213.     else
  1214.     {
  1215.             "Okay, %you're% no longer in "; self.thedesc; ". ";
  1216.             self.leaveRoom( actor );
  1217.         actor.moveInto( self.location );
  1218.     }
  1219.     }
  1220.     verDoAttackWith( actor, io ) =
  1221.     {
  1222.         "Attacking "; self.thedesc; " doesn't appear productive. ";
  1223.     }
  1224.     verIoAttackWith( actor ) =
  1225.     {
  1226.         "It's not very effective to attack with "; self.thedesc; ". ";
  1227.     }
  1228.     verDoEat( actor ) =
  1229.     {
  1230.         caps(); self.thedesc; " doesn't appear appetizing. ";
  1231.     }
  1232.     verDoDrink( actor ) =
  1233.     {
  1234.         caps(); self.thedesc; " doesn't appear appetizing. ";
  1235.     }
  1236.     verDoGiveTo( actor, io ) =
  1237.     {
  1238.         if ( not actor.isCarrying( self ))
  1239.         {
  1240.             "%You're% not carrying "; self.thedesc; ". ";
  1241.         }
  1242.         else self.verifyRemove( actor );
  1243.     }
  1244.     doGiveTo( actor, io ) =
  1245.     {
  1246.         self.moveInto( io );
  1247.         "Done. ";
  1248.     }
  1249.     verDoPull( actor ) =
  1250.     {
  1251.         "Pulling "; self.thedesc; " doesn't have any effect. ";
  1252.     }
  1253.     verDoThrowAt( actor, io ) =
  1254.     {
  1255.         if ( not actor.isCarrying( self ))
  1256.         {
  1257.             "%You're% not carrying "; self.thedesc; ". ";
  1258.         }
  1259.         else self.verifyRemove( actor );
  1260.     }
  1261.     doThrowAt( actor, io ) =
  1262.     {
  1263.         "%You% miss%es%. ";
  1264.         self.moveInto( actor.location );
  1265.     }
  1266.     verIoThrowAt( actor ) =
  1267.     {
  1268.         if ( actor.isCarrying( self ))
  1269.         {
  1270.             "%You% could at least drop "; self.thedesc; " first. ";
  1271.         }
  1272.     }
  1273.     ioThrowAt( actor, dobj ) =
  1274.     {
  1275.         dobj.doThrowAt( actor, self );
  1276.     }
  1277.     verDoThrowTo( actor, io ) =
  1278.     {
  1279.         if ( not actor.isCarrying( self ))
  1280.         {
  1281.             "%You're% not carrying "; self.thedesc; ". ";
  1282.         }
  1283.         else self.verifyRemove( actor );
  1284.     }
  1285.     doThrowTo( actor, io ) =
  1286.     {
  1287.         "%You% miss%es%. ";
  1288.         self.moveInto( actor.location );
  1289.     }
  1290.     verDoThrow( actor ) =
  1291.     {
  1292.         if ( not actor.isCarrying( self ))
  1293.         {
  1294.             "%You're% not carrying "; self.thedesc; ". ";
  1295.         }
  1296.         else self.verifyRemove( actor );
  1297.     }
  1298.     doThrow( actor ) =
  1299.     {
  1300.         "Thrown. ";
  1301.         self.moveInto( actor.location );
  1302.     }
  1303.     verDoShowTo( actor, io ) =
  1304.     {
  1305.     }
  1306.     doShowTo( actor, io ) =
  1307.     {
  1308.         if ( io <> nil ) { caps(); io.thedesc; " isn't impressed. "; }
  1309.     }
  1310.     verIoShowTo( actor ) =
  1311.     {
  1312.         caps(); self.thedesc; " isn't impressed. ";
  1313.     }
  1314.     verDoClean( actor ) =
  1315.     {
  1316.         caps(); self.thedesc; " looks a bit cleaner now. ";
  1317.     }
  1318.     verDoCleanWith( actor, io ) = {}
  1319.     doCleanWith( actor, io ) =
  1320.     {
  1321.         caps(); self.thedesc; " looks a bit cleaner now. ";
  1322.     }
  1323.     verDoMove( actor ) =
  1324.     {
  1325.         "Moving "; self.thedesc; " doesn't reveal anything. ";
  1326.     }
  1327.     verDoMoveTo( actor, io ) =
  1328.     {
  1329.         "Moving "; self.thedesc; " doesn't reveal anything. ";
  1330.     }
  1331.     verIoMoveTo( actor ) =
  1332.     {
  1333.         "That doesn't get us anywhere. ";
  1334.     }
  1335.     verDoMoveWith( actor, io ) =
  1336.     {
  1337.         "Moving "; self.thedesc; " doesn't reveal anything. ";
  1338.     }
  1339.     verIoMoveWith( actor ) =
  1340.     {
  1341.         caps(); self.thedesc; " doesn't seem to help. ";
  1342.     }
  1343.     verDoTypeOn( actor, io ) =
  1344.     {
  1345.         "You should say what you want to type in double quotes, for
  1346.         example, TYPE \"HELLO\" ON KEYBOARD. ";
  1347.     }
  1348.     verDoTouch( actor ) =
  1349.     {
  1350.         "Touching "; self.thedesc; " doesn't seem to have any effect. ";
  1351.     }
  1352.     verDoPoke( actor ) =
  1353.     {
  1354.         "Poking "; self.thedesc; " doesn't seem to have any effect. ";
  1355.     }
  1356.     verDoBreak(actor) = {}
  1357.     doBreak(actor) =
  1358.     {
  1359.     "You'll have to tell me how to do that.";
  1360.     }
  1361.     genMoveDir = { "%You% can't seem to do that. "; }
  1362.     verDoMoveN( actor ) = { self.genMoveDir; }
  1363.     verDoMoveS( actor ) = { self.genMoveDir; }
  1364.     verDoMoveE( actor ) = { self.genMoveDir; }
  1365.     verDoMoveW( actor ) = { self.genMoveDir; }
  1366.     verDoMoveNE( actor ) = { self.genMoveDir; }
  1367.     verDoMoveNW( actor ) = { self.genMoveDir; }
  1368.     verDoMoveSE( actor ) = { self.genMoveDir; }
  1369.     verDoMoveSW( actor ) = { self.genMoveDir; }
  1370.     verDoSearch( actor ) =
  1371.     {
  1372.         "%You% find%s% nothing of interest. ";
  1373.     }
  1374.  
  1375.     /* on dynamic construction, move into my contents list */
  1376.     construct =
  1377.     {
  1378.     self.moveInto(location);
  1379.     }
  1380.  
  1381.     /* on dynamic destruction, move out of contents list */
  1382.     destruct =
  1383.     {
  1384.     self.moveInto(nil);
  1385.     }
  1386.  
  1387.     /*
  1388.      *   Make it so that the player can give a command to an actor only
  1389.      *   if an actor is reachable in the normal manner.  This method
  1390.      *   returns true when 'self' can be given a command by the player. 
  1391.      */
  1392.     validActor = (self.isReachable(Me))
  1393. ;
  1394.  
  1395. /*
  1396.  *  item: thing
  1397.  *
  1398.  *  A basic item which can be picked up by the player.  It has no weight
  1399.  *  (0) and minimal bulk (1).  The weight property should be set
  1400.  *  to a non-zero value for heavy objects.  The bulk property
  1401.  *  should be set to a value greater than 1 for bulky objects, and to
  1402.  *  zero for objects that are very small and take essentially no effort
  1403.  *  to hold---or, more precisely, don't detract at all from the player's
  1404.  *  ability to hold other objects (for example, a piece of paper).
  1405.  */
  1406. class item: thing
  1407.     weight = 0
  1408.     bulk = 1
  1409. ;
  1410.     
  1411. /*
  1412.  *  lightsource: item
  1413.  *
  1414.  *  A portable lamp, candle, match, or other source of light.  The
  1415.  *  light source can be turned on and off with the islit property.
  1416.  *  If islit is true, the object provides light, otherwise it's
  1417.  *  just an ordinary object.  Note that this object provides a doTurnon
  1418.  *  method to provide appropriate behavior for a switchable light source,
  1419.  *  such as a flashlight or a room's electric lights.  However, this object
  1420.  *  does not provide a verDoTurnon method, so by default it can't be
  1421.  *  switched on and off.  To create something like a flashlight that should
  1422.  *  be a lightsource that can be switched on and off, simply include both
  1423.  *  lightsource and switchItem in the superclass list, and be sure
  1424.  *  that lightsource precedes switchItem in the superclass list,
  1425.  *  because the doTurnon method provided by lightsource should
  1426.  *  override the one provided by switchItem.  The doTurnon method
  1427.  *  provided here turns on the light source (by setting its isActive
  1428.  *  property to true, and then describes the room if it was previously
  1429.  *  dark.
  1430.  */
  1431. class lightsource: item
  1432.     islamp = true
  1433.     doTurnon(actor) =
  1434.     {
  1435.     local waslit := actor.location.islit;
  1436.  
  1437.     // turn on the light
  1438.     self.isActive := true;
  1439.     "You switch on <<thedesc>>";
  1440.  
  1441.     // if the room wasn't previously lit, and it is now, describe it
  1442.     if (actor.location.islit and not waslit)
  1443.     {
  1444.         ", lighting the area.\b";
  1445.         actor.location.enterRoom(actor);
  1446.     }
  1447.     else
  1448.         ".";
  1449.     }
  1450. ;
  1451.  
  1452. /*
  1453.  *  hiddenItem: object
  1454.  *
  1455.  *  This is an object that is hidden with one of the hider classes. 
  1456.  *  A hiddenItem object doesn't have any special properties in its
  1457.  *  own right, but all objects hidden with one of the hider classes
  1458.  *  must be of class hiddenItem so that initSearch can find
  1459.  *  them.
  1460.  */
  1461. class hiddenItem: object
  1462. ;
  1463.  
  1464. /*
  1465.  *  hider: item
  1466.  *
  1467.  *  This is a basic class of object that can hide other objects in various
  1468.  *  ways.  The underHider, behindHider, and searchHider classes
  1469.  *  are examples of hider subclasses.  The class defines
  1470.  *  the method searchObj(actor, list), which is given the list
  1471.  *  of hidden items contained in the object (for example, this would be the
  1472.  *  underCont property, in the case of an underHider), and "finds"
  1473.  *  the object or objects. Its action is dependent upon a couple of other
  1474.  *  properties of the hider object.  The serialSearch property,
  1475.  *  if true, indicates that items in the list are to be found one at
  1476.  *  a time; if nil (the default), the entire list is found on the
  1477.  *  first try.  The autoTake property, if true, indicates that
  1478.  *  the actor automatically takes the item or items found; if nil, the
  1479.  *  item or items are moved to the actor's location.  The searchObj method
  1480.  *  returns the list with the found object or objects removed; the
  1481.  *  caller should assign this returned value back to the appropriate
  1482.  *  property (for example, underHider will assign the return value
  1483.  *  to underCont).
  1484.  *  
  1485.  *  Note that because the hider is hiding something, this class
  1486.  *  overrides the normal verDoSearch method to display the
  1487.  *  message, "You'll have to be more specific about how you want
  1488.  *  to search that."  The reason is that the normal verDoSearch
  1489.  *  message ("You find nothing of interest") leads players to believe
  1490.  *  that the object was exhaustively searched, and we want to avoid
  1491.  *  misleading the player.  On the other hand, we don't want a general
  1492.  *  search to be exhaustive for most hider objects.  So, we just
  1493.  *  display a message letting the player know that the search was not
  1494.  *  enough, but we don't give away what they have to do instead.
  1495.  *  
  1496.  *  The objects hidden with one of the hider classes must be
  1497.  *  of class hiddenItem.
  1498.  */
  1499. class hider: item
  1500.     verDoSearch(actor) =
  1501.     {
  1502.     "%You%'ll have to be more specific about how %you% want%s%
  1503.     to search that. ";
  1504.     }
  1505.     searchObj(actor, list) =
  1506.     {
  1507.     local found, dest, i, tot;
  1508.  
  1509.     /* see how much we get this time */
  1510.     if (self.serialSearch)
  1511.     {
  1512.         found := [] + car(list);
  1513.         list := cdr(list);
  1514.     }
  1515.     else
  1516.     {
  1517.         found := list;
  1518.         list := nil;
  1519.     }
  1520.  
  1521.     /* set it(them) to the found item(s) */
  1522.         if (length(found) = 1)
  1523.         setit(found[1]);    // only one item - set 'it'
  1524.     else
  1525.         setit(found);       // multiple items - set 'them'
  1526.  
  1527.     /* figure destination */
  1528.     dest := actor;
  1529.     if (not self.autoTake) dest := dest.location;
  1530.     
  1531.     /* note what we found, and move it to destination */
  1532.     "%You% find%s% ";
  1533.     tot := length(found);
  1534.     i := 1;
  1535.     while (i <= tot)
  1536.     {
  1537.         found[i].adesc;
  1538.         if (i+1 < tot) ", ";
  1539.         else if (i = 1 and tot = 2) " and ";
  1540.         else if (i+1 = tot and tot > 2) ", and ";
  1541.         
  1542.         found[i].moveInto(dest);
  1543.         i := i + 1;
  1544.     }
  1545.  
  1546.     /* say what happened */
  1547.     if (self.autoTake) ", which %you% take%s%. ";
  1548.     else "! ";
  1549.  
  1550.     if (list<>nil and length(list)=0) list := nil;
  1551.     return(list);
  1552.     }
  1553.     serialSearch = nil             /* find everything in one try by default */
  1554.     autoTake = true               /* actor takes item when found by default */
  1555. ;
  1556.  
  1557. /*
  1558.  *  underHider: hider
  1559.  *
  1560.  *  This is an object that can have other objects placed under it.  The
  1561.  *  objects placed under it can only be found by looking under the object;
  1562.  *  see the description of hider for more information.  You should
  1563.  *  set the underLoc property of each hidden object to point to
  1564.  *  the underHider.
  1565.  *  
  1566.  *  Note that an underHider doesn't allow the player to put anything
  1567.  *  under the object during the game.  Instead, it's to make it easy for the
  1568.  *  game writer to set up hidden objects while implementing the game.  All you
  1569.  *  need to do to place an object under another object is declare the top
  1570.  *  object as an underHider, then declare the hidden object normally,
  1571.  *  except use underLoc rather than location to specify the
  1572.  *  location of the hidden object.  The behindHider and searchHider
  1573.  *  objects work similarly.
  1574.  *  
  1575.  *  The objects hidden with underHider must be of class hiddenItem.
  1576.  */
  1577. class underHider: hider
  1578.     underCont = []         /* list of items under me (set up by initSearch) */
  1579.     verDoLookunder(actor) = {}
  1580.     doLookunder(actor) =
  1581.     {
  1582.     if (self.underCont = nil)
  1583.         "There's nothing else under <<self.thedesc>>. ";
  1584.     else
  1585.         self.underCont := self.searchObj(actor, self.underCont);
  1586.     }
  1587. ;
  1588.  
  1589. /*
  1590.  *  behindHider: hider
  1591.  *
  1592.  *  This is just like an underHider, except that objects are hidden
  1593.  *  behind this object.  Objects to be behind this object should have their
  1594.  *  behindLoc property set to point to this object.
  1595.  *  
  1596.  *  The objects hidden with behindHider must be of class hiddenItem.
  1597.  */
  1598. class behindHider: hider
  1599.     behindCont = []
  1600.     verDoLookbehind(actor) = {}
  1601.     doLookbehind(actor) =
  1602.     {
  1603.     if (self.behindCont = nil)
  1604.         "There's nothing else behind <<self.thedesc>>. ";
  1605.     else
  1606.         self.behindCont := self.searchObj(actor, self.behindCont);
  1607.     }
  1608. ;
  1609.     
  1610. /*
  1611.  *  searchHider: hider
  1612.  *
  1613.  *  This is just like an underHider, except that objects are hidden
  1614.  *  within this object in such a way that the object must be looked in
  1615.  *  or searched.  Objects to be hidden in this object should have their
  1616.  *  searchLoc property set to point to this object.  Note that this
  1617.  *  is different from a normal container, in that the objects hidden within
  1618.  *  this object will not show up until the object is explicitly looked in
  1619.  *  or searched.
  1620.  *  
  1621.  *  The items hidden with searchHider must be of class hiddenItem.
  1622.  */
  1623. class searchHider: hider
  1624.     searchCont = []
  1625.     verDoSearch(actor) = {}
  1626.     doSearch(actor) =
  1627.     {
  1628.     if (self.searchCont = nil)
  1629.         "There's nothing else in <<self.thedesc>>. ";
  1630.     else
  1631.         self.searchCont := self.searchObj(actor, self.searchCont);
  1632.     }
  1633.     verDoLookin(actor) =
  1634.     {
  1635.     if (self.searchCont = nil)
  1636.         pass verDoLookin;
  1637.     }
  1638.     doLookin(actor) =
  1639.     {
  1640.     if (self.searchCont = nil)
  1641.         pass doLookin;
  1642.     else
  1643.         self.searchCont := self.searchObj(actor, self.searchCont);
  1644.     }
  1645. ;
  1646.     
  1647.  
  1648. /*
  1649.  *  fixeditem: thing
  1650.  *
  1651.  *  An object that cannot be taken or otherwise moved from its location.
  1652.  *  Note that a fixeditem is sometimes part of a movable object;
  1653.  *  this can be done to make one object part of another, ensuring that
  1654.  *  they cannot be separated.  By default, the functions that list a room's
  1655.  *  contents do not automatically describe fixeditem objects (because
  1656.  *  the isListed property is set to nil).  Instead, the game author
  1657.  *  will generally describe the fixeditem objects separately as part of
  1658.  *  the room's ldesc.  
  1659.  */
  1660. class fixeditem: thing      // An immovable object
  1661.     isListed = nil          // not listed in room/inventory displays
  1662.     isfixed = true          // Item can't be taken
  1663.     weight = 0              // no actual weight
  1664.     bulk = 0
  1665.     verDoTake( actor ) =
  1666.     {
  1667.         "%You% can't have "; self.thedesc; ". ";
  1668.     }
  1669.     verDoTakeOut( actor, io ) =
  1670.     {
  1671.         self.verDoTake( actor );
  1672.     }
  1673.     verDoDrop( actor ) =
  1674.     {
  1675.         "%You% can't drop "; self.thedesc; ". ";
  1676.     }
  1677.     verDoTakeOff( actor, io ) =
  1678.     {
  1679.         self.verDoTake( actor );
  1680.     }
  1681.     verDoPutIn( actor, io ) =
  1682.     {
  1683.         "%You% can't put "; self.thedesc; " anywhere. ";
  1684.     }
  1685.     verDoPutOn( actor, io ) =
  1686.     {
  1687.         "%You% can't put "; self.thedesc; " anywhere. ";
  1688.     }
  1689.     verDoMove( actor ) =
  1690.     {
  1691.         "%You% can't move "; self.thedesc; ". ";
  1692.     }
  1693.     verDoThrowAt(actor, iobj) =
  1694.     {
  1695.         "%You% can't throw <<self.thedesc>>.";
  1696.     }
  1697. ;
  1698.  
  1699. /*
  1700.  *  readable: item
  1701.  *
  1702.  *  An item that can be read.  The readdesc property is displayed
  1703.  *  when the item is read.  By default, the readdesc is the same
  1704.  *  as the ldesc, but the readdesc can be overridden to give
  1705.  *  a different message.
  1706.  */
  1707. class readable: item
  1708.     verDoRead( actor ) =
  1709.     {
  1710.     }
  1711.     doRead( actor ) =
  1712.     {
  1713.         self.readdesc;
  1714.     }
  1715.     readdesc =
  1716.     {
  1717.         self.ldesc;
  1718.     }
  1719. ;
  1720.  
  1721. /*
  1722.  *  fooditem: item
  1723.  *
  1724.  *  An object that can be eaten.  When eaten, the object is removed from
  1725.  *  the game, and global.lastMealTime is decremented by the
  1726.  *  foodvalue property.  By default, the foodvalue property
  1727.  *  is global.eatTime, which is the time between meals.  So, the
  1728.  *  default fooditem will last for one "nourishment interval."
  1729.  */
  1730. class fooditem: item
  1731.     verDoEat( actor ) =
  1732.     {
  1733.         self.verifyRemove( actor );
  1734.     }
  1735.     doEat( actor ) =
  1736.     {
  1737.         "That was delicious! ";
  1738.         global.lastMealTime := global.lastMealTime - self.foodvalue;
  1739.         self.moveInto( nil );
  1740.     }
  1741.     foodvalue = { return( global.eatTime ); }
  1742. ;
  1743.  
  1744. /*
  1745.  *  dialItem: fixeditem
  1746.  *
  1747.  *  This class is used for making "dials," which are controls in
  1748.  *  your game that can be turned to a range of numbers.  You must
  1749.  *  define the property maxsetting as a number specifying the
  1750.  *  highest number to which the dial can be turned; the lowest number
  1751.  *  on the dial is always 1.  The setting property is the dial's
  1752.  *  current setting, and can be changed by the player by typing the
  1753.  *  command "turn dial to number."  By default, the ldesc
  1754.  *  method displays the current setting.
  1755.  */
  1756. class dialItem: fixeditem
  1757.     maxsetting = 10 // it has settings from 1 to this number
  1758.     setting = 1     // the current setting
  1759.     ldesc =
  1760.     {
  1761.         caps(); self.thedesc; " can be turned to settings
  1762.         numbered from 1 to << self.maxsetting >>. It's
  1763.         currently set to << self.setting >>. ";
  1764.     }
  1765.     verDoTurn( actor ) = {}
  1766.     doTurn( actor ) =
  1767.     {
  1768.         askio( toPrep );
  1769.     }
  1770.     verDoTurnTo( actor, io ) = {}
  1771.     doTurnTo( actor, io ) =
  1772.     {
  1773.         if ( io = numObj )
  1774.         {
  1775.             if ( numObj.value < 1 or numObj.value > self.maxsetting )
  1776.             {
  1777.                 "There's no such setting! ";
  1778.             }
  1779.             else if ( numObj.value <> self.setting )
  1780.             {
  1781.                 self.setting := numObj.value;
  1782.                 "Okay, it's now turned to "; say( self.setting ); ". ";
  1783.             }
  1784.             else
  1785.             {
  1786.                 "It's already set to "; say( self.setting ); "! ";
  1787.             }
  1788.         }
  1789.         else
  1790.         {
  1791.             "I don't know how to turn "; self.thedesc;
  1792.             " to that. ";
  1793.         }
  1794.     }
  1795. ;
  1796.  
  1797. /*
  1798.  *  switchItem: fixeditem
  1799.  *
  1800.  *  This is a class for things that can be turned on and off by the
  1801.  *  player.  The only special property is isActive, which is nil
  1802.  *  if the switch is turned off and true when turned on.  The object
  1803.  *  accepts the commands "turn it on" and "turn it off,'' as well as
  1804.  *  synonymous constructions, and updates isActive accordingly.
  1805.  */
  1806. class switchItem: fixeditem
  1807.     verDoSwitch( actor ) = {}
  1808.     doSwitch( actor ) =
  1809.     {
  1810.         self.isActive := not self.isActive;
  1811.         "Okay, "; self.thedesc; " is now switched ";
  1812.         if ( self.isActive ) "on"; else "off";
  1813.         ". ";
  1814.     }
  1815.     verDoTurnon( actor ) =
  1816.     {
  1817.         /*
  1818.            You can't turn on something in the dark unless you're carrying
  1819.            it.  You also can't turn something on if it's already on.
  1820.         */
  1821.     if (not actor.location.islit and not actor.isCarrying(self))
  1822.         "It's pitch black.";
  1823.         else if ( self.isActive )
  1824.             "It's already turned on! ";
  1825.     }
  1826.     doTurnon( actor ) =
  1827.     {
  1828.         self.isActive := true;
  1829.         "Okay, it's now turned on. ";
  1830.     }
  1831.     verDoTurnoff( actor ) =
  1832.     {
  1833.         if ( not self.isActive ) "It's already turned off! ";
  1834.     }
  1835.     doTurnoff( actor ) =
  1836.     {
  1837.         self.isActive := nil;
  1838.         "Okay, it's now turned off. ";
  1839.     }
  1840. ;
  1841.  
  1842. /*
  1843.  *  room: thing
  1844.  *
  1845.  *  A location in the game.  By default, the islit property is
  1846.  *  true, which means that the room is lit (no light source is
  1847.  *  needed while in the room).  You should create a darkroom
  1848.  *  object rather than a room with islit set to nil if you
  1849.  *  want a dark room, because other methods are affected as well.
  1850.  *  The isseen property records whether the player has entered
  1851.  *  the room before; initially it's nil, and is set to true
  1852.  *  the first time the player enters.  The roomAction(actor,
  1853.  *  verb, directObject, preposition, indirectObject) method is
  1854.  *  activated for each player command; by default, all it does is
  1855.  *  call the room's location's roomAction method if the room
  1856.  *  is inside another room.  The lookAround(verbosity)
  1857.  *  method displays the room's description for a given verbosity
  1858.  *  level; true means a full description, nil means only
  1859.  *  the short description (just the room name plus a list of the
  1860.  *  objects present).  roomDrop(object) is called when
  1861.  *  an object is dropped within the room; normally, it just moves
  1862.  *  the object to the room and displays "Dropped."  The firstseen
  1863.  *  method is called when isseen is about to be set true
  1864.  *  for the first time (i.e., when the player first sees the room);
  1865.  *  by default, this routine does nothing, but it's a convenient
  1866.  *  place to put any special code you want to execute when a room
  1867.  *  is first entered.  The firstseen method is called after
  1868.  *  the room's description is displayed.
  1869.  */
  1870. class room: thing
  1871.     /*
  1872.      *   'reachable' is the list of explicitly reachable objects, over and
  1873.      *   above the objects that are here.  This is mostly used in nested
  1874.      *   rooms to make objects in the containing room accessible.  Most
  1875.      *   normal rooms will leave this as an empty list.
  1876.      */
  1877.     reachable = []
  1878.     
  1879.     /*
  1880.      *   roomCheck is true if the verb is valid in the room.  This
  1881.      *   is a first pass; generally, its only function is to disallow
  1882.      *   certain commands in a dark room.
  1883.      */
  1884.     roomCheck( v ) = { return( true ); }
  1885.     islit = true            // rooms are lit unless otherwise specified
  1886.     isseen = nil            // room has not been seen yet
  1887.     enterRoom( actor ) =    // sent to room as actor is entering it
  1888.     {
  1889.         self.lookAround(( not self.isseen ) or global.verbose );
  1890.         if ( self.islit )
  1891.     {
  1892.         if (not self.isseen) self.firstseen;
  1893.         self.isseen := true;
  1894.     }
  1895.     }
  1896.     roomAction( a, v, d, p, i ) =
  1897.     {
  1898.         if ( self.location ) self.location.roomAction( a, v, d, p, i );
  1899.     }
  1900.  
  1901.     /*
  1902.      *   Whenever a normal object (i.e., one that does not override the
  1903.      *   default doDrop provided by 'thing') is dropped, the actor's
  1904.      *   location is sent roomDrop(object being dropped).  By default, 
  1905.      *   we move the object into this room.
  1906.      */
  1907.     roomDrop( obj ) =
  1908.     {
  1909.         "Dropped. ";
  1910.     obj.moveInto( self );
  1911.     }
  1912.  
  1913.     /*
  1914.      *   Whenever an actor leaves this room, we run through the leaveList.
  1915.      *   This is a list of objects that have registered themselves with us
  1916.      *   via addLeaveList().  For each object in the leaveList, we send
  1917.      *   a "leaving" message, with the actor as the parameter.  It should
  1918.      *   return true if it wants to be removed from the leaveList, nil
  1919.      *   if it wants to stay.
  1920.      */
  1921.     leaveList = []
  1922.     addLeaveList( obj ) =
  1923.     {
  1924.         self.leaveList := self.leaveList + obj;
  1925.     }
  1926.     leaveRoom( actor ) =
  1927.     {
  1928.         local tmplist, thisobj, i, tot;
  1929.  
  1930.         tmplist := self.leaveList;
  1931.     tot := length( tmplist );
  1932.     i := 1;
  1933.         while ( i <= tot )
  1934.         {
  1935.         thisobj := tmplist[i];
  1936.             if ( thisobj.leaving( actor ))
  1937.                 self.leaveList := self.leaveList - thisobj;
  1938.             i := i + 1;
  1939.         }
  1940.     }
  1941.     /*
  1942.      *   lookAround describes the room.  If verbosity is true, the full
  1943.      *   description is given, otherwise an abbreviated description (without
  1944.      *   the room's ldesc) is displayed.
  1945.      */
  1946.     nrmLkAround( verbosity ) =      // lookAround without location status
  1947.     {
  1948.         local l, cur, i, tot;
  1949.  
  1950.         if ( verbosity )
  1951.         {
  1952.             "\n\t"; self.ldesc;
  1953.  
  1954.             l := self.contents;
  1955.         tot := length( l );
  1956.         i := 1;
  1957.             while ( i <= tot )
  1958.             {
  1959.             cur := l[i];
  1960.                 if ( cur.isfixed ) cur.heredesc;
  1961.                 i := i + 1;
  1962.             }
  1963.         }
  1964.         "\n\t";
  1965.         if (itemcnt( self.contents ))
  1966.         {
  1967.             "You see "; listcont( self ); " here. ";
  1968.         }
  1969.         listcontcont( self ); "\n";
  1970.  
  1971.         l := self.contents;
  1972.     tot := length( l );
  1973.     i := 1;
  1974.         while ( i <= tot )
  1975.         {
  1976.         cur := l[i];
  1977.             if ( cur.isactor )
  1978.             {
  1979.                 if ( cur <> Me )
  1980.                 {
  1981.                     "\n\t";
  1982.                     cur.actorDesc;
  1983.                 }
  1984.             }
  1985.             i := i + 1;
  1986.         }
  1987.     }
  1988.     statusLine =
  1989.     {
  1990.         self.sdesc; "\n\t";
  1991.     }
  1992.     lookAround( verbosity ) =
  1993.     {
  1994.         self.statusLine;
  1995.         self.nrmLkAround( verbosity );
  1996.     }
  1997.     
  1998.     /*
  1999.      *   Direction handlers.  The directions are all set up to
  2000.      *   the default, which is no travel allowed.  To make travel
  2001.      *   possible in a direction, just assign a room to the direction
  2002.      *   property.
  2003.      */
  2004.     north = { return( self.noexit ); }
  2005.     south = { return( self.noexit ); }
  2006.     east  = { return( self.noexit ); }
  2007.     west  = { return( self.noexit ); }
  2008.     up    = { return( self.noexit ); }
  2009.     down  = { return( self.noexit ); }
  2010.     ne    = { return( self.noexit ); }
  2011.     nw    = { return( self.noexit ); }
  2012.     se    = { return( self.noexit ); }
  2013.     sw    = { return( self.noexit ); }
  2014.     in    = { return( self.noexit ); }
  2015.     out   = { return( self.noexit ); }
  2016.     
  2017.     /*
  2018.      *   noexit displays a message when the player attempts to travel
  2019.      *   in a direction in which travel is not possible.
  2020.      */
  2021.     noexit = { "%You% can't go that way. "; return( nil ); }
  2022. ;
  2023.  
  2024. /*
  2025.  *  darkroom: room
  2026.  *
  2027.  *  A dark room.  The player must have some object that can act as a
  2028.  *  light source in order to move about and perform most operations
  2029.  *  while in this room.  Note that the room's lights can be turned
  2030.  *  on by setting the room's lightsOn property to true;
  2031.  *  do this instead of setting islit, because islit is
  2032.  *  a method which checks for the presence of a light source.
  2033.  */
  2034. class darkroom: room        // An enterable area which might be dark
  2035.     islit =                 // true ONLY if something is lighting the room
  2036.     {
  2037.         local rem, cur, tot, i;
  2038.  
  2039.     if ( self.lightsOn ) return( true );
  2040.  
  2041.     rem := global.lamplist;
  2042.     tot := length( rem );
  2043.     i := 1;
  2044.     while ( i <= tot )
  2045.     {
  2046.         cur := rem[i];
  2047.         if ( cur.isIn( self ) and cur.islit ) return( true );
  2048.         i := i + 1;
  2049.     }
  2050.     return( nil );
  2051.     }
  2052.     roomAction( actor, v, dobj, prep, io ) =
  2053.     {
  2054.         if ( not self.islit and not v.isDarkVerb )
  2055.     {
  2056.         "%You% can't see a thing. ";
  2057.         exit;
  2058.     }
  2059.     else pass roomAction;
  2060.     }
  2061.     statusLine =
  2062.     {
  2063.         if ( self.islit ) pass statusLine;
  2064.     else "In the dark.";
  2065.     }
  2066.     lookAround( verbosity ) =
  2067.     {
  2068.         if ( self.islit ) pass lookAround;
  2069.     else "It's pitch black. ";
  2070.     }
  2071.     noexit =
  2072.     {
  2073.         if ( self.islit ) pass noexit;
  2074.     else
  2075.     {
  2076.         darkTravel();
  2077.         return( nil );
  2078.     }
  2079.     }
  2080.     roomCheck( v ) =
  2081.     {
  2082.         if ( self.islit or v.isDarkVerb ) return( true );
  2083.     else
  2084.     {
  2085.         "It's pitch black.\n";
  2086.         return( nil );
  2087.     }
  2088.     }
  2089. ;
  2090.  
  2091. /*
  2092.  *  theFloor is a special item that appears in every room (hence
  2093.  *  the non-standard location property).  This object is included
  2094.  *  mostly for completeness, so that the player can refer to the
  2095.  *  floor; otherwise, it doesn't do much.  Dropping an item on the
  2096.  *  floor, for example, moves it to the current room.
  2097.  */
  2098. theFloor: beditem, floatingItem
  2099.     noun = 'floor' 'ground'
  2100.     sdesc = "ground"
  2101.     adesc = "the ground"
  2102.     statusPrep = "on"
  2103.     outOfPrep = "off of"
  2104.     location =
  2105.     {
  2106.         if ( Me.location = self )
  2107.             return( self.sitloc );
  2108.         else
  2109.             return( Me.location );
  2110.     }
  2111.     locationOK = true        // suppress warning about location being a method
  2112.     doSiton( actor ) =
  2113.     {
  2114.         "Okay, %you're% now sitting on "; self.thedesc; ". ";
  2115.         self.sitloc := actor.location;
  2116.         actor.moveInto( self );
  2117.     }
  2118.     doLieon( actor ) =
  2119.     {
  2120.         self.doSiton( actor );
  2121.     }
  2122.     ioPutOn( actor, dobj ) =
  2123.     {
  2124.         dobj.doDrop( actor );
  2125.     }
  2126.     ioPutIn( actor, dobj ) =
  2127.     {
  2128.         dobj.doDrop( actor );
  2129.     }
  2130. ;
  2131.  
  2132. /*
  2133.  *  Actor: fixeditem, movableActor
  2134.  *
  2135.  *  A character in the game.  The maxweight property specifies
  2136.  *  the maximum weight that the character can carry, and the maxbulk
  2137.  *  property specifies the maximum bulk the character can carry.  The
  2138.  *  actorAction(verb, directObject, preposition, indirectObject)
  2139.  *  method specifies what happens when the actor is given a command by
  2140.  *  the player; by default, the actor ignores the command and displays
  2141.  *  a message to this effect.  The isCarrying(object)
  2142.  *  method returns true if the object is being carried by
  2143.  *  the actor.  The actorDesc method displays a message when the
  2144.  *  actor is in the current room; this message is displayed along with
  2145.  *  a room's description when the room is entered or examined.  The
  2146.  *  verGrab(object) method is called when someone tries to
  2147.  *  take an object the actor is carrying; by default, an actor won't
  2148.  *  let other characters take its possessions.
  2149.  *  
  2150.  *  If you want the player to be able to follow the actor when it
  2151.  *  leaves the room, you should define a follower object to shadow
  2152.  *  the character, and set the actor's myfollower property to
  2153.  *  the follower object.  The follower is then automatically
  2154.  *  moved around just behind the actor by the actor's moveInto
  2155.  *  method.
  2156.  *  
  2157.  *  The isHim property should return true if the actor can
  2158.  *  be referred to by the player as "him," and likewise isHer
  2159.  *  should be set to true if the actor can be referred to as "her."
  2160.  *  Note that both or neither can be set; if neither is set, the actor
  2161.  *  can only be referred to as "it," and if both are set, any of "him,''
  2162.  *  "her," or "it'' will be accepted.
  2163.  */
  2164. class Actor: fixeditem, movableActor
  2165. ;
  2166.  
  2167. /*
  2168.  *  movableActor: qcontainer
  2169.  *
  2170.  *  Just like an Actor object, except that the player can
  2171.  *  manipulate the actor like an ordinary item.  Useful for certain
  2172.  *  types of actors, such as small animals.
  2173.  */
  2174. class movableActor: qcontainer // A character in the game
  2175.     isListed = nil          // described separately from room's contents
  2176.     weight = 10             // actors are pretty heavy
  2177.     bulk = 10               // and pretty bulky
  2178.     maxweight = 50          // Weight that can be carried at once
  2179.     maxbulk = 20            // Number of objects that can be carried at once
  2180.     isactor = true          // flag that this is an actor
  2181.     roomCheck( v ) = { return( self.location.roomCheck(v)); }
  2182.     actorAction( v, d, p, i ) =
  2183.     {
  2184.         caps(); self.thedesc; " doesn't appear interested. ";
  2185.         exit;
  2186.     }
  2187.     isCarrying( obj ) = { return( obj.isIn( self )); }
  2188.     actorDesc =
  2189.     {
  2190.         caps(); self.adesc; " is here. ";
  2191.     }
  2192.     verGrab( item ) =
  2193.     {
  2194.         caps(); self.thedesc; " is carrying "; item.thedesc;
  2195.         " and won't let %youm% have it. ";
  2196.     }
  2197.     verDoFollow( actor ) =
  2198.     {
  2199.         "But "; self.thedesc; " is right here! ";
  2200.     }
  2201.     moveInto( obj ) =
  2202.     {
  2203.         if ( self.myfollower ) self.myfollower.moveInto( self.location );
  2204.     pass moveInto;
  2205.     }
  2206.     // these properties are for the format strings
  2207.     fmtYou = "he"
  2208.     fmtYour = "his"
  2209.     fmtYoure = "he's"
  2210.     fmtYoum = "him"
  2211.     fmtYouve = "he's"
  2212.     fmtS = "s"
  2213.     fmtEs = "es"
  2214.     fmtHave = "has"
  2215.     fmtDo = "does"
  2216.     fmtAre = "is"
  2217.     fmtMe = { self.thedesc; }
  2218.     askWord(word, lst) = { return(nil); }
  2219.     verDoAskAbout(actor, iobj) = {}
  2220.     doAskAbout(actor, iobj) =
  2221.     {
  2222.     local lst, i, tot;
  2223.  
  2224.     lst := objwords(2);       // get actual words asked about
  2225.     tot := length(lst);
  2226.     if ((tot = 1 and (find(['it' 'them' 'him' 'her'], lst[1]) <> nil))
  2227.         or tot = 0)
  2228.     {
  2229.         "\"Could you be more specific?\"";
  2230.         return;
  2231.     }
  2232.  
  2233.     // try to find a response for each word
  2234.     for (i := 1 ; i <= tot ; ++i)
  2235.     {
  2236.         if (self.askWord(lst[i], lst))
  2237.             return;
  2238.         }
  2239.  
  2240.     // didn't find anything to talk about
  2241.     self.disavow;
  2242.     }
  2243.     disavow = "\"I don't know much about that.\""
  2244.     verIoPutIn(actor) =
  2245.     {
  2246.         "If you want to give that to << thedesc >>, just say so.";
  2247.     }
  2248.     verIoGiveTo(actor) =
  2249.     {
  2250.     if (actor = self)
  2251.         "That wouldn't accomplish anything!";
  2252.     }
  2253.     ioGiveTo(actor, dobj) =
  2254.     {
  2255.     "\^<<self.thedesc>> rejects the offer.";
  2256.     }
  2257.  
  2258.     // move to a new location, notifying player of coming and going
  2259.     travelTo(room) =
  2260.     {
  2261.     /* do nothing if going nowhere */
  2262.     if (room = nil) return;
  2263.     
  2264.         /* notify player if leaving player's location (and it's not dark) */
  2265.         if (self.location = Me.location and self.location.islit)
  2266.             self.sayLeaving;
  2267.  
  2268.         /* move to my new location */
  2269.         self.moveInto(room);
  2270.  
  2271.         /* notify player if arriving at player's location */
  2272.         if (self.location = Me.location and self.location.islit)
  2273.             self.sayArriving;
  2274.     }
  2275.  
  2276.     // sayLeaving and sayArriving announce the actor's departure and arrival
  2277.     // in the same room as the player.
  2278.     sayLeaving = "\n\t\^<<self.thedesc>> leaves the area."
  2279.     sayArriving = "\n\t\^<<self.thedesc>> enters the area."
  2280.  
  2281.     // this should be used as an actor when ambiguous
  2282.     preferredActor = true
  2283. ;
  2284.  
  2285. /*
  2286.  *  follower: Actor
  2287.  *
  2288.  *  This is a special object that can "shadow" the movements of a
  2289.  *  character as it moves from room to room.  The purpose of a follower
  2290.  *  is to allow the player to follow an actor as it leaves a room by
  2291.  *  typing a "follow" command.  Each actor that is to be followed must
  2292.  *  have its own follower object.  The follower object should
  2293.  *  define all of the same vocabulary words (nouns and adjectives) as the
  2294.  *  actual actor to which it refers.  The follower must also
  2295.  *  define the myactor property to be the Actor object that
  2296.  *  the follower follows.  The follower will always stay
  2297.  *  one room behind the character it follows; no commands are effective
  2298.  *  with a follower except for "follow."
  2299.  */
  2300. class follower: Actor
  2301.     sdesc = { self.myactor.sdesc; }
  2302.     isfollower = true
  2303.     ldesc = { caps(); self.thedesc; " is no longer here. "; }
  2304.     actorAction( v, d, p, i ) = { self.ldesc; exit; }
  2305.     actorDesc = {}
  2306.     myactor = nil   // set to the Actor to be followed
  2307.     verDoFollow( actor ) = {}
  2308.     doFollow( actor ) =
  2309.     {
  2310.         actor.travelTo( self.myactor.location );
  2311.     }
  2312.     dobjGen(a, v, i, p) =
  2313.     {
  2314.         if (v <> followVerb)
  2315.     {
  2316.         "\^<< self.myactor.thedesc >> is no longer here.";
  2317.         exit;
  2318.     }
  2319.     }
  2320.     iobjGen(a, v, d, p) =
  2321.     {
  2322.         "\^<< self.myactor.thedesc >> is no longer here.";
  2323.     exit;
  2324.     }
  2325. ;
  2326.  
  2327. /*
  2328.  *  basicMe: Actor
  2329.  *
  2330.  *  A default implementation of the Me object, which is the
  2331.  *  player character.  adv.t defines basicMe instead of
  2332.  *  Me to allow your game to override parts of the default
  2333.  *  implementation while still using the rest, and without changing
  2334.  *  adv.t itself.  To use basicMe unchanged as your player
  2335.  *  character, include this in your game:  "Me: basicMe;".
  2336.  *  
  2337.  *  The basicMe object defines all of the methods and properties
  2338.  *  required for an actor, with appropriate values for the player
  2339.  *  character.  The nouns "me" and "myself'' are defined ("I''
  2340.  *  is not defined, because it conflicts with the "inventory"
  2341.  *  command's minimal abbreviation of "i" in certain circumstances,
  2342.  *  and is generally not compatible with the syntax of most player
  2343.  *  commands anyway).  The sdesc is "you"; the thedesc
  2344.  *  and adesc are "yourself," which is appropriate for most
  2345.  *  contexts.  The maxbulk and maxweight properties are
  2346.  *  set to 10 each; a more sophisticated Me might include the
  2347.  *  player's state of health in determining the maxweight and
  2348.  *  maxbulk properties.
  2349.  */
  2350. class basicMe: Actor, floatingItem
  2351.     roomCheck( v ) = { return( self.location.roomCheck( v )); }
  2352.     noun = 'me' 'myself'
  2353.     sdesc = "you"
  2354.     thedesc = "yourself"
  2355.     adesc = "yourself"
  2356.     ldesc = "You look about the same as always. "
  2357.     maxweight = 10
  2358.     maxbulk = 10
  2359.     verDoFollow( actor ) =
  2360.     {
  2361.         if ( actor = self ) "You can't follow yourself! ";
  2362.     }
  2363.     actorAction( verb, dobj, prep, iobj ) = 
  2364.     {
  2365.     }
  2366.     travelTo( room ) =
  2367.     {
  2368.         if ( room )
  2369.         {
  2370.         if ( room.isobstacle )
  2371.         {
  2372.             self.travelTo( room.destination );
  2373.         }
  2374.         else if ( not ( self.location.islit or room.islit ))
  2375.         {
  2376.             darkTravel();
  2377.         }
  2378.         else
  2379.         {
  2380.                 if ( self.location ) self.location.leaveRoom( self );
  2381.                 self.location := room;
  2382.                 room.enterRoom( self );
  2383.         }
  2384.         }
  2385.     }
  2386.     moveInto( room ) =
  2387.     {
  2388.         self.location := room;
  2389.     }
  2390.     ioGiveTo(actor, dobj) =
  2391.     {
  2392.     "You accept <<dobj.thedesc>> from <<actor.thedesc>>.";
  2393.     dobj.moveInto(Me);
  2394.     }
  2395.  
  2396.     // these properties are for the format strings
  2397.     fmtYou = "you"
  2398.     fmtYour = "your"
  2399.     fmtYoure = "you're"
  2400.     fmtYoum = "you"
  2401.     fmtYouve = "you've"
  2402.     fmtS = ""
  2403.     fmtEs = ""
  2404.     fmtHave = "have"
  2405.     fmtDo = "do"
  2406.     fmtAre = "are"
  2407.     fmtMe = "me"
  2408. ;
  2409.  
  2410. /*
  2411.  *  decoration: fixeditem
  2412.  *
  2413.  *  An item that doesn't have any function in the game, apart from
  2414.  *  having been mentioned in the room description.  These items
  2415.  *  are immovable and can't be manipulated in any way, but can be
  2416.  *  referred to and inspected.  Liberal use of decoration items
  2417.  *  can improve a game's playability by helping the parser recognize
  2418.  *  all the words the game uses in its descriptions of rooms.
  2419.  */
  2420. class decoration: fixeditem
  2421.     ldesc = "That's not important."
  2422.     dobjGen(a, v, i, p) =
  2423.     {
  2424.         if (v <> inspectVerb)
  2425.     {
  2426.         "\^<<self.thedesc>> isn't important.";
  2427.         exit;
  2428.     }
  2429.     }
  2430.     iobjGen(a, v, d, p) =
  2431.     {
  2432.         "\^<<self.thedesc>> isn't important.";
  2433.     exit;
  2434.     }
  2435. ;
  2436.  
  2437. /*
  2438.  *  distantItem: fixeditem
  2439.  *
  2440.  *  This is an item that is too far away to manipulate, but can be seen.
  2441.  *  The class uses dobjGen and iobjGen to prevent any verbs from being
  2442.  *  used on the object apart from inspectVerb; using any other verb results
  2443.  *  in the message "It's too far away."  Instances of this class should
  2444.  *  provide the normal item properties:  sdesc, ldesc, location,
  2445.  *  and vocabulary.
  2446.  */
  2447. class distantItem: fixeditem
  2448.     dobjGen(a, v, i, p) =
  2449.     {
  2450.         if (v <> inspectVerb)
  2451.         {
  2452.             "It's too far away.";
  2453.             exit;
  2454.         }
  2455.     }
  2456.     iobjGen(a, v, d, p) = { self.dobjGen(a, v, d, p); }
  2457. ;
  2458.  
  2459. /*
  2460.  *  buttonitem: fixeditem
  2461.  *
  2462.  *  A button (the type you push).  The individual button's action method
  2463.  *  doPush(actor), which must be specified in
  2464.  *  the button, carries out the function of the button.  Note that
  2465.  *  all buttons have the noun "button" defined.
  2466.  */
  2467. class buttonitem: fixeditem
  2468.     noun = 'button'
  2469.     plural = 'buttons'
  2470.     verDoPush( actor ) = {}
  2471. ;
  2472.  
  2473. /*
  2474.  *  clothingItem: item
  2475.  *
  2476.  *  Something that can be worn.  By default, the only thing that
  2477.  *  happens when the item is worn is that its isworn property
  2478.  *  is set to true.  If you want more to happen, override the
  2479.  *  doWear(actor) property.  Note that, when a clothingItem
  2480.  *  is being worn, certain operations will cause it to be removed (for
  2481.  *  example, dropping it causes it to be removed).  If you want
  2482.  *  something else to happen, override the checkDrop method;
  2483.  *  if you want to disallow such actions while the object is worn,
  2484.  *  use an exit statement in the checkDrop method.
  2485.  */
  2486. class clothingItem: item
  2487.     checkDrop =
  2488.     {
  2489.         if ( self.isworn )
  2490.     {
  2491.         "(Taking off "; self.thedesc; " first)\n";
  2492.         self.isworn := nil;
  2493.     }
  2494.     }
  2495.     doDrop( actor ) =
  2496.     {
  2497.         self.checkDrop;
  2498.     pass doDrop;
  2499.     }
  2500.     doPutIn( actor, io ) =
  2501.     {
  2502.         self.checkDrop;
  2503.     pass doPutIn;
  2504.     }
  2505.     doPutOn( actor, io ) =
  2506.     {
  2507.         self.checkDrop;
  2508.     pass doPutOn;
  2509.     }
  2510.     doGiveTo( actor, io ) =
  2511.     {
  2512.         self.checkDrop;
  2513.     pass doGiveTo;
  2514.     }
  2515.     doThrowAt( actor, io ) =
  2516.     {
  2517.         self.checkDrop;
  2518.     pass doThrowAt;
  2519.     }
  2520.     doThrowTo( actor, io ) =
  2521.     {
  2522.         self.checkDrop;
  2523.     pass doThrowTo;
  2524.     }
  2525.     doThrow( actor ) =
  2526.     {
  2527.         self.checkDrop;
  2528.     pass doThrow;
  2529.     }
  2530.     moveInto( obj ) =
  2531.     {
  2532.         /*
  2533.      *   Catch any other movements with moveInto; this won't stop the
  2534.      *   movement from happening, but it will prevent any anamolous
  2535.      *   consequences caused by the object moving but still being worn.
  2536.      */
  2537.         self.isworn := nil;
  2538.     pass moveInto;
  2539.     }
  2540.     verDoWear( actor ) =
  2541.     {
  2542.         if ( self.isworn )
  2543.         {
  2544.             "%You're% already wearing "; self.thedesc; "! ";
  2545.         }
  2546.         else if ( not actor.isCarrying( self ))
  2547.         {
  2548.             "%You% %do%n't have "; self.thedesc; ". ";
  2549.         }
  2550.     }
  2551.     doWear( actor ) =
  2552.     {
  2553.         "Okay, %you're% now wearing "; self.thedesc; ". ";
  2554.         self.isworn := true;
  2555.     }
  2556.     verDoUnwear( actor ) =
  2557.     {
  2558.         if ( not self.isworn )
  2559.         {
  2560.             "%You're% not wearing "; self.thedesc; ". ";
  2561.         }
  2562.     }
  2563.     verDoTake(actor) =
  2564.     {
  2565.         if (self.isworn) self.verDoUnwear(actor);
  2566.     else pass verDoTake;
  2567.     }
  2568.     doTake(actor) =
  2569.     {
  2570.         if (self.isworn) self.doUnwear(actor);
  2571.     else pass doTake;
  2572.     }
  2573.     doUnwear( actor ) =
  2574.     {
  2575.         "Okay, %you're% no longer wearing "; self.thedesc; ". ";
  2576.         self.isworn := nil;
  2577.     }
  2578.     doSynonym('Unwear') = 'Unboard'
  2579. ;
  2580.  
  2581. /*
  2582.  *  obstacle: object
  2583.  *
  2584.  *  An obstacle is used in place of a room for a direction
  2585.  *  property.  The destination property specifies the room that
  2586.  *  is reached if the obstacle is successfully negotiated; when the
  2587.  *  obstacle is not successfully negotiated, destination should
  2588.  *  display an appropriate message and return nil.
  2589.  */
  2590. class obstacle: object
  2591.     isobstacle = true
  2592. ;
  2593.  
  2594. /*
  2595.  *  doorway: fixeditem, obstacle
  2596.  *
  2597.  *  A doorway is an obstacle that impedes progress when it is closed.
  2598.  *  When the door is open (isopen is true), the user ends up in
  2599.  *  the room specified in the doordest property upon going through
  2600.  *  the door.  Since a doorway is an obstacle, use the door object for
  2601.  *  a direction property of the room containing the door.
  2602.  *  
  2603.  *  If noAutoOpen is not set to true, the door will automatically
  2604.  *  be opened when the player tries to walk through the door, unless the
  2605.  *  door is locked (islocked = true).  If the door is locked,
  2606.  *  it can be unlocked simply by typing "unlock door", unless the
  2607.  *  mykey property is set, in which case the object specified in
  2608.  *  mykey must be used to unlock the door.  Note that the door can
  2609.  *  only be relocked by the player under the circumstances that allow
  2610.  *  unlocking, plus the property islockable must be set to true.
  2611.  *  By default, the door is closed; set isopen to true if the door
  2612.  *  is to start out open (and be sure to open the other side as well).
  2613.  *  
  2614.  *  otherside specifies the corresponding doorway object in the
  2615.  *  destination room (doordest), if any.  If otherside is
  2616.  *  specified, its isopen and islocked properties will be
  2617.  *  kept in sync automatically.
  2618.  */
  2619. class doorway: fixeditem, obstacle
  2620.     isdoor = true           // Item can be opened and closed
  2621.     destination =
  2622.     {
  2623.         if ( self.isopen ) return( self.doordest );
  2624.     else if ( not self.islocked and not self.noAutoOpen )
  2625.     {
  2626.         self.isopen := true;
  2627.         if ( self.otherside ) self.otherside.isopen := true;
  2628.         "(Opening << self.thedesc >>)\n";
  2629.         return( self.doordest );
  2630.     }
  2631.     else
  2632.     {
  2633.         "%You%'ll have to open << self.thedesc >> first. ";
  2634.         setit( self );
  2635.         return( nil );
  2636.     }
  2637.     }
  2638.     verDoOpen( actor ) =
  2639.     {
  2640.         if ( self.isopen ) "It's already open. ";
  2641.     else if ( self.islocked ) "It's locked. ";
  2642.     }
  2643.     doOpen( actor ) =
  2644.     {
  2645.         "Opened. ";
  2646.     self.isopen := true;
  2647.     if ( self.otherside ) self.otherside.isopen := true;
  2648.     }
  2649.     verDoClose( actor ) =
  2650.     {
  2651.         if ( not self.isopen ) "It's already closed. ";
  2652.     }
  2653.     doClose( actor ) =
  2654.     {
  2655.         "Closed. ";
  2656.     self.isopen := nil;
  2657.     if ( self.otherside ) self.otherside.isopen := nil;
  2658.     }
  2659.     verDoLock( actor ) =
  2660.     {
  2661.         if ( self.islocked ) "It's already locked! ";
  2662.     else if ( not self.islockable ) "It can't be locked. ";
  2663.     else if ( self.isopen ) "%You%'ll have to close it first. ";
  2664.     }
  2665.     doLock( actor ) =
  2666.     {
  2667.         if ( self.mykey = nil )
  2668.     {
  2669.         "Locked. ";
  2670.         self.islocked := true;
  2671.         if ( self.otherside ) self.otherside.islocked := true;
  2672.     }
  2673.     else
  2674.             askio( withPrep );
  2675.     }
  2676.     verDoUnlock( actor ) =
  2677.     {
  2678.         if ( not self.islocked ) "It's not locked! ";
  2679.     }
  2680.     doUnlock( actor ) =
  2681.     {
  2682.         if ( self.mykey = nil )
  2683.     {
  2684.         "Unlocked. ";
  2685.         self.islocked := nil;
  2686.         if ( self.otherside ) self.otherside.islocked := nil;
  2687.     }
  2688.     else
  2689.         askio( withPrep );
  2690.     }
  2691.     verDoLockWith( actor, io ) =
  2692.     {
  2693.         if ( self.islocked ) "It's already locked. ";
  2694.     else if ( not self.islockable ) "It can't be locked. ";
  2695.     else if ( self.mykey = nil )
  2696.         "%You% %do%n't need anything to lock it. ";
  2697.     else if ( self.isopen ) "%You%'ll have to close it first. ";
  2698.     }
  2699.     doLockWith( actor, io ) =
  2700.     {
  2701.         if ( io = self.mykey )
  2702.     {
  2703.         "Locked. ";
  2704.         self.islocked := true;
  2705.         if ( self.otherside ) self.otherside.islocked := true;
  2706.     }
  2707.     else "It doesn't fit the lock. ";
  2708.     }
  2709.     verDoUnlockWith( actor, io ) =
  2710.     {
  2711.         if ( not self.islocked ) "It's not locked! ";
  2712.     else if ( self.mykey = nil )
  2713.         "%You% %do%n't need anything to unlock it. ";
  2714.     }
  2715.     doUnlockWith( actor, io ) =
  2716.     {
  2717.         if ( io = self.mykey )
  2718.     {
  2719.         "Unlocked. ";
  2720.         self.islocked := nil;
  2721.         if ( self.otherside ) self.otherside.islocked := nil;
  2722.     }
  2723.     else "It doesn't fit the lock. ";
  2724.     }
  2725.     ldesc =
  2726.     {
  2727.     if ( self.isopen ) "It's open. ";
  2728.     else
  2729.     {
  2730.         if ( self.islocked ) "It's closed and locked. ";
  2731.         else "It's closed. ";
  2732.     }
  2733.     }
  2734. ;
  2735.  
  2736. /*
  2737.  *  lockableDoorway: doorway
  2738.  *
  2739.  *  This is just a normal doorway with the islockable and
  2740.  *  islocked properties set to true.  Fill in the other
  2741.  *  properties (otherside and doordest) as usual.  If
  2742.  *  the door has a key, set property mykey to the key object.
  2743.  */
  2744. class lockableDoorway: doorway
  2745.     islockable = true
  2746.     islocked = true
  2747. ;
  2748.  
  2749. /*
  2750.  *  vehicle: item, nestedroom
  2751.  *
  2752.  *  This is an object that an actor can board.  An actor cannot go
  2753.  *  anywhere while on board a vehicle (except where the vehicle goes);
  2754.  *  the actor must get out first.
  2755.  */
  2756. class vehicle: item, nestedroom
  2757.     reachable = ([] + self)
  2758.     isvehicle = true
  2759.     verDoEnter( actor ) = { self.verDoBoard( actor ); }
  2760.     doEnter( actor ) = { self.doBoard( actor ); }
  2761.     verDoBoard( actor ) =
  2762.     {
  2763.         if ( actor.location = self )
  2764.         {
  2765.             "%You're% already in "; self.thedesc; "! ";
  2766.         }
  2767.     else if (actor.isCarrying(self))
  2768.     {
  2769.         "%You%'ll have to drop <<thedesc>> first!";
  2770.     }
  2771.     }
  2772.     doBoard( actor ) =
  2773.     {
  2774.         "Okay, %you're% now in "; self.thedesc; ". ";
  2775.         actor.moveInto( self );
  2776.     }
  2777.     noexit =
  2778.     {
  2779.         "%You're% not going anywhere until %you% get%s% out of ";
  2780.       self.thedesc; ". ";
  2781.         return( nil );
  2782.     }
  2783.     out = ( self.location )
  2784.     verDoTake(actor) =
  2785.     {
  2786.         if (actor.isIn(self))
  2787.         "%You%'ll have to get <<self.outOfPrep>> <<self.thedesc>> first.";
  2788.     else
  2789.         pass verDoTake;
  2790.     }
  2791.     dobjGen(a, v, i, p) =
  2792.     {
  2793.         if (a.isIn(self) and v <> inspectVerb and v <> getOutVerb
  2794.         and v <> outVerb)
  2795.     {
  2796.         "%You%'ll have to get out of << thedesc >> first.";
  2797.         exit;
  2798.     }
  2799.     }
  2800.     iobjGen(a, v, d, p) =
  2801.     {
  2802.         if (a.isIn(self) and v <> putVerb)
  2803.     {
  2804.         "%You%'ll have to get out of << thedesc >> first.";
  2805.         exit;
  2806.     }
  2807.     }
  2808. ;
  2809.  
  2810. /*
  2811.  *  surface: item
  2812.  *
  2813.  *  Objects can be placed on a surface.  Apart from using the
  2814.  *  preposition "on" rather than "in'' to refer to objects
  2815.  *  contained by the object, a surface is identical to a
  2816.  *  container.  Note: an object cannot be both a
  2817.  *  surface and a container, because there is no
  2818.  *  distinction between the two internally.
  2819.  */
  2820. class surface: item
  2821.     issurface = true        // Item can hold objects on its surface
  2822.     ldesc =
  2823.     {
  2824.         if (itemcnt( self.contents ))
  2825.         {
  2826.             "On "; self.thedesc; " %you% see%s% "; listcont( self ); ". ";
  2827.         }
  2828.         else
  2829.         {
  2830.             "There's nothing on "; self.thedesc; ". ";
  2831.         }
  2832.     }
  2833.     verIoPutOn( actor ) = {}
  2834.     ioPutOn( actor, dobj ) =
  2835.     {
  2836.         dobj.doPutOn( actor, self );
  2837.     }
  2838. ;
  2839.  
  2840. /*
  2841.  *  container: item
  2842.  *
  2843.  *  This object can contain other objects.  The iscontainer property
  2844.  *  is set to true.  The default ldesc displays a list of the
  2845.  *  objects inside the container, if any.  The maxbulk property
  2846.  *  specifies the maximum amount of bulk the container can contain.
  2847.  */
  2848. class container: item
  2849.     maxbulk = 10            // maximum bulk the container can contain
  2850.     isopen = true           // in fact, it can't be closed at all
  2851.     iscontainer = true      // Item can contain other items
  2852.     ldesc =
  2853.     {
  2854.         if ( self.contentsVisible and itemcnt( self.contents ) <> 0 )
  2855.         {
  2856.             "In "; self.thedesc; " %you% see%s% "; listcont( self ); ". ";
  2857.         }
  2858.         else
  2859.         {
  2860.             "There's nothing in "; self.thedesc; ". ";
  2861.         }
  2862.     }
  2863.     verIoPutIn( actor ) =
  2864.     {
  2865.     }
  2866.     ioPutIn( actor, dobj ) =
  2867.     {
  2868.         if (addbulk( self.contents ) + dobj.bulk > self.maxbulk )
  2869.         {
  2870.             "%You% can't fit that in "; self.thedesc; ". ";
  2871.         }
  2872.         else
  2873.         {
  2874.         dobj.doPutIn( actor, self );
  2875.         }
  2876.     }
  2877.     verDoLookin( actor ) = {}
  2878.     doLookin( actor ) =
  2879.     {
  2880.         self.ldesc;
  2881.     }
  2882. ;
  2883.  
  2884. /*
  2885.  *  openable: container
  2886.  *
  2887.  *  A container that can be opened and closed.  The isopenable
  2888.  *  property is set to true.  The default ldesc displays
  2889.  *  the contents of the container if the container is open, otherwise
  2890.  *  a message saying that the object is closed.
  2891.  */
  2892. class openable: container
  2893.     contentsReachable = { return( self.isopen ); }
  2894.     contentsVisible = { return( self.isopen ); }
  2895.     isopenable = true
  2896.     ldesc =
  2897.     {
  2898.         caps(); self.thedesc;
  2899.         if ( self.isopen )
  2900.     {
  2901.         " is open. ";
  2902.         pass ldesc;
  2903.     }
  2904.         else
  2905.     {
  2906.         " is closed. ";
  2907.  
  2908.         /* if it's transparent, list its contents anyway */
  2909.         if (isclass(self, transparentItem)) pass ldesc;
  2910.     }
  2911.     }
  2912.     isopen = true
  2913.     verDoOpen( actor ) =
  2914.     {
  2915.         if ( self.isopen )
  2916.     {
  2917.         caps(); self.thedesc; " is already open! ";
  2918.     }
  2919.     }
  2920.     doOpen( actor ) =
  2921.     {
  2922.         if (itemcnt( self.contents ))
  2923.     {
  2924.         "Opening "; self.thedesc; " reveals "; listcont( self ); ". ";
  2925.     }
  2926.     else "Opened. ";
  2927.     self.isopen := true;
  2928.     }
  2929.     verDoClose( actor ) =
  2930.     {
  2931.         if ( not self.isopen )
  2932.     {
  2933.         caps(); self.thedesc; " is already closed! ";
  2934.     }
  2935.     }
  2936.     doClose( actor ) =
  2937.     {
  2938.         "Closed. ";
  2939.     self.isopen := nil;
  2940.     }
  2941.     verIoPutIn( actor ) =
  2942.     {
  2943.         if ( not self.isopen )
  2944.     {
  2945.         caps(); self.thedesc; " is closed. ";
  2946.     }
  2947.     }
  2948.     verDoLookin( actor ) =
  2949.     {
  2950.         /* we can look in it if either it's open or it's transparent */
  2951.         if (not self.isopen and not isclass(self, transparentItem))
  2952.            "It's closed. ";
  2953.     }
  2954. ;
  2955.  
  2956. /*
  2957.  *  qcontainer: container
  2958.  *
  2959.  *  A "quiet" container:  its contents are not listed when it shows
  2960.  *  up in a room description or inventory list.  The isqcontainer
  2961.  *  property is set to true.
  2962.  */
  2963. class qcontainer: container
  2964.     isqcontainer = true
  2965. ;
  2966.  
  2967. /*
  2968.  *  lockable: openable
  2969.  *
  2970.  *  A container that can be locked and unlocked.  The islocked
  2971.  *  property specifies whether the object can be opened or not.  The
  2972.  *  object can be locked and unlocked without the need for any other
  2973.  *  object; if you want a key to be involved, use a keyedLockable.
  2974.  */
  2975. class lockable: openable
  2976.     verDoOpen( actor ) =
  2977.     {
  2978.         if ( self.islocked )
  2979.         {
  2980.             "It's locked. ";
  2981.         }
  2982.         else pass verDoOpen;
  2983.     }
  2984.     verDoLock( actor ) =
  2985.     {
  2986.         if ( self.islocked )
  2987.         {
  2988.             "It's already locked! ";
  2989.         }
  2990.     }
  2991.     doLock( actor ) =
  2992.     {
  2993.         if ( self.isopen )
  2994.         {
  2995.             "%You%'ll have to close "; self.thedesc; " first. ";
  2996.         }
  2997.         else
  2998.         {
  2999.             "Locked. ";
  3000.             self.islocked := true;
  3001.         }
  3002.     }
  3003.     verDoUnlock( actor ) =
  3004.     {
  3005.         if ( not self.islocked ) "It's not locked! ";
  3006.     }
  3007.     doUnlock( actor ) =
  3008.     {
  3009.         "Unlocked. ";
  3010.         self.islocked := nil;
  3011.     }
  3012.     verDoLockWith( actor, io ) =
  3013.     {
  3014.         if ( self.islocked ) "It's already locked. ";
  3015.     }
  3016.     verDoUnlockWith( actor, io ) =
  3017.     {
  3018.         if ( not self.islocked ) "It's not locked! ";
  3019.     }
  3020. ;
  3021.  
  3022. /*
  3023.  *  keyedLockable: lockable
  3024.  *
  3025.  *  This subclass of lockable allows you to create an object
  3026.  *  that can only be locked and unlocked with a corresponding key.
  3027.  *  Set the property mykey to the keyItem object that can
  3028.  *  lock and unlock the object.
  3029.  */
  3030. class keyedLockable: lockable
  3031.     mykey = nil     // set 'mykey' to the key which locks/unlocks me
  3032.     doLock( actor ) =
  3033.     {
  3034.         askio( withPrep );
  3035.     }
  3036.     doUnlock( actor ) =
  3037.     {
  3038.         askio( withPrep );
  3039.     }
  3040.     doLockWith( actor, io ) =
  3041.     {
  3042.         if ( self.isopen )
  3043.         {
  3044.             "%You% can't lock << self.thedesc >> when it's open. ";
  3045.         }
  3046.         else if ( io = self.mykey )
  3047.         {
  3048.             "Locked. ";
  3049.             self.islocked := true;
  3050.         }
  3051.         else "It doesn't fit the lock. ";
  3052.     }
  3053.     doUnlockWith( actor, io ) =
  3054.     {
  3055.         if ( io = self.mykey )
  3056.         {
  3057.             "Unlocked. ";
  3058.             self.islocked := nil;
  3059.         }
  3060.         else "It doesn't fit the lock. ";
  3061.     }
  3062. ;
  3063.  
  3064. /*
  3065.  *  keyItem: item
  3066.  *
  3067.  *  This is an object that can be used as a key for a keyedLockable
  3068.  *  or lockableDoorway object.  It otherwise behaves as an ordinary item.
  3069.  */
  3070. class keyItem: item
  3071.     verIoUnlockWith( actor ) = {}
  3072.     ioUnlockWith( actor, dobj ) =
  3073.     {
  3074.         dobj.doUnlockWith( actor, self );
  3075.     }
  3076.     verIoLockWith( actor ) = {}
  3077.     ioLockWith( actor, dobj ) =
  3078.     {
  3079.         dobj.doLockWith( actor, self );
  3080.     }
  3081. ;
  3082.  
  3083. /*
  3084.  *  seethruItem: item
  3085.  *
  3086.  *  This is an object that the player can look through, such as a window.
  3087.  *  The thrudesc method displays a message for when the player looks
  3088.  *  through the object (with a command such as "look through window").
  3089.  *  Note this is not the same as a transparentItem, whose contents
  3090.  *  are visible from outside the object.
  3091.  */
  3092. class seethruItem: item
  3093.     verDoLookthru(actor) = {}
  3094.     doLookthru(actor) = { self.thrudesc; }
  3095. ;
  3096.  
  3097.  
  3098. /*
  3099.  *  transparentItem: item
  3100.  *
  3101.  *  An object whose contents are visible, even when the object is
  3102.  *  closed.  Whether the contents are reachable is decided in the
  3103.  *  normal fashion.  This class is useful for items such as glass
  3104.  *  bottles, whose contents can be seen when the bottle is closed
  3105.  *  but cannot be reached.
  3106.  */
  3107. class transparentItem: item
  3108.     contentsVisible = { return( true ); }
  3109.     ldesc =
  3110.     {
  3111.         if (self.contentsVisible and itemcnt(self.contents) <> 0)
  3112.         {
  3113.             "In "; self.thedesc; " %you% see%s% "; listcont(self); ". ";
  3114.         }
  3115.         else
  3116.         {
  3117.             "There's nothing in "; self.thedesc; ". ";
  3118.         }
  3119.     }
  3120.     verGrab( obj ) =
  3121.     {
  3122.         if ( self.isopenable and not self.isopen )
  3123.             "%You% will have to open << self.thedesc >> first. ";
  3124.     }
  3125.     doOpen( actor ) =
  3126.     {
  3127.         self.isopen := true;
  3128.         "Opened. ";
  3129.     }
  3130.     verDoLookin(actor) = {}
  3131.     doLookin(actor) = { self.ldesc; }
  3132. ;
  3133.  
  3134. /*
  3135.  *  basicNumObj: object
  3136.  *
  3137.  *  This object provides a default implementation for numObj.
  3138.  *  To use this default unchanged in your game, include in your
  3139.  *  game this line:  "numObj: basicNumObj".
  3140.  */
  3141. class basicNumObj: object   // when a number is used in a player command,
  3142.     value = 0               //  this is set to its value
  3143.     sdesc = "<<value>>"
  3144.     adesc = "a number"
  3145.     thedesc = "the number <<value>>"
  3146.     verDoTypeOn( actor, io ) = {}
  3147.     doTypeOn( actor, io ) = { "\"Tap, tap, tap, tap...\" "; }
  3148.     verIoTurnTo( actor ) = {}
  3149.     ioTurnTo( actor, dobj ) = { dobj.doTurnTo( actor, self ); }
  3150. ;
  3151.  
  3152. /*
  3153.  *  basicStrObj: object
  3154.  *
  3155.  *  This object provides a default implementation for strObj.
  3156.  *  To use this default unchanged in your game, include in your
  3157.  *  game this line:  "strObj: basicStrObj".
  3158.  */
  3159. class basicStrObj: object   // when a string is used in a player command,
  3160.     value = ''              //  this is set to its value
  3161.     sdesc = "\"<<value>>\""
  3162.     adesc = "\"<<value>>\""
  3163.     thedesc = "\"<<value>>\""
  3164.     verDoTypeOn( actor, io ) = {}
  3165.     doTypeOn( actor, io ) = { "\"Tap, tap, tap, tap...\" "; }
  3166.     doSynonym('TypeOn') = 'EnterOn' 'EnterIn' 'EnterWith'
  3167.     verDoSave( actor ) = {}
  3168.     saveGame(actor) =
  3169.     {
  3170.         if (save( self.value ))
  3171.     {
  3172.             "Save failed. ";
  3173.         return nil;
  3174.     }
  3175.         else
  3176.     {
  3177.             "Saved. ";
  3178.         return true;
  3179.     }
  3180.     }
  3181.     doSave( actor ) =
  3182.     {
  3183.     self.saveGame(actor);
  3184.     abort;
  3185.     }
  3186.     verDoRestore( actor ) = {}
  3187.     restoreGame(actor) =
  3188.     {
  3189.         if (restore( self.value ))
  3190.     {
  3191.             "Restore failed. ";
  3192.         return nil;
  3193.     }
  3194.         else
  3195.     {
  3196.             "Restored.\b";
  3197.         scoreStatus( global.score, global.turnsofar );
  3198.         Me.location.lookAround(true);
  3199.         return true;
  3200.     }
  3201.     }
  3202.     doRestore( actor ) =
  3203.     {
  3204.     self.restoreGame(actor);
  3205.         abort;
  3206.     }
  3207.     verDoScript( actor ) = {}
  3208.     startScripting(actor) =
  3209.     {
  3210.         logging( self.value );
  3211.         "Writing script file. ";
  3212.     }
  3213.     doScript( actor ) =
  3214.     {
  3215.     self.startScripting(actor);
  3216.         abort;
  3217.     }
  3218.     verDoSay( actor ) = {}
  3219.     doSay( actor ) =
  3220.     {
  3221.         "Okay, \""; say( self.value ); "\".";
  3222.     }
  3223. ;
  3224.  
  3225. /*
  3226.  *  deepverb: object
  3227.  *
  3228.  *  A "verb object" that is referenced by the parser when the player
  3229.  *  uses an associated vocabulary word.  A deepverb contains both
  3230.  *  the vocabulary of the verb and a description of available syntax.
  3231.  *  The verb property lists the verb vocabulary words;
  3232.  *  one word (such as 'take') or a pair (such as 'pick up')
  3233.  *  can be used.  In the latter case, the second word must be a
  3234.  *  preposition, and may move to the end of the sentence in a player's
  3235.  *  command, as in "pick it up."  The action(actor)
  3236.  *  method specifies what happens when the verb is used without any
  3237.  *  objects; its absence specifies that the verb cannot be used without
  3238.  *  an object.  The doAction specifies the root of the message
  3239.  *  names (in single quotes) sent to the direct object when the verb
  3240.  *  is used with a direct object; its absence means that a single object
  3241.  *  is not allowed.  Likewise, the ioAction(preposition)
  3242.  *  specifies the root of the message name sent to the direct and
  3243.  *  indirect objects when the verb is used with both a direct and
  3244.  *  indirect object; its absence means that this syntax is illegal.
  3245.  *  Several ioAction properties may be present:  one for each
  3246.  *  preposition that can be used with an indirect object with the verb.
  3247.  *  
  3248.  *  The validDo(actor, object, seqno) method returns true
  3249.  *  if the indicated object is valid as a direct object for this actor.
  3250.  *  The validIo(actor, object, seqno) method does likewise
  3251.  *  for indirect objects.  The seqno parameter is a "sequence
  3252.  *  number," starting with 1 for the first object tried for a given
  3253.  *  verb, 2 for the second, and so forth; this parameter is normally
  3254.  *  ignored, but can be used for some special purposes.  For example,
  3255.  *  askVerb does not distinguish between objects matching vocabulary
  3256.  *  words, and therefore accepts only the first from a set of ambiguous
  3257.  *  objects.  These methods do not normally need to be changed; by
  3258.  *  default, they return true if the object is accessible to the
  3259.  *  actor.
  3260.  *  
  3261.  *  The doDefault(actor, prep, indirectObject) and
  3262.  *  ioDefault(actor, prep) methods return a list of the
  3263.  *  default direct and indirect objects, respectively.  These lists
  3264.  *  are used for determining which objects are meant by "all" and which
  3265.  *  should be used when the player command is missing an object.  These
  3266.  *  normally return a list of all objects that are applicable to the
  3267.  *  current command.
  3268.  *  
  3269.  *  The validDoList(actor, prep, indirectObject) and
  3270.  *  validIoList(actor, prep, directObject) methods return
  3271.  *  a list of all of the objects for which validDo would be true.
  3272.  *  Remember to include floating objects, which are generally
  3273.  *  accessible.  Note that the objects returned by this list will
  3274.  *  still be submitted by the parser to validDo, so it's okay for
  3275.  *  this routine to return too many objects.  In fact, this
  3276.  *  routine is entirely unnecessary; if you omit it altogether, or
  3277.  *  make it return nil, the parser will simply submit every
  3278.  *  object matching the player's vocabulary words to validDo.
  3279.  *  The reason to provide this method is that it can significantly
  3280.  *  improve parsing speed when the game has lots of objects that
  3281.  *  all have the same vocabulary word, because it cuts down on the
  3282.  *  number of times that validDo has to be called (each call
  3283.  *  to validDo is fairly time-consuming).
  3284.  */
  3285. class deepverb: object                // A deep-structure verb.
  3286.     validDo( actor, obj, seqno ) =
  3287.     {
  3288.         return( obj.isReachable( actor ));
  3289.     }
  3290.     validDoList(actor, prep, iobj) =
  3291.     {
  3292.     local ret;
  3293.     local loc;
  3294.  
  3295.     loc := actor.location;
  3296.     while (loc.location) loc := loc.location;
  3297.     ret := visibleList(actor) + visibleList(loc)
  3298.            + global.floatingList;
  3299.     return(ret);
  3300.     }
  3301.     validIo( actor, obj, seqno ) =
  3302.     {
  3303.         return( obj.isReachable( actor ));
  3304.     }
  3305.     validIoList(actor, prep, dobj) = (self.validDoList(actor, prep, dobj))
  3306.     doDefault( actor, prep, io ) =
  3307.     {
  3308.         return( actor.contents + actor.location.contents );
  3309.     }
  3310.     ioDefault( actor, prep ) =
  3311.     {
  3312.         return( actor.contents + actor.location.contents );
  3313.     }
  3314. ;
  3315.  
  3316. /*
  3317.    Dark verb - a verb that can be used in the dark.  Travel verbs
  3318.    are all dark verbs, as are system verbs (quit, save, etc.).
  3319.    In addition, certain special verbs are usable in the dark:  for
  3320.    example, you can drop objects you are carrying, and you can turn
  3321.    on light sources you are carrying. 
  3322. */
  3323.  
  3324. class darkVerb: deepverb
  3325.    isDarkVerb = true
  3326. ;
  3327.  
  3328. /*
  3329.  *   Various verbs.
  3330.  */
  3331. inspectVerb: deepverb
  3332.     verb = 'inspect' 'examine' 'look at' 'l at' 'x'
  3333.     sdesc = "inspect"
  3334.     doAction = 'Inspect'
  3335.     validDo( actor, obj, seqno ) =
  3336.     {
  3337.         return( obj.isVisible( actor ));
  3338.     }
  3339. ;
  3340. askVerb: deepverb
  3341.     verb = 'ask'
  3342.     sdesc = "ask"
  3343.     prepDefault = aboutPrep
  3344.     ioAction( aboutPrep ) = 'AskAbout'
  3345.     validIo( actor, obj, seqno ) = { return( seqno = 1 ); }
  3346.     validIoList(actor, prep, dobj) = (nil)
  3347. ;
  3348. tellVerb: deepverb
  3349.     verb = 'tell'
  3350.     sdesc = "tell"
  3351.     prepDefault = aboutPrep
  3352.     ioAction( aboutPrep ) = 'TellAbout'
  3353.     validIo( actor, obj, seqno ) = { return( seqno = 1 ); }
  3354.     validIoList(actor, prep, dobj) = (nil)
  3355.     ioDefault( actor, prep ) =
  3356.     {
  3357.         if (prep = aboutPrep)
  3358.         return([]);
  3359.     else
  3360.         return(actor.contents + actor.location.contents);
  3361.     }
  3362. ;
  3363. followVerb: deepverb
  3364.     sdesc = "follow"
  3365.     verb = 'follow'
  3366.     doAction = 'Follow'
  3367. ;
  3368. digVerb: deepverb
  3369.     verb = 'dig' 'dig in'
  3370.     sdesc = "dig in"
  3371.     prepDefault = withPrep
  3372.     ioAction( withPrep ) = 'DigWith'
  3373. ;
  3374. jumpVerb: deepverb
  3375.     verb = 'jump' 'jump over' 'jump off'
  3376.     sdesc = "jump"
  3377.     doAction = 'Jump'
  3378.     action(actor) = { "Wheeee!"; }
  3379. ;
  3380. pushVerb: deepverb
  3381.     verb = 'push' 'press'
  3382.     sdesc = "push"
  3383.     doAction = 'Push'
  3384. ;
  3385. attachVerb: deepverb
  3386.     verb = 'attach' 'connect'
  3387.     sdesc = "attach"
  3388.     prepDefault = toPrep
  3389.     ioAction( toPrep ) = 'AttachTo'
  3390. ;
  3391. wearVerb: deepverb
  3392.     verb = 'wear' 'put on'
  3393.     sdesc = "wear"
  3394.     doAction = 'Wear'
  3395. ;
  3396. dropVerb: deepverb, darkVerb
  3397.     verb = 'drop' 'put down'
  3398.     sdesc = "drop"
  3399.     ioAction( onPrep ) = 'PutOn'
  3400.     doAction = 'Drop'
  3401.     doDefault( actor, prep, io ) =
  3402.     {
  3403.         return( actor.contents );
  3404.     }
  3405. ;
  3406. removeVerb: deepverb
  3407.     verb = 'take off'
  3408.     sdesc = "take off"
  3409.     doAction = 'Unwear'
  3410.     ioAction( fromPrep ) = 'RemoveFrom'
  3411. ;
  3412. openVerb: deepverb
  3413.     verb = 'open'
  3414.     sdesc = "open"
  3415.     doAction = 'Open'
  3416. ;
  3417. closeVerb: deepverb
  3418.     verb = 'close'
  3419.     sdesc = "close"
  3420.     doAction = 'Close'
  3421. ;
  3422. putVerb: deepverb
  3423.     verb = 'put' 'place'
  3424.     sdesc = "put"
  3425.     prepDefault = inPrep
  3426.     ioAction( inPrep ) = 'PutIn'
  3427.     ioAction( onPrep ) = 'PutOn'
  3428.     doDefault( actor, prep, io ) =
  3429.     {
  3430.         return( takeVerb.doDefault( actor, prep, io ) + actor.contents );
  3431.     }
  3432. ;
  3433. takeVerb: deepverb                   // This object defines how to take things
  3434.     verb = 'take' 'pick up' 'get' 'remove'
  3435.     sdesc = "take"
  3436.     ioAction( offPrep ) = 'TakeOff'
  3437.     ioAction( outPrep ) = 'TakeOut'
  3438.     ioAction( fromPrep ) = 'TakeOut'
  3439.     ioAction( inPrep ) = 'TakeOut'
  3440.     ioAction( onPrep ) = 'TakeOff'
  3441.     doAction = 'Take'
  3442.     doDefault( actor, prep, io ) =
  3443.     {
  3444.         local ret, rem, cur, rem2, cur2, tot, i, tot2, j;
  3445.     
  3446.     ret := [];
  3447.         
  3448.     /*
  3449.      *   For "take all out/off of <iobj>", return the (non-fixed)
  3450.      *   contents of the indirect object.  Same goes for "take all in
  3451.      *   <iobj>", "take all on <iobj>", and "take all from <iobj>".
  3452.      */
  3453.     if (( prep=outPrep or prep=offPrep or prep=inPrep or prep=onPrep
  3454.      or prep=fromPrep ) and io<>nil )
  3455.     {
  3456.         rem := io.contents;
  3457.         i := 1;
  3458.         tot := length( rem );
  3459.         while ( i <= tot )
  3460.         {
  3461.             cur := rem[i];
  3462.             if (not cur.isfixed and self.validDo(actor, cur, i))
  3463.             ret += cur;
  3464.         ++i;
  3465.         }
  3466.             return( ret );
  3467.     }
  3468.  
  3469.         /*
  3470.      *   In the general case, return everything that's not fixed
  3471.      *   in the actor's location, or everything inside fixed containers
  3472.      *   that isn't itself fixed.
  3473.      */
  3474.         rem := actor.location.contents;
  3475.     tot := length( rem );
  3476.     i := 1;
  3477.         while ( i <= tot )
  3478.         {
  3479.         cur := rem[i];
  3480.             if ( cur.isfixed )
  3481.             {
  3482.                 if ((( cur.isopenable and cur.isopen ) or
  3483.                   ( not cur.isopenable )) and ( not cur.isactor ))
  3484.                 {
  3485.                     rem2 := cur.contents;
  3486.             tot2 := length( rem2 );
  3487.             j := 1;
  3488.                     while ( j <= tot2 )
  3489.                     {
  3490.                 cur2 := rem2[j];
  3491.                         if ( not cur2.isfixed and not cur2.notakeall )
  3492.             {
  3493.                 ret := ret + cur2;
  3494.             }
  3495.                         j := j + 1;
  3496.                     }
  3497.                 }
  3498.             }
  3499.             else if ( not cur.notakeall )
  3500.         {
  3501.             ret := ret + cur;
  3502.         }
  3503.  
  3504.         i := i + 1;            
  3505.         }
  3506.         return( ret );
  3507.     }
  3508. ;
  3509. plugVerb: deepverb
  3510.     verb = 'plug'
  3511.     sdesc = "plug"
  3512.     prepDefault = inPrep
  3513.     ioAction( inPrep ) = 'PlugIn'
  3514. ;
  3515. lookInVerb: deepverb
  3516.     verb = 'look in' 'look on' 'l in' 'l on'
  3517.     sdesc = "look in"
  3518.     doAction = 'Lookin'
  3519. ;
  3520. screwVerb: deepverb
  3521.     verb = 'screw'
  3522.     sdesc = "screw"
  3523.     ioAction( withPrep ) = 'ScrewWith'
  3524.     doAction = 'Screw'
  3525. ;
  3526. unscrewVerb: deepverb
  3527.     verb = 'unscrew'
  3528.     sdesc = "unscrew"
  3529.     ioAction( withPrep ) = 'UnscrewWith'
  3530.     doAction = 'Unscrew'
  3531. ;
  3532. turnVerb: deepverb
  3533.     verb = 'turn' 'rotate' 'twist'
  3534.     sdesc = "turn"
  3535.     ioAction( toPrep ) = 'TurnTo'
  3536.     ioAction( withPrep ) = 'TurnWith'
  3537.     doAction = 'Turn'
  3538. ;
  3539. switchVerb: deepverb
  3540.     verb = 'switch'
  3541.     sdesc = "switch"
  3542.     doAction = 'Switch'
  3543. ;
  3544. flipVerb: deepverb
  3545.     verb = 'flip'
  3546.     sdesc = "flip"
  3547.     doAction = 'Flip'
  3548. ;
  3549. turnOnVerb: deepverb, darkVerb
  3550.     verb = 'activate' 'turn on' 'switch on'
  3551.     sdesc = "turn on"
  3552.     doAction = 'Turnon'
  3553. ;
  3554. turnOffVerb: deepverb
  3555.     verb = 'turn off' 'deactiv' 'switch off'
  3556.     sdesc = "turn off"
  3557.     doAction = 'Turnoff'
  3558. ;
  3559. lookVerb: deepverb
  3560.     verb = 'look' 'l' 'look around' 'l around'
  3561.     sdesc = "look"
  3562.     action( actor ) =
  3563.     {
  3564.         actor.location.lookAround( true );
  3565.     }
  3566. ;
  3567. sitVerb: deepverb
  3568.     verb = 'sit on' 'sit in' 'sit' 'sit down' 'sit downin' 'sit downon'
  3569.     sdesc = "sit on"
  3570.     doAction = 'Siton'
  3571. ;
  3572. lieVerb: deepverb
  3573.     verb = 'lie' 'lie on' 'lie in' 'lie down' 'lie downon' 'lie downin'
  3574.     sdesc = "lie on"
  3575.     doAction = 'Lieon'
  3576. ;
  3577. getOutVerb: deepverb
  3578.     verb = 'get out' 'get outof' 'get off' 'get offof'
  3579.     sdesc = "get out of"
  3580.     doAction = 'Unboard'
  3581.     action(actor) = { askdo; }
  3582.     doDefault( actor, prep, io ) =
  3583.     {
  3584.         if ( actor.location and actor.location.location )
  3585.             return( [] + actor.location );
  3586.         else return( [] );
  3587.     }
  3588. ;
  3589. boardVerb: deepverb
  3590.     verb = 'get in' 'get into' 'board' 'get on'
  3591.     sdesc = "get on"
  3592.     doAction = 'Board'
  3593. ;
  3594. againVerb: darkVerb         // Required verb:  repeats last command.  No
  3595.                             // action routines are necessary; this one's
  3596.                             // handled internally by the parser.
  3597.     verb = 'again' 'g'
  3598. ;
  3599. waitVerb: darkVerb
  3600.     verb = 'wait' 'z'
  3601.     action( actor ) =
  3602.     {
  3603.         "Time passes...\n";
  3604.     }
  3605. ;
  3606. iVerb: deepverb
  3607.     verb = 'inventory' 'i'
  3608.     action( actor ) =
  3609.     {
  3610.         if (length( actor.contents ))
  3611.         {
  3612.             "%You% %have% "; listcont( actor ); ". ";
  3613.             listcontcont( actor );
  3614.         }
  3615.     else
  3616.             "%You% %are% empty-handed.\n";
  3617.     }
  3618. ;
  3619. lookThruVerb: deepverb
  3620.     verb = 'look through' 'look thru' 'l through' 'l thru'
  3621.     sdesc = "look through"
  3622.     doAction = 'Lookthru'
  3623. ;
  3624. breakVerb: deepverb
  3625.     verb = 'break' 'ruin' 'destroy'
  3626.     sdesc = "break"
  3627.     doAction = 'Break'
  3628. ;
  3629. attackVerb: deepverb
  3630.     verb = 'attack' 'kill' 'hit'
  3631.     sdesc = "attack"
  3632.     prepDefault = withPrep
  3633.     ioAction( withPrep ) = 'AttackWith'
  3634. ;
  3635. climbVerb: deepverb
  3636.     verb = 'climb'
  3637.     sdesc = "climb"
  3638.     doAction = 'Climb'
  3639. ;
  3640. eatVerb: deepverb
  3641.     verb = 'eat' 'consume'
  3642.     sdesc = "eat"
  3643.     doAction = 'Eat'
  3644. ;
  3645. drinkVerb: deepverb
  3646.     verb = 'drink'
  3647.     sdesc = "drink"
  3648.     doAction = 'Drink'
  3649. ;
  3650. giveVerb: deepverb
  3651.     verb = 'give' 'offer'
  3652.     sdesc = "give"
  3653.     prepDefault = toPrep
  3654.     ioAction( toPrep ) = 'GiveTo'
  3655.     doDefault( actor, prep, io ) =
  3656.     {
  3657.         return( actor.contents );
  3658.     }
  3659. ;
  3660. pullVerb: deepverb
  3661.     verb = 'pull'
  3662.     sdesc = "pull"
  3663.     doAction = 'Pull'
  3664. ;
  3665. readVerb: deepverb
  3666.     verb = 'read'
  3667.     sdesc = "read"
  3668.     doAction = 'Read'
  3669. ;
  3670. throwVerb: deepverb
  3671.     verb = 'throw' 'toss'
  3672.     sdesc = "throw"
  3673.     prepDefault = atPrep
  3674.     ioAction( atPrep ) = 'ThrowAt'
  3675.     ioAction( toPrep ) = 'ThrowTo'
  3676. ;
  3677. standOnVerb: deepverb
  3678.     verb = 'stand on'
  3679.     sdesc = "stand on"
  3680.     doAction = 'Standon'
  3681. ;
  3682. standVerb: deepverb
  3683.     verb = 'stand' 'stand up' 'get up'
  3684.     sdesc = "stand"
  3685.     action( actor ) =
  3686.     {
  3687.         if ( actor.location=nil or actor.location.location = nil )
  3688.             "%You're% already standing! ";
  3689.         else
  3690.         {
  3691.         actor.location.doUnboard( actor );
  3692.         }
  3693.     }
  3694. ;
  3695. helloVerb: deepverb
  3696.     verb = 'hello' 'hi' 'greetings'
  3697.     action( actor ) =
  3698.     {
  3699.         "Nice weather we've been having.\n";
  3700.     }
  3701. ;
  3702. showVerb: deepverb
  3703.     verb = 'show'
  3704.     sdesc = "show"
  3705.     prepDefault = toPrep
  3706.     ioAction( toPrep ) = 'ShowTo'
  3707.     doDefault( actor, prep, io ) =
  3708.     {
  3709.         return( actor.contents );
  3710.     }
  3711. ;
  3712. cleanVerb: deepverb
  3713.     verb = 'clean'
  3714.     sdesc = "clean"
  3715.     ioAction( withPrep ) = 'CleanWith'
  3716.     doAction = 'Clean'
  3717. ;
  3718. sayVerb: deepverb
  3719.     verb = 'say'
  3720.     sdesc = "say"
  3721.     doAction = 'Say'
  3722. ;
  3723. yellVerb: deepverb
  3724.     verb = 'yell' 'shout' 'yell at' 'shout at'
  3725.     action( actor ) =
  3726.     {
  3727.         "%Your% throat is a bit sore now. ";
  3728.     }
  3729. ;
  3730. moveVerb: deepverb
  3731.     verb = 'move'
  3732.     sdesc = "move"
  3733.     ioAction( withPrep ) = 'MoveWith'
  3734.     ioAction( toPrep ) = 'MoveTo'
  3735.     doAction = 'Move'
  3736. ;
  3737. fastenVerb: deepverb
  3738.     verb = 'fasten' 'buckle' 'buckle up'
  3739.     sdesc = "fasten"
  3740.     doAction = 'Fasten'
  3741. ;
  3742. unfastenVerb: deepverb
  3743.     verb = 'unfasten' 'unbuckle'
  3744.     sdesc = "unfasten"
  3745.     doAction = 'Unfasten'
  3746. ;
  3747. unplugVerb: deepverb
  3748.     verb = 'unplug'
  3749.     sdesc = "unplug"
  3750.     ioAction( fromPrep ) = 'UnplugFrom'
  3751.     doAction = 'Unplug'
  3752. ;
  3753. lookUnderVerb: deepverb
  3754.     verb = 'look under' 'look beneath' 'l under' 'l beneath'
  3755.     sdesc = "look under"
  3756.     doAction = 'Lookunder'
  3757. ;
  3758. lookBehindVerb: deepverb
  3759.     verb = 'look behind' 'l behind'
  3760.     sdesc = "look behind"
  3761.     doAction = 'Lookbehind'
  3762. ;
  3763. typeVerb: deepverb
  3764.     verb = 'type'
  3765.     sdesc = "type"
  3766.     prepDefault = onPrep
  3767.     ioAction( onPrep ) = 'TypeOn'
  3768. ;
  3769. lockVerb: deepverb
  3770.     verb = 'lock'
  3771.     sdesc = "lock"
  3772.     ioAction( withPrep ) = 'LockWith'
  3773.     doAction = 'Lock'
  3774.     prepDefault = withPrep
  3775. ;
  3776. unlockVerb: deepverb
  3777.     verb = 'unlock'
  3778.     sdesc = "unlock"
  3779.     ioAction( withPrep ) = 'UnlockWith'
  3780.     doAction = 'Unlock'
  3781.     prepDefault = withPrep
  3782. ;
  3783. detachVerb: deepverb
  3784.     verb = 'detach' 'disconnect'
  3785.     prepDefault = fromPrep
  3786.     ioAction( fromPrep ) = 'DetachFrom'
  3787.     doAction = 'Detach'
  3788.     sdesc = "detach"
  3789. ;
  3790. sleepVerb: darkVerb
  3791.     action( actor ) =
  3792.     {
  3793.         if ( actor.cantSleep )
  3794.             "%You% %are% much too anxious worrying about %your% continued
  3795.             survival to fall asleep now. ";
  3796.         else if ( global.awakeTime+1 < global.sleepTime )
  3797.             "%You're% not tired. ";
  3798.         else if ( not ( actor.location.isbed or actor.location.ischair ))
  3799.             "I don't know about you, but I can never sleep
  3800.             standing up. %You% should find a nice comfortable
  3801.             bed somewhere. ";
  3802.         else
  3803.         {
  3804.             "%You% quickly drift%s% off into dreamland...\b";
  3805.             goToSleep();
  3806.         }
  3807.     }
  3808.     verb = 'sleep'
  3809. ;
  3810. pokeVerb: deepverb
  3811.     verb = 'poke' 'jab'
  3812.     sdesc = "poke"
  3813.     doAction = 'Poke'
  3814. ;
  3815. touchVerb: deepverb
  3816.     verb = 'touch'
  3817.     sdesc = "touch"
  3818.     doAction = 'Touch'
  3819. ;
  3820. moveNVerb: deepverb
  3821.     verb = 'move north' 'move n' 'push north' 'push n'
  3822.     sdesc = "move north"
  3823.     doAction = 'MoveN'
  3824. ;
  3825. moveSVerb: deepverb
  3826.     verb = 'move south' 'move s' 'push south' 'push s'
  3827.     sdesc = "move south"
  3828.     doAction = 'MoveS'
  3829. ;
  3830. moveEVerb: deepverb
  3831.     verb = 'move east' 'move e' 'push east' 'push e'
  3832.     sdesc = "move east"
  3833.     doAction = 'MoveE'
  3834. ;
  3835. moveWVerb: deepverb
  3836.     verb = 'move west' 'move w' 'push west' 'push w'
  3837.     sdesc = "move west"
  3838.     doAction = 'MoveW'
  3839. ;
  3840. moveNEVerb: deepverb
  3841.     verb = 'move northeast' 'move ne' 'push northeast' 'push ne'
  3842.     sdesc = "move northeast"
  3843.     doAction = 'MoveNE'
  3844. ;
  3845. moveNWVerb: deepverb
  3846.     verb = 'move northwest' 'move nw' 'push northwest' 'push nw'
  3847.     sdesc = "move northwest"
  3848.     doAction = 'MoveNW'
  3849. ;
  3850. moveSEVerb: deepverb
  3851.     verb = 'move southeast' 'move se' 'push southeast' 'push se'
  3852.     sdesc = "move southeast"
  3853.     doAction = 'MoveSE'
  3854. ;
  3855. moveSWVerb: deepverb
  3856.     verb = 'move southwest' 'move sw' 'push southwest' 'push sw'
  3857.     sdesc = "move southwest"
  3858.     doAction = 'MoveSW'
  3859. ;
  3860. centerVerb: deepverb
  3861.     verb = 'center'
  3862.     sdesc = "center"
  3863.     doAction = 'Center'
  3864. ;
  3865. searchVerb: deepverb
  3866.     verb = 'search'
  3867.     sdesc = "search"
  3868.     doAction = 'Search'
  3869. ;
  3870.  
  3871. /*
  3872.  *   Travel verbs  - these verbs allow the player to move about.
  3873.  *   All travel verbs have the property isTravelVerb set true.
  3874.  */
  3875. class travelVerb: deepverb, darkVerb
  3876.     isTravelVerb = true
  3877. ;
  3878.  
  3879. eVerb: travelVerb
  3880.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3881.     verb = 'e' 'east' 'go east'
  3882.     travelDir( actor ) = { return( actor.location.east ); }
  3883. ;
  3884. sVerb: travelVerb
  3885.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3886.     verb = 's' 'south' 'go south'
  3887.     travelDir( actor ) = { return( actor.location.south ); }
  3888. ;
  3889. nVerb: travelVerb
  3890.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3891.     verb = 'n' 'north' 'go north'
  3892.     travelDir( actor ) = { return( actor.location.north ); }
  3893. ;
  3894. wVerb: travelVerb
  3895.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3896.     verb = 'w' 'west' 'go west'
  3897.     travelDir( actor ) = { return( actor.location.west ); }
  3898. ;
  3899. neVerb: travelVerb
  3900.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3901.     verb = 'ne' 'northeast' 'go ne' 'go northeast'
  3902.     travelDir( actor ) = { return( actor.location.ne ); }
  3903. ;
  3904. nwVerb: travelVerb
  3905.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3906.     verb = 'nw' 'northwest' 'go nw' 'go northwest'
  3907.     travelDir( actor ) = { return( actor.location.nw ); }
  3908. ;
  3909. seVerb: travelVerb
  3910.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3911.     verb = 'se' 'southeast' 'go se' 'go southeast'
  3912.     travelDir( actor ) = { return( actor.location.se ); }
  3913. ;
  3914. swVerb: travelVerb
  3915.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3916.     verb = 'sw' 'southwest' 'go sw' 'go southwest'
  3917.     travelDir( actor ) = { return( actor.location.sw ); }
  3918. ;
  3919. inVerb: travelVerb
  3920.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3921.     verb = 'in' 'go in' 'enter'
  3922.     sdesc = "enter"
  3923.     doAction = 'Enter'
  3924.     travelDir( actor ) = { return( actor.location.in ); }
  3925.     ioAction(onPrep) = 'EnterOn'
  3926.     ioAction(inPrep) = 'EnterIn'
  3927.     ioAction(withPrep) = 'EnterWith'
  3928. ;
  3929. outVerb: travelVerb
  3930.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3931.     verb = 'out' 'go out' 'exit' 'leave'
  3932.     travelDir( actor ) = { return( actor.location.out ); }
  3933. ;
  3934. dVerb: travelVerb
  3935.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3936.     verb = 'd' 'down' 'go down'
  3937.     travelDir( actor ) = { return( actor.location.down ); }
  3938. ;
  3939. uVerb: travelVerb
  3940.     action( actor ) = { actor.travelTo( self.travelDir( actor )); }
  3941.     verb = 'u' 'up' 'go up'
  3942.     travelDir( actor ) = { return( actor.location.up ); }
  3943. ;
  3944.  
  3945. /*
  3946.  *   sysverb:  A system verb.  Verbs of this class are special verbs that
  3947.  *   can be executed without certain normal validations.  For example,
  3948.  *   a system verb can be executed in a dark room.  System verbs are
  3949.  *   for operations such as saving, restoring, and quitting, which are
  3950.  *   not really part of the game.
  3951.  */
  3952. class sysverb: deepverb, darkVerb
  3953.     issysverb = true
  3954. ;
  3955.  
  3956. quitVerb: sysverb
  3957.     verb = 'quit'
  3958.     quitGame(actor) =
  3959.     {
  3960.         local yesno;
  3961.  
  3962.         scoreRank();
  3963.         "\bDo you really want to quit? (YES or NO) > ";
  3964.         yesno := yorn();
  3965.         "\b";
  3966.         if ( yesno = 1 )
  3967.         {
  3968.             terminate();    // allow user good-bye message
  3969.         quit();
  3970.         }
  3971.         else
  3972.         {
  3973.             "Okay. ";
  3974.         }
  3975.     }
  3976.     action( actor ) =
  3977.     {
  3978.     self.quitGame(actor);
  3979.     abort;
  3980.     }
  3981. ;
  3982. verboseVerb: sysverb
  3983.     verb = 'verbose'
  3984.     verboseMode(actor) =
  3985.     {
  3986.         "Okay, now in VERBOSE mode.\n";
  3987.         global.verbose := true;
  3988.     Me.location.lookAround( true );
  3989.     }
  3990.     action( actor ) =
  3991.     {
  3992.     self.verboseMode(actor);
  3993.     abort;
  3994.     }
  3995. ;
  3996. terseVerb: sysverb
  3997.     verb = 'brief' 'terse'
  3998.     terseMode(actor) =
  3999.     {
  4000.         "Okay, now in TERSE mode.\n";
  4001.         global.verbose := nil;
  4002.     }
  4003.     action( actor ) =
  4004.     {
  4005.     self.terseMode(actor);
  4006.     abort;
  4007.     }
  4008. ;
  4009. scoreVerb: sysverb
  4010.     verb = 'score' 'status'
  4011.     showScore(actor) =
  4012.     {
  4013.         scoreRank();
  4014.     }
  4015.     action( actor ) =
  4016.     {
  4017.     self.showScore(actor);
  4018.     abort;
  4019.     }
  4020. ;
  4021. saveVerb: sysverb
  4022.     verb = 'save'
  4023.     sdesc = "save"
  4024.     doAction = 'Save'
  4025.     saveGame(actor) =
  4026.     {
  4027.         local savefile;
  4028.     
  4029.     savefile := askfile( 'File to save game in' );
  4030.     if ( savefile = nil or savefile = '' )
  4031.         {
  4032.         "Failed. ";
  4033.             return nil;
  4034.     }
  4035.     else if (save( savefile ))
  4036.         {
  4037.         "Saved failed. ";
  4038.             return nil;
  4039.     }
  4040.     else
  4041.     {
  4042.         "Saved. ";
  4043.             return true;
  4044.     }
  4045.     }
  4046.     action( actor ) =
  4047.     {
  4048.     self.saveGame(actor);
  4049.     abort;
  4050.     }
  4051. ;
  4052. restoreVerb: sysverb
  4053.     verb = 'restore'
  4054.     sdesc = "restore"
  4055.     doAction = 'Restore'
  4056.     restoreGame(actor) =
  4057.     {
  4058.         local savefile;
  4059.     
  4060.     savefile := askfile( 'File to restore game from' );
  4061.     if ( savefile = nil or savefile = '' )
  4062.         {
  4063.         "Failed. ";
  4064.             return nil;
  4065.     }
  4066.     else if (restore( savefile ))
  4067.         {
  4068.         "Restore failed. ";
  4069.             return nil;
  4070.     }
  4071.     else
  4072.     {
  4073.         scoreStatus(global.score, global.turnsofar);
  4074.         "Restored.\b";
  4075.         Me.location.lookAround(true);
  4076.         return true;
  4077.     }
  4078.     }
  4079.     action( actor ) =
  4080.     {
  4081.     self.restoreGame(actor);
  4082.     abort;
  4083.     }
  4084. ;
  4085. scriptVerb: sysverb
  4086.     verb = 'script'
  4087.     doAction = 'Script'
  4088.     startScripting(actor) =
  4089.     {
  4090.         local scriptfile;
  4091.     
  4092.     scriptfile := askfile( 'File to write transcript to' );
  4093.     if ( scriptfile = nil or scriptfile = '' )
  4094.         "Failed. ";
  4095.     else
  4096.     {
  4097.         logging( scriptfile );
  4098.         "All text will now be saved to the script file.
  4099.             Type UNSCRIPT at any time to discontinue scripting.";
  4100.     }
  4101.     }
  4102.     action( actor ) =
  4103.     {
  4104.     self.startScripting(actor);
  4105.     abort;
  4106.     }
  4107. ;
  4108. unscriptVerb: sysverb
  4109.     verb = 'unscript'
  4110.     stopScripting(actor) =
  4111.     {
  4112.         logging( nil );
  4113.         "Script closed.\n";
  4114.     }
  4115.     action( actor ) =
  4116.     {
  4117.     self.stopScripting(actor);
  4118.         abort;
  4119.     }
  4120. ;
  4121. restartVerb: sysverb
  4122.     verb = 'restart'
  4123.     restartGame(actor) =
  4124.     {
  4125.         local yesno;
  4126.         while ( true )
  4127.         {
  4128.             "Are you sure you want to start over? (YES or NO) > ";
  4129.             yesno := yorn();
  4130.             if ( yesno = 1 )
  4131.             {
  4132.                 "\n";
  4133.         scoreStatus(0, 0);
  4134.                 restart(initRestart, global.initRestartParam);
  4135.                 break;
  4136.             }
  4137.             else if ( yesno = 0 )
  4138.             {
  4139.                 "\nOkay.\n";
  4140.         break;
  4141.             }
  4142.         }
  4143.     }
  4144.     action( actor ) =
  4145.     {
  4146.     self.restartGame(actor);
  4147.     abort;
  4148.     }
  4149. ;
  4150. versionVerb: sysverb
  4151.     verb = 'version'
  4152.     showVersion(actor) =
  4153.     {
  4154.         version.sdesc;
  4155.     }
  4156.     action( actor ) =
  4157.     {
  4158.     self.showVersion(actor);
  4159.         abort;
  4160.     }
  4161. ;
  4162. debugVerb: sysverb
  4163.     verb = 'debug'
  4164.     enterDebugger(actor) =
  4165.     {
  4166.     if (debugTrace())
  4167.         "You can't think this game has any bugs left in it... ";
  4168.     }
  4169.     action( actor ) =
  4170.     {
  4171.     self.enterDebugger(actor);
  4172.     abort;
  4173.     }
  4174. ;
  4175.  
  4176. undoVerb: sysverb
  4177.     verb = 'undo'
  4178.     undoMove(actor) =
  4179.     {
  4180.     /* do TWO undo's - one for this 'undo', one for previous command */
  4181.     if (undo() and undo())
  4182.     {
  4183.         "(Undoing one command)\b";
  4184.         Me.location.lookAround(true);
  4185.         scoreStatus(global.score, global.turnsofar);
  4186.     }
  4187.     else
  4188.         "No more undo information is available. ";
  4189.     }
  4190.     action(actor) =
  4191.     {
  4192.     self.undoMove(actor);
  4193.     abort;
  4194.     }
  4195. ;
  4196.  
  4197. /*
  4198.  *  Prep: object
  4199.  *
  4200.  *  A preposition.  The preposition property specifies the
  4201.  *  vocabulary word.
  4202.  */
  4203. class Prep: object
  4204. ;
  4205.  
  4206. /*
  4207.  *   Various prepositions
  4208.  */
  4209. ofPrep: Prep
  4210.     preposition = 'of'
  4211.     sdesc = "of"
  4212. ;
  4213. aboutPrep: Prep
  4214.     preposition = 'about'
  4215.     sdesc = "about"
  4216. ;
  4217. withPrep: Prep
  4218.     preposition = 'with'
  4219.     sdesc = "with"
  4220. ;
  4221. toPrep: Prep
  4222.     preposition = 'to'
  4223.     sdesc = "to"
  4224. ;
  4225. onPrep: Prep
  4226.     preposition = 'on' 'onto' 'downon' 'upon'
  4227.     sdesc = "on"
  4228. ;
  4229. inPrep: Prep
  4230.     preposition = 'in' 'into' 'downin'
  4231.     sdesc = "in"
  4232. ;
  4233. offPrep: Prep
  4234.     preposition = 'off' 'offof'
  4235.     sdesc = "off"
  4236. ;
  4237. outPrep: Prep
  4238.     preposition = 'out' 'outof'
  4239.     sdesc = "out"
  4240. ;
  4241. fromPrep: Prep
  4242.     preposition = 'from'
  4243.     sdesc = "from"
  4244. ;
  4245. betweenPrep: Prep
  4246.     preposition = 'between' 'inbetween'
  4247.     sdesc = "between"
  4248. ;
  4249. overPrep: Prep
  4250.     preposition = 'over'
  4251.     sdesc = "over"
  4252. ;
  4253. atPrep: Prep
  4254.     preposition = 'at'
  4255.     sdesc = "at"
  4256. ;
  4257. aroundPrep: Prep
  4258.     preposition = 'around'
  4259.     sdesc = "around"
  4260. ;
  4261. thruPrep: Prep
  4262.     preposition = 'through' 'thru'
  4263.     sdesc = "through"
  4264. ;
  4265. dirPrep: Prep
  4266.     preposition = 'north' 'south' 'east' 'west' 'up' 'down' 'northeast' 'ne'
  4267.                   'northwest' 'nw' 'southeast' 'se' 'southwest' 'sw'
  4268.     sdesc = "north"         // Shouldn't ever need this, but just in case
  4269. ;
  4270. underPrep: Prep
  4271.     preposition = 'under' 'beneath'
  4272.     sdesc = "under"
  4273. ;
  4274. behindPrep: Prep
  4275.     preposition = 'behind'
  4276.     sdesc = "behind"
  4277. ;
  4278.  
  4279. /*
  4280.  *   articles:  the "built-in" articles.  "The," "a," and "an" are
  4281.  *   defined.
  4282.  */
  4283. articles: object
  4284.     article = 'the' 'a' 'an'
  4285. ;
  4286.  
  4287. /*
  4288. @numbered_cleanup: function
  4289. This function is used as a fuse to delete objects created by the
  4290. \tt numberedObject\ class in reponse to calls to its \tt newNumbered\
  4291. method.  Whenever that method creates a new object, it sets up a fuse
  4292. call to this function to delete the object at the end of the turn in
  4293. which it created the object.
  4294. */
  4295. numbered_cleanup: function(obj)
  4296. {
  4297.     delete obj;
  4298. }
  4299.  
  4300. /*
  4301. @numberedObject: object
  4302. This class can be added to a class list for an object to allow it to
  4303. be used as a generic numbered object.  You can create a single object
  4304. with this class, and then the player can refer to that object with
  4305. any number.  For example, you can create a single "button" object
  4306. that the player can refer to with ``button 100'' or ``button 1000''
  4307. or any other number.  If you want to limit the range of acceptable
  4308. numbers, override the \tt num_is_valid\ method so that it displays
  4309. an appropriate error message and returns \tt nil\ for invalid numbers.
  4310. If you want to use a separate object to handle references to the object
  4311. with a plural ("look at buttons"), override \tt newNumberedPlural\ to
  4312. return the object to handle these references; by default, the original
  4313. object is used to handle plurals.
  4314. */
  4315.  
  4316. class numberedObject: object
  4317.     adjective = '#'
  4318.     anyvalue(n) = { return n; }
  4319.     clean_up = { delete self; }
  4320.     newNumberedPlural(a, v) = { return self; }
  4321.     newNumbered(a, v, n) =
  4322.     {
  4323.     local obj;
  4324.  
  4325.     if (n = nil) return self.newNumberedPlural(a, v);
  4326.     if (not self.num_is_valid(n)) return nil;
  4327.     obj := new self;
  4328.     obj.value := n;
  4329.         setfuse(numbered_cleanup, 0, obj);
  4330.     return obj;
  4331.     }
  4332.     num_is_valid(n) = { return true; }
  4333.     dobjGen(a, v, i, p) =
  4334.     {
  4335.     if (self.value = nil)
  4336.     {
  4337.         "You'll have to be more specific about which one you mean.";
  4338.         exit;
  4339.     }
  4340.     }
  4341.     iobjGen(a, v, d, p) = { self.dobjGen(a, v, d, p); }
  4342. ;
  4343.