home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #7 / amigamamagazinepolishissue1998.iso / rozrywka / rpg / amigamud / src / basics / util1.m < prev    next >
Text File  |  1997-06-29  |  43KB  |  1,734 lines

  1. /*
  2.  * Amiga MUD
  3.  *
  4.  * Copyright (c) 1997 by Chris Gray
  5.  */
  6.  
  7. /*
  8.  * util1.m - a bunch of handy utility routines. Also some core routines for
  9.  *    some standard things used in most dungeons.
  10.  */
  11.  
  12. private tp_util1 CreateTable()$
  13. use tp_util1
  14.  
  15.  
  16. /***************************************************************************/
  17.  
  18. /* codes for use with LeaveRoomStuff and EnterRoomStuff */
  19.  
  20. define t_util MOVE_NORMAL    0$
  21. define t_util MOVE_POOF     1$
  22. define t_util MOVE_SPECIAL    2$
  23.  
  24.  
  25. /***************************************************************************/
  26.  
  27. /* some standard types of rooms */
  28.  
  29. define t_roomTypes r_indoors CreateThing(nil)$
  30. r_indoors@p_rScenery :=
  31.     "floor,ceiling,air.wall;north,south,east,west,n,s,e,w"$
  32. AutoGraphics(r_indoors, AutoClosedRoom)$
  33. SetThingStatus(r_indoors, ts_readonly)$
  34.  
  35. define t_roomTypes r_outdoors CreateThing(nil)$
  36. r_outdoors@p_rScenery := "ground,sky,air,sun,sunlight"$
  37. AutoGraphics(r_outdoors, AutoPaths)$
  38. SetThingStatus(r_outdoors, ts_readonly)$
  39.  
  40. define t_roomTypes r_path CreateThing(r_outdoors)$
  41. r_path@p_rScenery :=
  42.     "ground,sky,air,sun,sunlight,path,pathway,trail,bush,bushes,grass,dust"$
  43. AutoGraphics(r_path, AutoPaths)$
  44. SetThingStatus(r_path, ts_readonly)$
  45.  
  46. define t_roomTypes r_road CreateThing(r_outdoors)$
  47. r_road@p_rScenery := "ground,sky,air,sun,sunlight,road,dirt,alley,dust"$
  48. AutoGraphics(r_road, AutoRoads)$
  49. SetThingStatus(r_road, ts_readonly)$
  50.  
  51. define t_roomTypes r_forest CreateThing(r_outdoors)$
  52. r_forest@p_rScenery :=
  53.     "ground,sky,air,sun,sunlight,grass,bush,bushes,tree,leaf,leaves,foliage"$
  54. AutoGraphics(r_forest, AutoPaths)$
  55. AutoPens(r_forest, C_DARK_GREEN, C_BROWN, 0, 0)$
  56. SetThingStatus(r_forest, ts_readonly)$
  57.  
  58. define t_roomTypes r_field CreateThing(r_outdoors)$
  59. r_field@p_rScenery :=
  60.     "ground,sky,air,sun,sunlight,grass,field,flower,insect,pasture"$
  61. AutoGraphics(r_field, AutoOpenSpace)$
  62. SetThingStatus(r_field, ts_readonly)$
  63.  
  64. define t_roomTypes r_sidewalk CreateThing(r_outdoors)$
  65. r_sidewalk@p_rScenery :=
  66.     "ground,sky,air,sun,sunlight,sidewalk,pavement,road,dust"$
  67. AutoGraphics(r_sidewalk, AutoPaths)$
  68. SetThingStatus(r_sidewalk, ts_readonly)$
  69.  
  70. define t_roomTypes r_park CreateThing(r_outdoors)$
  71. r_park@p_rScenery :=
  72.     "ground,sky,air,sun,sunlight,sidewalk,fountain,tree,bush,"
  73.     "bushes,grass.park.flower"$
  74. AutoGraphics(r_park, AutoOpenSpace)$
  75. SetThingStatus(r_park, ts_readonly)$
  76.  
  77. define t_roomTypes r_tunnel CreateThing(r_indoors)$
  78. r_tunnel@p_rScenery :=
  79.     "floor,ground,air,roof,ceiling,rock,stone."
  80.     "side,wall;north,south,east,west,n,s,e,w"$
  81. AutoGraphics(r_tunnel, AutoTunnels)$
  82. SetThingStatus(r_tunnel, ts_readonly)$
  83.  
  84.  
  85. /***************************************************************************/
  86.  
  87. /* some routines to help us build a world */
  88.  
  89. /*
  90.  * ExtendDesc - add some stuff to a room description - this is used when
  91.  *    adding a room to an already existing setup.
  92.  */
  93.  
  94. define t_util proc utility public ExtendDesc(thing room; string desc)void:
  95.     string s;
  96.  
  97.     s := room@p_rDesc;
  98.     if s = "" then
  99.     s := desc;
  100.     else
  101.     s := s + " " + desc;
  102.     fi;
  103.     room@p_rDesc := s;
  104. corp;
  105.  
  106. /*
  107.  * Scenery - add some names that will be found by 'look', etc., but that
  108.  *    have nothing special about them. Doing it this way saves creating
  109.  *    a lot of extra things.
  110.  */
  111.  
  112. define t_util proc utility public Scenery(thing room; string newScenery)void:
  113.     string oldScenery;
  114.     int len;
  115.  
  116.     len := Length(newScenery);
  117.     if len ~= 0 then
  118.     len := len - 1;
  119.     /* Trim any extra final '.' given. */
  120.     if SubString(newScenery, len, 1) = "." then
  121.         newScenery := SubString(newScenery, 0, len);
  122.     fi;
  123.     oldScenery := room@p_rScenery;
  124.     if oldScenery ~= "" then
  125.         newScenery := oldScenery + "." + newScenery;
  126.     fi;
  127.     room@p_rScenery := newScenery;
  128.     fi;
  129. corp;
  130.  
  131. /*
  132.  * Sign - create a dummy sign.
  133.  */
  134.  
  135. define t_util proc utility public Sign(thing room; string name, desc,text)void:
  136.     thing sign;
  137.  
  138.     sign := CreateThing(nil);
  139.     sign@p_oName := name;
  140.     if desc ~= "" then
  141.     sign@p_oDesc := desc;
  142.     fi;
  143.     sign@p_oReadString := text;
  144.     sign@p_oNotGettable := true;
  145.     sign@p_oInvisible := true;
  146.     SetThingStatus(sign, ts_readonly);
  147.     AddTail(room@p_rContents, sign);
  148. corp;
  149.  
  150. /*
  151.  * Several variants for setting up rooms. Note: the 'P' variants are the
  152.  *    same as the non-P forms, except that they make the room public,
  153.  *    i.e. add-to-able by others.
  154.  *    The base variant takes the room, the name string, and an optional
  155.  *    description string.
  156.  */
  157.  
  158. define t_util proc utility public SetupRoom(thing room; string name, desc)void:
  159.  
  160.     room@p_rName := name;
  161.     if desc ~= "" then
  162.     room@p_rDesc := desc;
  163.     fi;
  164.     room@p_rContents := CreateThingList();
  165.     room@p_rExits := CreateIntList();
  166.     SetThingStatus(room, ts_readonly);
  167. corp;
  168.  
  169. define t_util proc utility public SetupRoomP(thing room;
  170.     string name, desc)void:
  171.  
  172.     room@p_rName := name;
  173.     if desc ~= "" then
  174.     room@p_rDesc := desc;
  175.     fi;
  176.     room@p_rContents := CreateThingList();
  177.     room@p_rExits := CreateIntList();
  178.     SetThingStatus(room, ts_wizard);
  179. corp;
  180.  
  181. define t_util proc utility public SetupRoomD(thing room;
  182.     string name, desc)void:
  183.  
  184.     room@p_rName := name;
  185.     if desc ~= "" then
  186.     room@p_rDesc := desc;
  187.     fi;
  188.     room@p_rContents := CreateThingList();
  189.     room@p_rExits := CreateIntList();
  190.     SetThingStatus(room, ts_readonly);
  191.     room@p_rDark := true;
  192. corp;
  193.  
  194. define t_util proc utility public SetupRoomDP(thing room;
  195.     string name, desc)void:
  196.  
  197.     room@p_rName := name;
  198.     if desc ~= "" then
  199.     room@p_rDesc := desc;
  200.     fi;
  201.     room@p_rContents := CreateThingList();
  202.     room@p_rExits := CreateIntList();
  203.     SetThingStatus(room, ts_wizard);
  204.     room@p_rDark := true;
  205. corp;
  206.  
  207. /* This variant has no description, and a proc to provide the name.
  208.    This is useful with many similar rooms, to avoid duplicating the
  209.    name string. */
  210.  
  211. define t_util proc utility public SetupRoom2(thing room;
  212.     action nameAction)void:
  213.  
  214.     room@p_rNameAction := nameAction;
  215.     room@p_rContents := CreateThingList();
  216.     room@p_rExits := CreateIntList();
  217.     SetThingStatus(room, ts_readonly);
  218. corp;
  219.  
  220. define t_util proc utility public SetupRoom2P(thing room;
  221.     action nameAction)void:
  222.  
  223.     room@p_rNameAction := nameAction;
  224.     room@p_rContents := CreateThingList();
  225.     room@p_rExits := CreateIntList();
  226.     SetThingStatus(room, ts_wizard);
  227. corp;
  228.  
  229. /* Variant with name action, but a required description string */
  230.  
  231. define t_util proc utility public SetupRoom3(thing room; action nameAction;
  232.     string desc)void:
  233.  
  234.     room@p_rNameAction := nameAction;
  235.     room@p_rDesc := desc;
  236.     room@p_rContents := CreateThingList();
  237.     room@p_rExits := CreateIntList();
  238.     SetThingStatus(room, ts_readonly);
  239. corp;
  240.  
  241. define t_util proc utility public SetupRoom3P(thing room; action nameAction;
  242.     string desc)void:
  243.  
  244.     room@p_rNameAction := nameAction;
  245.     room@p_rDesc := desc;
  246.     room@p_rContents := CreateThingList();
  247.     room@p_rExits := CreateIntList();
  248.     SetThingStatus(room, ts_wizard);
  249. corp;
  250.  
  251. /* Similar utility to set up an object. Takes the object, an optional room
  252.    to put it in and to make its home, the name string, and an optional
  253.    description string. */
  254.  
  255. define t_util proc utility public SetupObject(thing object, where;
  256.     string name, desc)void:
  257.  
  258.     object@p_oName := name;
  259.     if desc ~= "" then
  260.     object@p_oDesc := desc;
  261.     fi;
  262.     if where ~= nil then
  263.     AddTail(where@p_rContents, object);
  264.     object@p_oHome := where;
  265.     object@p_oWhere := where;
  266.     fi;
  267.     SetThingStatus(object, ts_wizard);
  268. corp;
  269.  
  270. /* this one makes a fake, non-gettable object */
  271.  
  272. define t_util proc utility public FakeObject(thing object, where;
  273.     string name, desc)void:
  274.  
  275.     object@p_oName := name;
  276.     if desc ~= "" then
  277.     object@p_oDesc := desc;
  278.     fi;
  279.     object@p_oNotGettable := true;
  280.     object@p_oInvisible := true;
  281.     if where ~= nil then
  282.     AddTail(where@p_rContents, object);
  283.     fi;
  284.     SetThingStatus(object, ts_wizard);
  285. corp;
  286.  
  287. /* this one makes just a model for a fake, non-gettable object */
  288.  
  289. define t_util proc utility public FakeModel(thing object;
  290.     string name, desc)void:
  291.  
  292.     object@p_oName := name;
  293.     if desc ~= "" then
  294.     object@p_oDesc := desc;
  295.     fi;
  296.     object@p_oNotGettable := true;
  297.     object@p_oInvisible := true;
  298.     SetThingStatus(object, ts_wizard);
  299. corp;
  300.  
  301. /*
  302.  * DepositObject - add a clone of an object to the indicated room.
  303.  */
  304.  
  305. define t_util proc utility public DepositClone(thing room, model)void:
  306.     thing new;
  307.  
  308.     new := CreateThing(model);
  309.     AddTail(room@p_rContents, new);
  310.     new@p_oCreator := Me();
  311.     new@p_oWhere := room;
  312.     GiveThing(new, SysAdmin);
  313.     SetThingStatus(new, ts_public);
  314. corp;
  315.  
  316. /* Some utilities for making connections between rooms. 'Connect' is the
  317.    most useful one. */
  318.  
  319. define t_util proc utility public UniConnect(thing r1, r2; int dir)void:
  320.     list int exits;
  321.  
  322.     r1@DirProp(dir) := r2;
  323.     exits := r1@p_rExits;
  324.     if exits = nil then
  325.     exits := CreateIntList();
  326.     r1@p_rExits := exits;
  327.     fi;
  328.     AddTail(exits, dir);
  329. corp;
  330.  
  331. define t_util proc utility public BiConnect(thing r1, r2; int dir1, dir2)void:
  332.     list int exits;
  333.  
  334.     r1@DirProp(dir1) := r2;
  335.     exits := r1@p_rExits;
  336.     if exits = nil then
  337.     exits := CreateIntList();
  338.     r1@p_rExits := exits;
  339.     fi;
  340.     AddTail(exits, dir1);
  341.     r2@DirProp(dir2) := r1;
  342.     exits := r2@p_rExits;
  343.     if exits = nil then
  344.     exits := CreateIntList();
  345.     r2@p_rExits := exits;
  346.     fi;
  347.     AddTail(exits, dir2);
  348. corp;
  349.  
  350. define t_util proc utility public Connect(thing r1, r2; int dir)void:
  351.     list int exits;
  352.  
  353.     r1@DirProp(dir) := r2;
  354.     exits := r1@p_rExits;
  355.     if exits = nil then
  356.     exits := CreateIntList();
  357.     r1@p_rExits := exits;
  358.     fi;
  359.     AddTail(exits, dir);
  360.     dir := DirBack(dir);
  361.     r2@DirProp(dir) := r1;
  362.     exits := r2@p_rExits;
  363.     if exits = nil then
  364.     exits := CreateIntList();
  365.     r2@p_rExits := exits;
  366.     fi;
  367.     AddTail(exits, dir);
  368. corp;
  369.  
  370. /*
  371.  * HConnect is the same as Connect, except that the connection is not
  372.  *    added to the list of obvious exits.
  373.  */
  374.  
  375. define t_util proc utility public HConnect(thing r1, r2; int dir)void:
  376.  
  377.     r1@DirProp(dir) := r2;
  378.     r2@DirProp(DirBack(dir)) := r1;
  379. corp;
  380.  
  381. /*
  382.  * HUniConnect - a hidden one-way connection.
  383.  */
  384.  
  385. define t_util proc utility public HUniConnect(thing r1, r2; int dir)void:
  386.  
  387.     r1@DirProp(dir) := r2;
  388. corp;
  389.  
  390.  
  391. /***************************************************************************/
  392.  
  393. /* some routines useful for verbs */
  394.  
  395. /* a couple of handy utilities */
  396.  
  397. define t_util proc isYes(string s)bool:
  398.  
  399.     s == "y" or s == "yes" or s == "t" or s == "true"
  400. corp;
  401.  
  402. define t_util proc isNo(string s)bool:
  403.  
  404.     s == "n" or s == "no" or s == "n" or s == "false"
  405. corp;
  406.  
  407. /*
  408.  * ShowExits - show the obvious exits from the current room.
  409.  */
  410.  
  411. define t_util proc public ShowExits(thing room)void:
  412.     list int li;
  413.     int count, i, oldIndent;
  414.  
  415.     li := room@p_rExits;
  416.     if li ~= nil then
  417.     count := Count(li);
  418.     if count = 0 then
  419.         Print("There are no obvious exits.\n");
  420.     else
  421.         Print("Obvious exits: ");
  422.         oldIndent := GetIndent();
  423.         SetIndent(oldIndent + 2);
  424.         for i from 0 upto count - 1 do
  425.         Print(ExitName(li[i]));
  426.         if i ~= count - 1 then
  427.             Print(" ");
  428.         fi;
  429.         od;
  430.         SetIndent(oldIndent);
  431.         Print("\n");
  432.     fi;
  433.     else
  434.     Print("There are no obvious exits.\n");
  435.     fi;
  436. corp;
  437.  
  438. /*
  439.  * ShowList - print out a contents/carrying list. Return 'true' if nothing
  440.  *    was printed.
  441.  */
  442.  
  443. define t_util proc utility public ShowList(list thing lt; string starter)bool:
  444.     int i;
  445.     thing object;
  446.     string s;
  447.     bool first;
  448.  
  449.     first := true;
  450.     if lt ~= nil then
  451.     for i from 0 upto Count(lt) - 1 do
  452.         object := lt[i];
  453.         if not object@p_oInvisible then
  454.         if first then
  455.             first := false;
  456.             Print(starter);
  457.         fi;
  458.         Print("  " + FormatName(object@p_oName) + "\n");
  459.         fi;
  460.     od;
  461.     fi;
  462.     first
  463. corp;
  464.  
  465. /*
  466.  * DoAll - do the given proc for each visible thing in the given list. Return
  467.  *    'continue' if at least one is done and all done yield 'true';
  468.  *    return 'succeed' if one does not return 'true', and return 'fail'
  469.  *    if there are none to do.
  470.  */
  471.  
  472. define t_util proc public DoAll(list thing lt; action a)status:
  473.     int count, i, oldCount;
  474.     thing th;
  475.     bool ok, doneOne;
  476.  
  477.     doneOne := false;
  478.     if lt ~= nil then
  479.     count := Count(lt);
  480.     i := 0;
  481.     ok := true;
  482.     while ok and i ~= count do
  483.         th := lt[i];
  484.         if not th@p_oInvisible then
  485.         doneOne := true;
  486.         if call(a, bool)(th) then
  487.             oldCount := count;
  488.             count := Count(lt);
  489.             i := i - (oldCount - count) + 1;
  490.         else
  491.             ok := false;
  492.         fi;
  493.         else
  494.         i := i + 1;
  495.         fi;
  496.     od;
  497.     fi;
  498.     if doneOne then
  499.     if ok then continue else succeed fi
  500.     else
  501.     fail
  502.     fi
  503. corp;
  504.  
  505. /* NOTE: When a monster is killed, DoDrop is called to drop whatever it is
  506.    carrying. That in turn calls CanSee, with 'thePlayer' set to the monster. */
  507.  
  508. define t_util proc public CanSee(thing theRoom, thePlayer)bool:
  509.  
  510.     if not theRoom@p_rDark then
  511.     true
  512.     else
  513.     if thePlayer ~= nil and not thePlayer@p_pStandard then
  514.         thePlayer := Me();
  515.     fi;
  516.     if thePlayer = nil then
  517.         theRoom@p_rContents ~= nil and
  518.         FindFlagOnList(theRoom@p_rContents, p_oLight) or
  519.         FindAgentWithFlag(theRoom, p_oLight) ~= nil or
  520.         FindAgentWithFlagOnList(theRoom, p_pCarrying, p_oLight) ~= nil
  521.     elif thePlayer@p_oLight then
  522.         true
  523.     else
  524.         FindFlagOnList(thePlayer@p_pCarrying, p_oLight) or
  525.         theRoom@p_rContents ~= nil and
  526.         FindFlagOnList(theRoom@p_rContents, p_oLight) or
  527.         FindAgentWithFlag(theRoom, p_oLight) ~= nil or
  528.         FindAgentWithFlagOnList(theRoom, p_pCarrying, p_oLight) ~= nil
  529.     fi
  530.     fi
  531. corp;
  532.  
  533. /*
  534.  * LightAt - return 'true' if there is light in the given room, without
  535.  *    the current player being considered to be there.
  536.  */
  537.  
  538. define t_util proc public LightAt(thing theRoom)bool:
  539.  
  540.     not theRoom@p_rDark or
  541.     theRoom@p_rContents ~= nil and
  542.     FindFlagOnList(theRoom@p_rContents, p_oLight) or
  543.     FindAgentWithFlag(theRoom, p_oLight) ~= nil or
  544.     FindAgentWithFlagOnList(theRoom, p_pCarrying, p_oLight) ~= nil
  545. corp;
  546.  
  547. /*
  548.  * HasLight - return 'true' if the given thing (character) supplies light.
  549.  */
  550.  
  551. define t_util proc public HasLight(thing who)bool:
  552.  
  553.     who@p_oLight or FindFlagOnList(who@p_pCarrying, p_oLight)
  554. corp;
  555.  
  556. /*
  557.  * CarryingChild - return any child of the given thing that the given
  558.  *    player is carrying, either directly or indirectly.
  559.  */
  560.  
  561. define tp_util1 proc containsChild(list thing lt; thing what)thing:
  562.     int count, i;
  563.     thing th;
  564.  
  565.     if lt = nil then
  566.     nil
  567.     else
  568.     count := Count(lt);
  569.     i := 0;
  570.     while i < count do
  571.         th := lt[i];
  572.         if Parent(th) = what then
  573.         i := count + 1;
  574.         elif th@p_oContents ~= nil then
  575.         th := containsChild(th@p_oContents, what);
  576.         if th ~= nil then
  577.             i := count + 1;
  578.         else
  579.             i := i + 1;
  580.         fi;
  581.         else
  582.         i := i + 1;
  583.         fi;
  584.     od;
  585.     if i > count then th else nil fi
  586.     fi
  587. corp;
  588.  
  589. define t_util proc CarryingChild(thing who, what)thing:
  590.     containsChild(who@p_pCarrying, what)
  591. corp;
  592.  
  593. /*
  594.  * ChildHere - return any child of the given thing that the given room
  595.  *    contains, either directly or indirectly.
  596.  */
  597.  
  598. define t_util proc ChildHere(thing room, what)thing:
  599.     containsChild(room@p_rContents, what)
  600. corp;
  601.  
  602. /*
  603.  * ShowPosition - return the position of the given player/character.
  604.  */
  605.  
  606. define t_util proc public ShowPosition(thing th)string:
  607.     int pos;
  608.  
  609.     pos := th@p_pPosition;
  610.     if pos ~= POS_NONE then
  611.     case pos
  612.     incase POS_SIT_IN:
  613.         "sitting in"
  614.     incase POS_SIT_ON:
  615.         "sitting on"
  616.     incase POS_LIE_IN:
  617.         "lying in"
  618.     incase POS_LIE_ON:
  619.         "lying on"
  620.     incase POS_STAND_IN:
  621.         "standing in"
  622.     incase POS_STAND_ON:
  623.         "standing on"
  624.     default:
  625.         "relative to"
  626.     esac +
  627.     " the " + FormatName(th@p_pWhere@p_oName) + "."
  628.     else
  629.     "here."
  630.     fi
  631. corp;
  632.  
  633. /*
  634.  * ZapObject - destroy an object, and anything it contains.
  635.  */
  636.  
  637. define t_util proc public ZapObject(thing object)void:
  638.     list thing lt;
  639.     int count;
  640.     thing th;
  641.  
  642.     CancelAllDoAfters(object);
  643.     lt := object@p_oContents;
  644.     if lt ~= nil then
  645.     count := Count(lt);
  646.     while count ~= 0 do
  647.         count := count - 1;
  648.         th := lt[count];
  649.         ZapObject(th);
  650.         DelElement(lt, th);
  651.     od;
  652.     fi;
  653.     ClearThing(object);
  654. corp;
  655.  
  656. /*
  657.  * SayToList - output a given message to each location on a list.
  658.  */
  659.  
  660. define t_util proc SayToList(list thing lt; string message)void:
  661.     int i;
  662.  
  663.     if lt ~= nil then
  664.     for i from 0 upto Count(lt) - 1 do
  665.         ABPrint(lt[i], nil, nil, message);
  666.     od;
  667.     fi;
  668. corp;
  669.  
  670. /*
  671.  * CharacterDescription - return the normal description of the passed character
  672.  */
  673.  
  674. define t_util proc CharacterDescription(thing who)string:
  675.     string s;
  676.     action a;
  677.  
  678.     SetIt(who);
  679.     a := who@p_pDescAction;
  680.     if a = nil then
  681.     s := who@p_pDesc;
  682.     else
  683.     s := call(a, string)();
  684.     fi;
  685.     s + DoActionsString(who@p_pDescMore)
  686. corp;
  687.  
  688. /*
  689.  * LookAtCharacter - take a detailed look at the given player/monster.
  690.  */
  691.  
  692. define t_util proc LookAtCharacter(thing who)bool:
  693.     action a;
  694.     status st;
  695.     string name, s;
  696.  
  697.     st := continue;
  698.     a := who@p_pDescCheck;
  699.     if a ~= nil then
  700.     /* if p_pDescCheck returns 'continue', all is well and we
  701.        will continue looking at the player, and around. If it
  702.        returns 'succeed', then we are done looking at the
  703.        player, but can look around. If it returns 'fail', then
  704.        we cannot look anymore (or some such). */
  705.     SetIt(who);
  706.     st := call(a, status)();
  707.     fi;
  708.     if st ~= fail then
  709.     if who@p_Image ~= "" then
  710.         ShowImage(who@p_Image);
  711.     fi;
  712.     fi;
  713.     if st = continue then
  714.     s := CharacterDescription(who);
  715.     name := Capitalize(CharacterNameS(who));
  716.     if s = "" then
  717.         s := name + " has no description - bug him/her about it."
  718.     fi;
  719.     Print(s + "\n");
  720.     if who = Me() then
  721.         s := "You are carrying:\n";
  722.     else
  723.         s := name + " is carrying:\n";
  724.     fi;
  725.     ignore ShowList(who@p_pCarrying, s);
  726.     true
  727.     else
  728.     st = succeed
  729.     fi
  730. corp;
  731.  
  732.  
  733. /***************************************************************************/
  734.  
  735. /* some code to aid the 'follow' verb. */
  736.  
  737. define tp_util1 p_pOldHere CreateThingProp()$
  738. define tp_util1 p_pMeFollowDir CreateIntProp()$
  739. define tp_util1 p_pFollowMeDir CreateIntProp()$
  740.  
  741. define t_util proc Follow(thing leader)void:
  742.     list thing followers;
  743.  
  744.     followers := leader@p_pFollowers;
  745.     if followers = nil then
  746.     followers := CreateThingList();
  747.     leader@p_pFollowers := followers;
  748.     leader@p_pFollowMeDir := -1;
  749.     fi;
  750.     AddTail(followers, Me());
  751.     Me()@p_pFollowing := leader;
  752.     Me()@p_pMeFollowDir := -1;
  753. corp;
  754.  
  755. define t_util proc public DoMove(int dir)bool: false corp;    /* replaced */
  756.  
  757. define tp_util1 proc doFollow()status:
  758.     thing me;
  759.     int dir;
  760.  
  761.     me := Me();
  762.     dir := me@p_pMeFollowDir;
  763.     Print("You follow " + CharacterNameS(me@p_pFollowing) + " to " +
  764.     DirName(dir) + ".\n");
  765.     if DoMove(dir) then
  766.     continue
  767.     else
  768.     fail
  769.     fi
  770. corp;
  771.  
  772. define tp_util1 proc doCheckFollowers()void:
  773.     list thing followers;
  774.     thing oldHere, leader, follower;
  775.     int dir, i;
  776.  
  777.     leader := Me();
  778.     followers := leader@p_pFollowers;
  779.     if followers ~= nil then
  780.     oldHere := leader@p_pOldHere;
  781.     dir := leader@p_pFollowMeDir;
  782.     i := Count(followers);
  783.     while i ~= 0 do
  784.         i := i - 1;
  785.         follower := followers[i];
  786.         if follower@p_pFollowing = leader and
  787.         AgentLocation(follower) = oldHere
  788.         then
  789.         follower@p_pMeFollowDir := dir;
  790.         if ForceAction(follower, doFollow) ~= continue
  791.         then
  792.             /* the follow failed - remove this follower */
  793.             /* note that we specifically do not inform the
  794.                follower! */
  795.             follower -- p_pFollowing;
  796.             follower -- p_pMeFollowDir;
  797.             DelElement(followers, follower);
  798.         fi;
  799.         else
  800.         /* Again, we do not inform the follower - that could tell
  801.            him that the one he was following has moved, when he
  802.            should not normally know that. */
  803.         follower -- p_pFollowing;
  804.         follower -- p_pMeFollowDir;
  805.         DelElement(followers, follower);
  806.         fi;
  807.     od;
  808.     if Count(followers) = 0 then
  809.         leader -- p_pFollowers;
  810.         leader -- p_pFollowMeDir;
  811.     fi;
  812.     fi;
  813. corp;
  814.  
  815. define t_util proc CheckFollowers(thing here; int dir)void:
  816.     thing me;
  817.  
  818.     me := Me();
  819.     if me@p_pFollowers ~= nil then
  820.     me@p_pOldHere := here;
  821.     me@p_pFollowMeDir := dir;
  822.     After(0.0, doCheckFollowers);
  823.     fi;
  824. corp;
  825.  
  826. define t_util proc ClearFollowers(thing leader)void:
  827.     list thing followers;
  828.     thing follower;
  829.     int i;
  830.     string name;
  831.  
  832.     followers := leader@p_pFollowers;
  833.     if followers ~= nil then
  834.     name := CharacterNameS(leader);
  835.     for i from 0 upto Count(followers) - 1 do
  836.         follower := followers[i];
  837.         if follower@p_pFollowing = leader then
  838.         follower -- p_pFollowing;
  839.         follower -- p_pMeFollowDir;
  840.         SPrint(follower,"You are no longer following " + name + ".\n");
  841.         fi;
  842.     od;
  843.     leader -- p_pFollowers;
  844.     leader -- p_pFollowMeDir;
  845.     fi;
  846. corp;
  847.  
  848. define t_util proc UnFollow()void:
  849.     list thing followers;
  850.     thing me, leader;
  851.  
  852.     me := Me();
  853.     leader := me@p_pFollowing;
  854.     if leader ~= nil then
  855.     me -- p_pFollowing;
  856.     me -- p_pMeFollowDir;
  857.     Print("You stop following " + CharacterNameS(leader) + ".\n");
  858.     followers := leader@p_pFollowers;
  859.     if followers ~= nil then
  860.         DelElement(followers, me);
  861.         if Count(followers) = 0 then
  862.         leader -- p_pFollowers;
  863.         leader -- p_pFollowMeDir;
  864.         fi;
  865.     fi;
  866.     fi;
  867. corp;
  868.  
  869.  
  870. /* NOTE: for the following sets of routines, the code usually just calls the
  871.    the inner (one/once) routine directly via ForEachAgent, just to save one
  872.    interpreted subroutine call. */
  873.  
  874. /*
  875.  * ShowAgents - show who/what is in the current room.
  876.  */
  877.  
  878. define t_util proc public ShowOneAgent(thing th)void:
  879.  
  880.     if th@p_pName ~= "" and not th@p_pHidden then
  881.     Print(Capitalize(CharacterNameG(th)) + " is " + 
  882.         ShowPosition(th) + "\n");
  883.     GShowIcon(nil, th, not th@p_pStandard, Parent(th) ~= nil);
  884.     fi;
  885. corp;
  886.  
  887. define t_util proc public ShowAgents()void:
  888.  
  889.     ForEachAgent(Here(), ShowOneAgent);
  890. corp;
  891.  
  892. /*
  893.  * ShowRoomTo - show the room to someone who is in it.
  894.  */
  895.  
  896. define t_util proc ShowRoomToMe(bool full)bool:
  897.     thing me, room;
  898.     action a;
  899.     string s;
  900.     status st;
  901.  
  902.     me := Me();
  903.     room := Here();
  904.     a := room@p_rNameAction;
  905.     if a = nil then
  906.     s := room@p_rName;
  907.     else
  908.     s := call(a, string)();
  909.     fi;
  910.     if s ~= "" then
  911.     Print("You are " + s + ".\n");
  912.     fi;
  913.     /* looking around the room can "fail" or "succeed" */
  914.     st := DoRoomLookChecks(room);
  915.     if st ~= fail then
  916.     if st = continue then
  917.         if full or me@p_pVerbose then
  918.         /* it may seem redundant to allow for both 'rLookChecks'
  919.            and 'rDescAction', but what the heck! */
  920.         a := room@p_rDescAction;
  921.         if a = nil then
  922.             s := room@p_rDesc;
  923.             if s = "" then
  924.             Print("You see nothing special here.\n");
  925.             else
  926.             Print(s + "\n");
  927.             fi;
  928.             ShowExits(room);
  929.         else
  930.             Print(call(a, string)() + "\n");
  931.         fi;
  932.         elif not me@p_pSuperBrief then
  933.         ShowExits(room);
  934.         fi;
  935.     fi;
  936.     ignore ShowList(room@p_rContents, "Nearby:\n");
  937.     if GOn(nil) then
  938.         GUndrawIcons(nil);
  939.         GResetIcons(nil);
  940.         a := room@p_rEnterRoomDraw;
  941.         if a ~= nil then
  942.         RemoveCursor();
  943.         call(a, void)();
  944.         elif room@p_Image ~= "" then
  945.         ShowImage(room@p_Image);
  946.         fi;
  947.     fi;
  948.     ForEachAgent(room, ShowOneAgent);
  949.     a := room@p_rFurtherDesc;
  950.     if a ~= nil then
  951.         call(a, void)();
  952.     fi;
  953.     true
  954.     else
  955.     false
  956.     fi
  957. corp;
  958.  
  959. define tp_util1 proc doShowRoom()status:
  960.  
  961.     ignore ShowRoomToMe(false);
  962.     continue
  963. corp;
  964.  
  965. define t_util proc ShowRoomToAgent(thing who)void:
  966.  
  967.     /* no need to do anything for machines */
  968.     if who ~= Me() and ThingCharacter(who) ~= nil then
  969.     ignore ForceAction(who, doShowRoom);
  970.     fi;
  971. corp;
  972.  
  973. define t_util proc UnShowRoomFromMe()void:
  974.     action a;
  975.  
  976.     if GOn(nil) then
  977.     GUndrawIcons(nil);
  978.     GResetIcons(nil);
  979.     a := Here()@p_rLeaveRoomDraw;
  980.     if a ~= nil then
  981.         call(a, void)(nil);
  982.     fi;
  983.     fi;
  984. corp;
  985.  
  986. define tp_util1 proc doUnShowRoom()status:
  987.  
  988.     UnShowRoomFromMe();
  989.     continue
  990. corp;
  991.  
  992. define t_util proc UnShowRoomFromAgent(thing who)void:
  993.  
  994.     if who ~= Me() and ThingCharacter(who) ~= nil then
  995.     /* only do it for players */
  996.     ignore ForceAction(who, doUnShowRoom);
  997.     fi;
  998. corp;
  999.  
  1000. /* general code dealing with entering and exiting rooms, moving, etc. */
  1001.  
  1002. define t_util proc EnterRoomStuff(thing dest; int fromDir, moveKind)void:
  1003.     thing me;
  1004.     bool lightThere;
  1005.     string name, s;
  1006.  
  1007.     DoRoomAnyEnterActions(dest);
  1008.     me := Me();
  1009.     lightThere := LightAt(dest);
  1010.     SetLocation(dest);
  1011.     if lightThere or me@p_oLight or FindFlagOnList(me@p_pCarrying, p_oLight)
  1012.     then
  1013.     ignore ShowRoomToMe(false);
  1014.     /* if I can't see, neither can anyone else */
  1015.     if not me@p_pHidden then
  1016.         if lightThere then
  1017.         ForEachAgent(dest, ShowIconOnce);
  1018.         fi;
  1019.         name := Capitalize(CharacterNameG(me));
  1020.         case moveKind
  1021.         incase MOVE_NORMAL:
  1022.         if fromDir >= 0 then
  1023.             s := dest@(DirEMessage(fromDir));
  1024.             if s = "" then
  1025.             OPrint(name + " has arrived from " +
  1026.                 DirName(fromDir) + ".\n");
  1027.             elif s ~= "." then
  1028.             OPrint(name + " " + s + "\n");
  1029.             fi;
  1030.         fi;
  1031.         incase MOVE_POOF:
  1032.         OPrint(name + " *POOFS* in.\n");
  1033.         esac;
  1034.     else
  1035.         if moveKind = MOVE_POOF then
  1036.         OPrint("*POOF*\n");
  1037.         fi;
  1038.     fi;
  1039.     if not lightThere then
  1040.         ForEachAgent(dest, ShowRoomToAgent);
  1041.     fi;
  1042.     else
  1043.     Print("It is dark here.\n");
  1044.     if dest@p_rEnterRoomDraw ~= nil and GOn(nil) then
  1045.         UnShowRoomFromMe();
  1046.     fi;
  1047.     fi;
  1048. corp;
  1049.  
  1050. /*
  1051.  * similar stuff for the going out of a room half.
  1052.  */
  1053.  
  1054. define t_util proc LeaveRoomStuff(thing dest; int dir, moveKind)void:
  1055.     thing me, here;
  1056.     action a;
  1057.     string name, s;
  1058.     bool lightHere;
  1059.  
  1060.     me := Me();
  1061.     here := Here();
  1062.     SetLocation(nil);
  1063.     lightHere := LightAt(here);
  1064.     if lightHere or me@p_oLight or FindFlagOnList(me@p_pCarrying, p_oLight)
  1065.     then
  1066.     name := Capitalize(CharacterNameG(me));
  1067.     /* have to use ABPrint, since we have done SetLocation(nil) */
  1068.     case moveKind
  1069.     incase MOVE_NORMAL:
  1070.         if not me@p_pHidden then
  1071.         s := here@(DirOMessage(dir));
  1072.         if s = "" then
  1073.             ABPrint(here, me, me,
  1074.             name + " has left to " + DirName(dir) + ".\n");
  1075.         elif s ~= "." then
  1076.             ABPrint(here, me, me, name + " " + s + "\n");
  1077.         fi;
  1078.         CheckFollowers(here, dir);
  1079.         fi;
  1080.         /* we keep the rest in case he/she went hidden while here */
  1081.         s := here@(DirMessage(dir));
  1082.         if s ~= "" then
  1083.         NPrint(s);
  1084.         fi;
  1085.     incase MOVE_POOF:
  1086.         if me@p_pHidden then
  1087.         ABPrint(here, me, me, "*POOF*\n");
  1088.         else
  1089.         ABPrint(here, me, me, name + " *POOFS* out.\n");
  1090.         fi;
  1091.         Print("*POOF*\n");
  1092.         ClearFollowers(me);
  1093.         UnFollow();
  1094.     esac;
  1095.     ForEachAgent(here, UnShowIconOnce);
  1096.     if GOn(nil) then
  1097.         GUndrawIcons(nil);
  1098.         GResetIcons(nil);
  1099.         a := here@p_rLeaveRoomDraw;
  1100.         if a ~= nil then
  1101.         call(a, void)(dest);
  1102.         fi;
  1103.     fi;
  1104.     if not lightHere then
  1105.         ForEachAgent(here, UnShowRoomFromAgent);
  1106.     fi;
  1107.     fi;
  1108.     /* put the location back to the old room for DoRoomAnyEnterActions */
  1109.     SetLocation(here);
  1110. corp;
  1111.  
  1112. /*
  1113.  * EnterRoom - called whenever the player finally enters a given room.
  1114.  *    Returns 'true' if all is well and we should continue with commands.
  1115.  */
  1116.  
  1117. define t_util proc public EnterRoom(thing dest; int dir, moveType)bool:
  1118.  
  1119.     LeaveRoomStuff(dest, dir, moveType);
  1120.     EnterRoomStuff(dest, DirBack(dir), moveType);
  1121.     ignore DoPlayerEnterChecks(Me());
  1122.     /* allow for funny things like instant teleports out, etc. */
  1123.     DoRoomAnyEnterChecks(dest) ~= fail
  1124. corp;
  1125.  
  1126. /*
  1127.  * DoMove - top level routine to attempt to move in the given direction.
  1128.  *    Note: not suitable for other than called by the player.
  1129.  *    Other Note: it should work indirectly for machines, e.g. when
  1130.  *        someone does 'say Packrat go north'.
  1131.  */
  1132.  
  1133. replace DoMove(int dir)bool:
  1134.     thing me, here, dest;
  1135.     string s;
  1136.     action a;
  1137.     property list action checks;
  1138.  
  1139.     me := Me();
  1140.     if me@p_pPosition ~= POS_NONE then
  1141.     Print("You are still " + ShowPosition(me) + "\n");
  1142.     false
  1143.     else
  1144.     here := Here();
  1145.     dest := here@(DirProp(dir));
  1146.     checks := DirChecks(dir);
  1147.     if dest = nil then
  1148.         a := here@p_rNoGoAction;
  1149.         if a ~= nil then
  1150.         call(a, void)(dir);
  1151.         else
  1152.         s := here@p_rNoGoString;
  1153.         if s ~= "" then
  1154.             NPrint(s);
  1155.         else
  1156.             Print("You can't go in that direction.\n");
  1157.         fi;
  1158.         fi;
  1159.         false
  1160.     elif dest@p_rLocked and CharacterThing(Owner(dest)) ~= me and
  1161.         me ~= CharacterThing(SysAdmin)
  1162.     then
  1163.         Print("The owner of that location has locked it.\n");
  1164.         false
  1165.     elif (dest@p_rName = "" and dest@p_rNameAction = nil or
  1166.         dest@p_rExits = nil or dest@p_rContents = nil) and
  1167.         (here@checks = nil or Count(here@checks) = 0)
  1168.     then
  1169.         Print("The location in that direction is not usable.\n");
  1170.         false
  1171.     elif DoPlayerLeaveChecks(me, dir) ~= fail and
  1172.         DoChecks(here@checks) ~= fail and
  1173.         DoRoomAnyLeaveChecks(here) ~= fail
  1174.     then
  1175.         /* nothing was blocking the exit, nothing abnormal happened
  1176.            when we tried to go through, and nothing funny like player
  1177.            being chained to the floor */
  1178.         EnterRoom(dest, dir, MOVE_NORMAL)
  1179.     else
  1180.         false
  1181.     fi
  1182.     fi
  1183. corp;
  1184.  
  1185. /*
  1186.  * UserMove - the user is explicitly moving.
  1187.  */
  1188.  
  1189. define t_util proc UserMove(int dir)bool:
  1190.  
  1191.     UnFollow();
  1192.     DoMove(dir)
  1193. corp;
  1194.  
  1195. /*
  1196.  * TryToMove - similar to 'DoMove', but intended for machines.
  1197.  *    Returns 'true' if it can do the move.
  1198.  *    Note: intended only for calling by the machine doing the moving.
  1199.  */
  1200.  
  1201. define t_util proc public TryToMove(int dir)bool:
  1202.     thing here, there, me;
  1203.  
  1204.     here := Here();
  1205.     me := Me();
  1206.     there := here@(DirProp(dir));
  1207.     if there = nil or
  1208.     there@p_rName = "" and there@p_rNameAction = nil or
  1209.     there@p_rExits = nil or there@p_rContents = nil
  1210.     then
  1211.     false
  1212.     else
  1213.     not there@p_rNoMachines and not there@p_rLocked and
  1214.         me@p_pPosition = POS_NONE and
  1215.         DoPlayerLeaveChecks(me, dir) ~= fail and
  1216.         DoChecks(here@(DirChecks(dir))) ~= fail and
  1217.         DoRoomAnyLeaveChecks(here) ~= fail
  1218.     fi
  1219. corp;
  1220.  
  1221. /*
  1222.  * MachineMove - do the other half of 'DoMove' for machines. This does NOT
  1223.  *    use any of the exit checkers. It should be used with 'TryToMove',
  1224.  *    and not by itself.
  1225.  *    Note: intended only to be called by the machine doing the move.
  1226.  */
  1227.  
  1228. define t_util proc public MachineMove(int dir)void:
  1229.     thing here, me, dest;
  1230.     string myName, s;
  1231.     bool otherLight, meLight;
  1232.  
  1233.     here := Here();
  1234.     me := Me();
  1235.     myName := Capitalize(CharacterNameG(me));
  1236.     dest := here@(DirProp(dir));
  1237.     if dest ~= nil then
  1238.     meLight := me@p_oLight or FindFlagOnList(me@p_pCarrying, p_oLight);
  1239.     otherLight := LightAt(here);
  1240.     if otherLight or meLight then
  1241.         if not me@p_pHidden then
  1242.         s := here@(DirOMessage(dir));
  1243.         if s = "" then
  1244.             OPrint(myName + " has left to " + DirName(dir) + ".\n");
  1245.         elif s ~= "." then
  1246.             OPrint(myName + " " + s + "\n");
  1247.         fi;
  1248.         CheckFollowers(here, dir);
  1249.         fi;
  1250.         if not otherLight then
  1251.         ForEachAgent(here, UnShowRoomFromAgent);
  1252.         else
  1253.         /* we keep this in case it went hidden while here */
  1254.         ForEachAgent(here, UnShowIconOnce);
  1255.         fi;
  1256.     fi;
  1257.     /* The following is a subset of EnterRoom. It is cheaper, since the
  1258.        machine doesn't have to be told about the room and what and who
  1259.        is in it. */
  1260.     SetLocation(nil);
  1261.     otherLight := LightAt(dest);
  1262.     SetLocation(dest);
  1263.     if otherLight or meLight then
  1264.         dir := DirBack(dir);
  1265.         s := dest@(DirEMessage(dir));
  1266.         if s = "" then
  1267.         OPrint(myName + " has arrived from " + DirName(dir) + ".\n");
  1268.         elif s ~= "." then
  1269.         OPrint(myName + " " + s + "\n");
  1270.         fi;
  1271.         if not otherLight then
  1272.         ForEachAgent(dest, ShowRoomToAgent);
  1273.         else
  1274.         ForEachAgent(dest, ShowIconOnce);
  1275.         fi;
  1276.     fi;
  1277.     /* allow monster gen, etc. */
  1278.     ignore DoPlayerEnterChecks(me);
  1279.     /* allow for funny things like instant teleports out, etc. */
  1280.     ignore DoRoomAnyEnterChecks(dest);
  1281.     else
  1282.     OPrint("BUGGY MACHINE " + myName + " IS STUCK HERE.\n");
  1283.     fi;
  1284. corp;
  1285.  
  1286. /*
  1287.  * GetAgents - return a string which is a comma separated list of the
  1288.  *    names of the agents in the given room.
  1289.  */
  1290.  
  1291. define tp_util1 p_pAgentList CreateStringProp()$
  1292.  
  1293. define tp_util1 proc addAnAgent(thing agent)void:
  1294.     thing me;
  1295.     string name, s;
  1296.  
  1297.     me := Me();
  1298.     name := agent@p_pName;
  1299.     if name ~= "" and not agent@p_pHidden then
  1300.     name := FormatName(name);
  1301.     s := me@p_pAgentList;
  1302.     if s ~= "" then
  1303.         s := s + ", ";
  1304.     fi;
  1305.     s := s + name;
  1306.     me@p_pAgentList := s;
  1307.     fi;
  1308. corp;
  1309.  
  1310. define t_util proc GetAgents(thing room)string:
  1311.     string s;
  1312.  
  1313.     ForEachAgent(room, addAnAgent);
  1314.     s := Me()@p_pAgentList;
  1315.     Me() -- p_pAgentList;
  1316.     s
  1317. corp;
  1318.  
  1319. /*
  1320.  * CarryItem - try to add an item to the carry list. If too many complain
  1321.  *    and return false, else add the item and return true.
  1322.  */
  1323.  
  1324. define t_util proc CarryItem(thing object)bool:
  1325.     thing me;
  1326.     list thing carrying;
  1327.  
  1328.     me := Me();
  1329.     carrying := me@p_pCarrying;
  1330.     if Count(carrying) >= MAX_CARRY then
  1331.     Print("You can't carry anything else.\n");
  1332.     false
  1333.     else
  1334.     AddTail(carrying, object);
  1335.     object@p_oCarryer := me;
  1336.     true
  1337.     fi
  1338. corp;
  1339.  
  1340.  
  1341. /***************************************************************************/
  1342.  
  1343. /* Stuff relating to top-level things in the scenario */
  1344.  
  1345. /*
  1346.  * AddSpecialCommand - set things up to add a special this-room-only
  1347.  *    command. Note: allowing the use of this procedure is a fairly large
  1348.  *    security hole, since the commands thus added take precedence OVER
  1349.  *    the normal ones, thus this routine can be used to invoke arbitrary
  1350.  *    action when a player uses a presumed safe command. See 'parseInput'
  1351.  *    for the actual use of these values.
  1352.  */
  1353.  
  1354. define tp_util1 p_rSpecialWords CreateStringProp()$
  1355. define tp_util1 p_rSpecialActions CreateActionListProp()$
  1356.  
  1357. define t_util proc utility public AddSpecialCommand(thing room; string command;
  1358.     action a)void:
  1359.     list action la;
  1360.  
  1361.     la := room@p_rSpecialActions;
  1362.     if la = nil then
  1363.     la := CreateActionList();
  1364.     room@p_rSpecialActions := la;
  1365.     fi;
  1366.     room@p_rSpecialWords := room@p_rSpecialWords + command + ".";
  1367.     AddTail(la, a);
  1368. corp;
  1369.  
  1370. define t_util proc utility public RemoveSpecialCommand(thing room;
  1371.     string command; action a)bool:
  1372.     list action la;
  1373.     string s;
  1374.     int pos, len;
  1375.  
  1376.     la := room@p_rSpecialActions;
  1377.     if la ~= nil then
  1378.     s := room@p_rSpecialWords;
  1379.     command := command + ".";
  1380.     pos := Index(s, command);
  1381.     if pos ~= -1 then
  1382.         len := Length(command);
  1383.         room@p_rSpecialWords := SubString(s, 0, pos) +
  1384.         SubString(s, pos + len, Length(s) - pos - len);
  1385.         DelElement(la, a);
  1386.         true
  1387.     else
  1388.         false
  1389.     fi
  1390.     else
  1391.     false
  1392.     fi
  1393. corp;
  1394.  
  1395. /*
  1396.  * DoSay - bottom level of saying - here since 'parseInput' uses it.
  1397.  *    Needs to be not 'utility' in order to use 'Say'.
  1398.  */
  1399.  
  1400. define t_util proc public DoSay(string what)void:
  1401.     thing me, here;
  1402.  
  1403.     here := Here();
  1404.     if DoRoomSayChecks(here, what) = continue then
  1405.     me := Me();
  1406.     if me@p_pEchoPose then
  1407.         Print("You say: " + what + "\n");
  1408.     fi;
  1409.     Say(if me@p_pHidden or not CanSee(me, here) then "Someone" else "" fi,
  1410.         what);
  1411.     fi;
  1412. corp;
  1413.  
  1414. /*
  1415.  * checkAlias - check for and handle an alias on the character. This is
  1416.  *    a separate routine so that it is NOT 'utility', but is owned by
  1417.  *    SysAdmin. This lets folks other than SysAdmin read the alias
  1418.  *    things!
  1419.  */
  1420.  
  1421. define tp_util1 proc checkAlias(string s)string:
  1422.     list thing aliases;
  1423.     thing alias;
  1424.     string word;
  1425.     int count;
  1426.     bool doneIt;
  1427.  
  1428.     SetTail(s);
  1429.     word := GetWord();
  1430.     aliases := Me()@p_pAliases;
  1431.     if aliases ~= nil then
  1432.     count := Count(aliases);
  1433.     doneIt := false;
  1434.     while count ~= 0 and not doneIt do
  1435.         count := count - 1;
  1436.         alias := aliases[count];
  1437.         if alias@p_sAliasKey == word then
  1438.         s := alias@p_sAliasValue + " " + GetTail();
  1439.         doneIt := true;
  1440.         fi;
  1441.     od;
  1442.     fi;
  1443.     s
  1444. corp;
  1445.  
  1446. /*
  1447.  * parseInput - the normal input command handler.
  1448.  *    NOTE: we want this to be 'utility', so that the build commands can
  1449.  *    be run by the real player. The problem with this is that any message
  1450.  *    from 'Parse' will have an '@' in front if it is run by a non-wizard.
  1451.  *    I'll kluge that by having 'Parse' force wizard-mode if it needs to
  1452.  *    print an error message. Sigh.
  1453.  *    Another '@' problem surfaces: if the whole result of the user command
  1454.  *    is to print a 'p_oActString', then that output will be prefixed with
  1455.  *    '@' when a non-wizard is running. I have implemented 'NPrint' to
  1456.  *    hopefully get around this.
  1457.  */
  1458.  
  1459. define tp_misc proc utility parseInput(string s)void:
  1460.     action a;
  1461.     thing here, it, me;
  1462.     string word, specials;
  1463.     int which, count;
  1464.     bool doneIt;
  1465.  
  1466.     while SubString(s, 0, 1) = ";" do
  1467.     s := SubString(s, 1, Length(s) - 1);
  1468.     od;
  1469.     if s ~= "" then
  1470.     GlobalThing@p_FlushNeeded := true;
  1471.     if SubString(s, 0, 1) = "\"" or SubString(s, 0, 1) = "'" then
  1472.         DoSay(SubString(s, 1, Length(s) - 1));
  1473.     else
  1474.         here := Here();
  1475.         me := Me();
  1476.         s := checkAlias(s);
  1477.         SetTail(s);
  1478.         word := GetWord();
  1479.         if FindName(me@p_pCarrying, p_oActWord, word) = fail and
  1480.         (here@p_rContents = nil or
  1481.          FindName(here@p_rContents, p_oActWord, word) = fail)
  1482.         then
  1483.         doneIt := false;
  1484.         specials := here@p_rSpecialWords;
  1485.         if specials ~= "" then
  1486.             which := MatchName(specials, word);
  1487.             if which >= 0 then
  1488.             call(here@p_rSpecialActions[which], void)();
  1489.             doneIt := true;
  1490.             fi;
  1491.         fi;
  1492.         if not doneIt then
  1493.             /* most commands are done right here */
  1494.             ignore Parse(G, s);
  1495.         fi;
  1496.         else
  1497.         it := FindResult();
  1498.         a := it@p_oActAction;
  1499.         if a ~= nil then
  1500.             SetIt(it);
  1501.             call(a, void)();
  1502.         else
  1503.             NPrint(it@p_oActString);
  1504.         fi;
  1505.         fi;
  1506.     fi;
  1507.     fi;
  1508. corp;
  1509.  
  1510. /*
  1511.  * define constants for the various raw-key codes.
  1512.  */
  1513.  
  1514. define t_util KEY_HELP        0x0020$
  1515. define t_util KEY_KP_UL     0x0001$
  1516. define t_util KEY_KP_U        0x0002$
  1517. define t_util KEY_KP_UR     0x0003$
  1518. define t_util KEY_KP_L        0x0004$
  1519. define t_util KEY_KP_C        0x0005$
  1520. define t_util KEY_KP_R        0x0006$
  1521. define t_util KEY_KP_DL     0x0007$
  1522. define t_util KEY_KP_D        0x0008$
  1523. define t_util KEY_KP_DR     0x0009$
  1524. define t_util KEY_KP_PLUS    0x000a$
  1525. define t_util KEY_KP_MINUS    0x000b$
  1526.  
  1527. /*
  1528.  * handleRawKey - handle a raw special key-hit.
  1529.  *    We want this routine NOT utility, so that there is not an '@' in
  1530.  *    front of the command when 'InsertCommand' prints it.
  1531.  */
  1532.  
  1533. define tp_misc proc handleRawKey(int n)void:
  1534.  
  1535.     case n
  1536.     incase KEY_HELP:
  1537.     InsertCommand("help");
  1538.     incase KEY_KP_UL:
  1539.     InsertCommand("northwest");
  1540.     incase KEY_KP_U:
  1541.     InsertCommand("north");
  1542.     incase KEY_KP_UR:
  1543.     InsertCommand("northeast");
  1544.     incase KEY_KP_L:
  1545.     InsertCommand("west");
  1546.     incase KEY_KP_C:
  1547.     InsertCommand("look");
  1548.     incase KEY_KP_R:
  1549.     InsertCommand("east");
  1550.     incase KEY_KP_DL:
  1551.     InsertCommand("southwest");
  1552.     incase KEY_KP_D:
  1553.     InsertCommand("south");
  1554.     incase KEY_KP_DR:
  1555.     InsertCommand("southeast");
  1556.     incase KEY_KP_PLUS:
  1557.     InsertCommand("up");
  1558.     incase KEY_KP_MINUS:
  1559.     InsertCommand("down");
  1560.     esac;
  1561. corp;
  1562.  
  1563. /*
  1564.  * idleAction - the action that is executed when the player leaves.
  1565.  *    These are NOT utility - do not want '@' in front of any output.
  1566.  */
  1567.  
  1568. define tp_misc proc idleAction()void:
  1569.     thing me, here;
  1570.  
  1571.     me := Me();
  1572.     DoList(me@p_pExitActions);
  1573.  
  1574.     here := Here();
  1575.     SetLocation(nil);
  1576.     if LightAt(here) then
  1577.     ForEachAgent(here, UnShowIconOnce);
  1578.     else
  1579.     if HasLight(me) then
  1580.         ForEachAgent(here, UnShowRoomFromAgent);
  1581.     fi;
  1582.     fi;
  1583.     SetLocation(here);
  1584.     OPrint(Capitalize(me@p_pName) + " has exited the world.\n");
  1585.     GlobalThing@p_FlushNeeded := true;
  1586. corp;
  1587.  
  1588. /*
  1589.  * activeAction - the action that is executed when the player re-enters.
  1590.  */
  1591.  
  1592. define tp_misc proc activeAction()void:
  1593.     thing here, me;
  1594.  
  1595.     here := Here();
  1596.     me := Me();
  1597.     me@p_MapGroup := NO_MAP_GROUP;
  1598.     if GOn(nil) then
  1599.     GSetTextColour(nil, 0, me@p_pTextColours[0]);
  1600.     GSetTextColour(nil, 1, me@p_pTextColours[1]);
  1601.     GSetTextColour(nil, 2, me@p_pTextColours[2]);
  1602.     GSetTextColour(nil, 3, me@p_pTextColours[3]);
  1603.     InitStandardGraphics();
  1604.     else
  1605.     me@p_pStandardGraphicsDone := false;
  1606.     fi;
  1607.  
  1608.     OPrint(Capitalize(me@p_pName) + " has entered the world.\n");
  1609.  
  1610.     DoList(me@p_pEnterActions);
  1611.  
  1612.     ignore Parse(G, "look around");
  1613.     ignore ShowClients(false);
  1614.     SetLocation(nil);
  1615.     if LightAt(here) then
  1616.     SetLocation(here);
  1617.     ForEachAgent(here, ShowIconOnce);
  1618.     else
  1619.     SetLocation(here);
  1620.     if HasLight(me) then
  1621.         ForEachAgent(here, ShowRoomToAgent);
  1622.     fi;
  1623.     fi;
  1624. corp;
  1625.  
  1626.  
  1627. /***************************************************************************/
  1628.  
  1629. /*
  1630.  * ResetObjects - go through a list of objects and put them back where they
  1631.  *    belong. This is useful for single-user-at-a-time quests.
  1632.  */
  1633.  
  1634. define t_util proc utility public ResetObjects(list thing lt)void:
  1635.     int count;
  1636.     thing object, home, now;
  1637.  
  1638.     count := Count(lt);
  1639.     while count ~= 0 do
  1640.     count := count - 1;
  1641.     object := lt[count];
  1642.     home := object@p_oHome;
  1643.     if home ~= nil then
  1644.         now := object@p_oWhere;
  1645.         if now ~= nil then
  1646.         if now ~= home then
  1647.             AddTail(home@p_rContents, object);
  1648.             if now@p_rContents ~= nil then
  1649.             DelElement(now@p_rContents, object);
  1650.             else
  1651.             DelElement(now@p_oContents, object);
  1652.             fi;
  1653.             object@p_oWhere := home;
  1654.         fi;
  1655.         else
  1656.         now := object@p_oCarryer;
  1657.         if now = nil then
  1658.             Print("An object being reset isn't anywhere!\n"
  1659.             "Please inform the owner of this quest.\n");
  1660.         else
  1661.             AddTail(home@p_rContents, object);
  1662.             DelElement(now@p_pCarrying, object);
  1663.             object -- p_oCarryer;
  1664.             object@p_oWhere := home;
  1665.             /* Specifically SPrint, so that other players won't see
  1666.                the objects, perhaps secret to the quest, go away.
  1667.                Not just 'Print' in case the quest allows the object
  1668.                to be given to someone else. */
  1669.             SPrint(now, FormatName(object@p_oName) + " vanishes.\n");
  1670.         fi;
  1671.         fi;
  1672.     fi;
  1673.     od;
  1674. corp;
  1675.  
  1676. /*
  1677.  * RemoveAllFromInventory - remove all occurrences of the given object
  1678.  *    from the given characters inventory, including inside containers.
  1679.  */
  1680.  
  1681. define tp_util1 proc scanList(thing who;list thing lt;thing what;bool top)void:
  1682.     int count, i;
  1683.     thing th;
  1684.  
  1685.     count := Count(lt);
  1686.     i := 0;
  1687.     while i ~= count do
  1688.     th := lt[i];
  1689.     if Parent(th) = what then
  1690.         if top then
  1691.         SPrint(who, FormatName(what@p_oName) + " vanishes.\n");
  1692.         fi;
  1693.         ClearThing(th);
  1694.         DelElement(lt, th);
  1695.         count := count - 1;
  1696.     else
  1697.         if th@p_oContents ~= nil then
  1698.         scanList(who, th@p_oContents, what, false);
  1699.         fi;
  1700.         i := i + 1;
  1701.     fi;
  1702.     od;
  1703. corp;
  1704.     
  1705. define t_util proc RemoveAllFromInventory(thing who, what)void:
  1706.  
  1707.     scanList(who, who@p_pCarrying, what, true);
  1708. corp;
  1709.  
  1710.  
  1711. /***************************************************************************/
  1712.  
  1713. /* create the arrivals room */
  1714.  
  1715. public r_arrivals CreateThing(r_indoors)$
  1716. SetupRoom(r_arrivals, "in the arrivals room",
  1717.     "This room is where new players enter the game.")$
  1718.  
  1719. /* set up 'SysAdmin' */
  1720.  
  1721. CharacterThing(SysAdmin)@p_pDesc :=
  1722.     "SysAdmin is the mighty creator of the entire known universe. "
  1723.     "His least whim is law. "
  1724.     "Nothing is beyond his power. "
  1725.     "Beware lest you antagonize him!"$
  1726. CharacterThing(SysAdmin)@p_pMoney := 10000$
  1727. CharacterThing(SysAdmin)@p_pPrivileged := true$
  1728. /* do this right away so we can add checkers as they are defined */
  1729. CharacterThing(SysAdmin)@p_pEnterActions := CreateActionList()$
  1730. CharacterThing(SysAdmin)@p_pExitActions := CreateActionList()$
  1731.  
  1732.  
  1733. unuse tp_util1
  1734.