home *** CD-ROM | disk | FTP | other *** search
/ Amiga Special: Spiele Hits / Hits-CD.iso / aminet / spiele / ammud1_1.lha / AmigaMUD / Doc / Programming.txt < prev    next >
Text File  |  1997-07-06  |  73KB  |  1,960 lines

  1. AmigaMUD, Copyright 1997 by Chris Gray
  2.  
  3.  
  4.         Programming in the AmigaMUD System
  5.  
  6. Introduction
  7.  
  8.  
  9. The AmigaMUD system contains a complete programming system for a
  10. structured programming language. This language is used to program any
  11. MUD scenarios, quests, puzzles, etc. The AmigaMUD system contains
  12. facilities for parsing, executing, storing, retrieving and pretty-
  13. printing code in the language. Although intended for writing MUD
  14. scenarios, the language can easily be used for other purposes.
  15.  
  16. Although the interpreter is reasonably efficient, it is by no means as
  17. fast as true compiled code. Programmers should keep this in mind when
  18. using the language - things that are practical in, say, C, may not be
  19. practical in AmigaMUD.
  20.  
  21. AmigaMUD programming is accessed though one of the client programs,
  22. just like playing a scenario is. Only characters with status 'wizard'
  23. or 'apprentice' can directly access the programming features.
  24. Characters enabled as builders in the standard scenario can indirectly
  25. access them by writing actions as described in the building document.
  26.  
  27. The AmigaMUD programming language does not contain any language
  28. constructs for doing input/output, graphics, sound, etc. Instead, the
  29. system contains a large number of builtin functions which perform
  30. these activities. Other builtin functions perform utility operations
  31. such as returning the length of a string, taking a substring,
  32. returning the current time and date, etc.
  33.  
  34. Most AmigaMUD programming involves writing functions. These functions
  35. are stored in the system database and are automatically retrieved as
  36. needed (e.g. to call them or print them out). AmigaMUD functions can
  37. have parameters and can return a result. They can also be recursive,
  38. although this is unlikely in a MUD scenario.
  39.  
  40. All AmigaMUD code executes in the server program, MUDServ, on the host
  41. computer. Lexical scanning, parsing, and editing all happen on the
  42. client computers. Parsed functions are sent from the client to the
  43. server as a "compiled" bytestream. Pretty-printing is done on the
  44. host computer, and the results are sent to the client as text. Because
  45. the server computer can never wait for any client (the human player
  46. might get a phone call in the middle of typing in a function!), some
  47. operations, such as input, are done differently than in other
  48. languages.
  49.  
  50. When using the standard scenario, a wizard or apprentice can go into
  51. programming, or wizard mode, by typing the 'wizard' command. The
  52. prompt will change to "> ". In this mode, input typed in is assumed to
  53. be statements in the programming language, definitions of functions,
  54. or one of a few simple wizard-mode commands. For reference, a
  55. statement to get out of wizard mode consists of:
  56.  
  57.     Normal()$
  58.  
  59. This, of course, is only valid when the prompt is "> ", i.e. when no
  60. partial statement has been entered, and the user is not in the middle
  61. of typing in a function definition.
  62.  
  63. If the input statement does not fit on a single line, it can be
  64. continued on as many lines as needed. On lines other than the first,
  65. the prompt will change to ": ". The input statement is ended with a
  66. dollar sign, as in the above example. If the input statement is in
  67. fact an expression, i.e. it returns a value, then the system will
  68. print out that value. For example:
  69.  
  70.     > 2 + 3 $
  71.     ==> 5
  72.  
  73. Not all values can be printed in any meaningful way. Function and
  74. thing (database entity) values are printed either symbolically (if the
  75. system can find a symbol for them) or as a hexadecimal number.
  76.  
  77. Each input line entered by any user is subject to an execution time
  78. limit, which can be controlled by the MUD administrator (SysAdmin).
  79. Running out of time will result in the execution being stopped, and a
  80. traceback of the called functions being produced. Other run-time
  81. errors, such as dividing by zero, produce a similar abort and
  82. traceback.
  83.  
  84. The following sections of this document give some examples of AmigaMUD
  85. programming. It is assumed that the reader already knows something
  86. about programming, or is a fast learner - this document does not try
  87. to teach programming to a novice. Readers are not expected to fully
  88. understand these examples - they are just a random sampling to show
  89. the flavour of AmigaMUD programming.
  90.  
  91.  
  92. Example - the Towers of Hanoi
  93.  
  94.  
  95. Here is a log of entering, printing and running the classic "Towers of
  96. Hanoi" function. Commentary is separated off and enclosed in square
  97. brackets. For those not familiar with this computer programming
  98. classic, the story goes something like this:
  99.  
  100.     There is a monastery near Hanoi where there live a group of monks
  101.     dedicated to keeping the universe running. They do this by
  102.     continually moving flat disks around on a set of three pegs. The
  103.     disks are round, and have a hole in the middle so that they can
  104.     slide onto the pegs. At the beginning of the universe, all 64
  105.     disks were on the left-most peg, with the widest disk on the
  106.     bottom, and the narrowest one on the top. When the monks have
  107.     succeeded in moving all of the disks to the right-hand peg, the
  108.     universe will end. They can only move one disk at a time, and must
  109.     never place a wider disk on top of a narrower one. The monks must
  110.     move the disks as fast as they can.
  111.  
  112. input> wizard
  113.  
  114.     [I was initially in normal playing mode. I used the 'wizard'
  115.     command to get into wizard mode so I can program.]
  116.  
  117. > private proc hanoi(int n; string from, to, using)void:
  118. *** expecting identifier for proc parameter name
  119. *** expecting ',', ';' or ')' after proc parameter
  120. : .
  121. *** expecting 'corp' to end proc definition
  122. Errors detected, proc "hanoi" not created.
  123.  
  124.     [I accidentally tried to use a reserved word as a parameter name.
  125.     I decided to abort the entering of the function by typing a '$'.
  126.     This doesn't always work - sometimes closing parentheses or
  127.     constructs are also needed. Note that the prompt changed to ": "
  128.     while I was entering the function definition.]
  129.  
  130. > private proc hanoi(int n; string fromStr, toStr, usingStr)void:
  131. Postman has arrived from the north.
  132. : if n ~= 0 then
  133. Postman heads into the passageway.
  134. :  hanoi(n - 1, fromStr, usingStr, toStr);
  135. :  Print("Move disk " + IntToString(n) + " from " + fromStr + " peg to " +
  136. :   toStr + " peg.\n");
  137. :  hanoi(n - 1, usingStr, toStr, fromStr);
  138. : fi;
  139. : corp
  140.  
  141.     [Being in wizard mode doesn't take your character out of the
  142.     scenario, hence I still saw messages about Postman passing
  143.     through. It is often wise to go somewhere private when doing
  144.     serious wizarding, so that you aren't interrupted.]
  145.  
  146. > describe hanoi$
  147. hanoi: proc, owner Merlin, useCount 2:
  148. proc hanoi(int n; string fromStr, toStr, usingStr)void:
  149.     if n ~= 0 then
  150.     hanoi(n - 1, fromStr, usingStr, toStr);
  151.     Print("Move disk " + IntToString(n) + " from " + fromStr + " peg to "
  152.          + toStr + " peg.\n");
  153.     hanoi(n - 1, usingStr, toStr, fromStr);
  154.     fi;
  155. corp
  156.  
  157.     [The exact form in which I entered the function is not preserved.
  158.     The function is stored internally as a byte stream, and is
  159.     "pretty-printed" by the system as needed. I used the 'describe'
  160.     wizard-mode command to display the function.]
  161.  
  162. > hanoi(0, "left", "right", "center")$
  163.  
  164.     [Now I call the function. This is a directly entered statement in
  165.     the programming language. With 'n' equal to 0, the function does
  166.     nothing, and, since it returns nothing ("void"), nothing is
  167.     printed.]
  168.  
  169. > hanoi(1, "left", "right", "center")$
  170. Move disk 1 from left peg to right peg.
  171.  
  172.     [With 'n' equal to 1, there is one line of output.]
  173.  
  174. > hanoi(2, "left", "right", "center")$
  175. Move disk 1 from left peg to center peg.
  176. Move disk 2 from left peg to right peg.
  177. Move disk 1 from center peg to right peg.
  178. > hanoi(3, "left", "right", "center")$
  179. Move disk 1 from left peg to right peg.
  180. Move disk 2 from left peg to center peg.
  181. Move disk 1 from right peg to center peg.
  182. Move disk 3 from left peg to right peg.
  183. Move disk 1 from center peg to left peg.
  184. Move disk 2 from center peg to right peg.
  185. Move disk 1 from left peg to right peg.
  186.  
  187.     [The number of lines of output is equal to 2 to the power of 'n',
  188.     minus one. Thus, we need not fear for the imminent end of the
  189.     world. Even if the monks can move one disk per second, the time
  190.     needed to complete the task, 2 to the power of 64, minus one, is a
  191.     very long time indeed!]
  192.  
  193. > Normal()$
  194. input> bye
  195.  
  196.     [I go back into normal mode, and exit.]
  197.  
  198.  
  199. Example - Code to Draw the Streets Area
  200.  
  201.  
  202. (This is not a stand-alone example - it lives within the standard
  203. scenario.)
  204.  
  205. define tp_streets proc drawStreets()void:
  206.  
  207.     if not KnowsEffect(nil, STREETS_ID) then
  208.     DefineEffect(nil, STREETS_ID);
  209.     GSetImage(nil, "Town/streets");
  210.     IfFound(nil);
  211.         GShowImage(nil, "", 0.0, 0.0, 0.5, 1.0, 0.0, 0.0);
  212.     Else(nil);
  213.         GSetPen(nil, C_DARK_GREY);
  214.         GAMove(nil, 0.0, 0.0);
  215.         GRectangle(nil, 0.4995, 1.0, true);
  216.  
  217.         GSetPen(nil, C_LIGHT_GREY);
  218.         GAMove(nil, 0.0, 0.0);
  219.         GRectangle(nil, 0.217, 0.415, true);
  220.         GAMove(nil, 0.277, 0.0);
  221.         GRectangle(nil, 0.2235, 0.415, true);
  222.         GAMove(nil, 0.0, 0.57);
  223.         GRectangle(nil, 0.217, 0.44, true);
  224.         GAMove(nil, 0.277, 0.57);
  225.         GRectangle(nil, 0.2235, 0.44, true);
  226.  
  227.         GSetPen(nil, C_DARK_BROWN);
  228.         GAMove(nil, 0.0, 0.0);
  229.         GRectangle(nil, 0.193, 0.35, true);
  230.         GAMove(nil, 0.3, 0.0);
  231.         GRectangle(nil, 0.202, 0.35, true);
  232.         GAMove(nil, 0.0, 0.63);
  233.         GRectangle(nil, 0.193, 0.38, true);
  234.  
  235.         GSetPen(nil, C_WHITE);
  236.         GAMove(nil, 0.246, 0.0);
  237.         GADraw(nil, 0.246, 0.35);
  238.         GAMove(nil, 0.0, 0.49);
  239.         GADraw(nil, 0.194, 0.49);
  240.         GAMove(nil, 0.303, 0.49);
  241.         GADraw(nil, 0.499, 0.49);
  242.         GAMove(nil, 0.246, 0.63);
  243.         GADraw(nil, 0.246, 0.997);
  244.  
  245.         GSetPen(nil, C_BLACK);
  246.         GAMove(nil, 0.193, 0.13);
  247.         VerticalDoor();
  248.         GAMove(nil, 0.3, 0.01);
  249.         VerticalDoor();
  250.         GAMove(nil, 0.3, 0.13);
  251.         VerticalDoor();
  252.         GAMove(nil, 0.3, 0.245);
  253.         VerticalDoor();
  254.         GAMove(nil, 0.31562, 0.35);
  255.         HorizontalDoor();
  256.         GAMove(nil, 0.38125, 0.35);
  257.         HorizontalDoor();
  258.         GAMove(nil, 0.44687, 0.35);
  259.         HorizontalDoor();
  260.         GAMove(nil, 0.193, 0.65);
  261.         VerticalDoor();
  262.         GAMove(nil, 0.193, 0.77);
  263.         VerticalDoor();
  264.         GAMove(nil, 0.193, 0.89);
  265.         VerticalDoor();
  266.         GAMove(nil, 0.01563, 0.63);
  267.         HorizontalDoor();
  268.         GAMove(nil, 0.08124, 0.63);
  269.         HorizontalDoor();
  270.         GAMove(nil, 0.14687, 0.63);
  271.         HorizontalDoor();
  272.  
  273.         GAMove(nil, 0.085, 0.35);
  274.         GADraw(nil, 0.106, 0.35);
  275.  
  276.         GSetPen(nil, C_LIGHT_GREEN);
  277.         GAMove(nil, 0.3, 0.64);
  278.         GRectangle(nil, 0.18, 0.3, true);
  279.         GSetPen(nil, C_LIGHT_GREY);
  280.         GAMove(nil, 0.378, 0.63);
  281.         GRectangle(nil, 0.0155, 0.36, true);
  282.         GAMove(nil, 0.345, 0.69);
  283.         GRectangle(nil, 0.079, 0.19, true);
  284.         GSetPen(nil, C_BLUE);
  285.         GAMove(nil, 0.36875, 0.74);
  286.         GRectangle(nil, 0.03437, 0.09, true);
  287.         GSetPen(nil, C_GOLD);
  288.         GAMove(nil, 0.38437, 0.78);
  289.         GEllipse(nil, 0.01, 0.02, true);
  290.  
  291.         GSetPen(nil, C_DARK_BROWN);
  292.         GAMove(nil, 0.32, 0.72);
  293.         GRectangle(nil, 0.025, 0.13, true);
  294.         GAMove(nil, 0.425, 0.72);
  295.         GRectangle(nil, 0.025, 0.13, true);
  296.         GSetPen(nil, C_BLACK);
  297.         GAMove(nil, 0.3437, 0.74);
  298.         VerticalDoor();
  299.         GAMove(nil, 0.425, 0.74);
  300.         VerticalDoor();
  301.  
  302.         GSetPen(nil, C_FOREST_GREEN);
  303.         GAMove(nil, 0.3125, 0.67);
  304.         GCircle(nil, 0.01563, true);
  305.         GAMove(nil, 0.42188, 0.67);
  306.         GCircle(nil, 0.0125, true);
  307.         GAMove(nil, 0.45313, 0.68);
  308.         GCircle(nil, 0.01563, true);
  309.         GAMove(nil, 0.35625, 0.91);
  310.         GCircle(nil, 0.00937, true);
  311.         GAMove(nil, 0.33437, 0.9);
  312.         GCircle(nil, 0.00937, true);
  313.         GAMove(nil, 0.30938, 0.91);
  314.         GCircle(nil, 0.00937, true);
  315.         GAMove(nil, 0.46563, 0.8);
  316.         GCircle(nil, 0.00937, true);
  317.         GAMove(nil, 0.4625, 0.87);
  318.         GCircle(nil, 0.00937, true);
  319.         GAMove(nil, 0.44375, 0.91);
  320.         GCircle(nil, 0.00937, true);
  321.         GAMove(nil, 0.41562, 0.9);
  322.         GCircle(nil, 0.00937, true);
  323.     Fi(nil);
  324.     EndEffect();
  325.     fi;
  326.     CallEffect(nil, STREETS_ID);
  327. corp;
  328.  
  329.  
  330. Recall from earlier documents that the "MUD" client program can cache
  331. effects, such as the graphics for the streets area. The server program
  332. keeps track of which active clients currently know which effects. The
  333. code here is asking the server if the current client knows the effect
  334. identified by 'STREETS_ID'. If it doesn't, then that effect is
  335. defined. The effect is actually like a little program itself. A
  336. graphics image called "Town/streets" is requested. If it is found on
  337. the client machine, then it is shown, otherwise a rough rendering of
  338. the image is produced using rectangles, lines, circles, etc. Note that
  339. this decision is made in the client program, since the server cannot
  340. wait for the result of that decision. The rough drawing of the streets
  341. area can be summarized as:
  342.  
  343.     - fill the entire image area with dark grey
  344.     - draw four rectangles of light grey as sidewalks
  345.     - draw three smaller rectangles of dark brown as the buildings
  346.     - draw lines of white down the middle of the roads
  347.     - draw a bunch of black doors. 'VerticalDoor' and 'HorizontalDoor'
  348.     are scenario functions which in turn use effects to draw the
  349.     standard vertical and horizontal doors.
  350.     - draw a light green rectangle to be the body of the park
  351.     - draw a pair of overlapping light grey rectangles to be the
  352.     sidewalks in the park
  353.     - draw the blue fountain with the gold mermaid in it
  354.     - draw two dark brown buildings with black doors
  355.     - draw a bunch of forest green trees
  356.  
  357. After the STREETS_ID effect is defined (if it wasn't already), it is
  358. called up. The result of all of this is that the first time a client
  359. program needs to draw this area, there is a pause as the effect code
  360. is sent from the server. On subsequent uses, however, the server knows
  361. that the client knows the effect, so only a short request to run it is
  362. sent over. (The pause is not noticeable with a fast connection.)
  363.  
  364.  
  365. Example - Code for the 'Inventory' Verb
  366.  
  367.  
  368. (This is not a stand-alone example - it lives within the standard
  369. scenario.)
  370.  
  371. define tp_verbs proc v_inventory()bool:
  372.     int cash;
  373.     thing me;
  374.  
  375.     me := Me();
  376.     cash := me@p_pMoney;
  377.     if cash = 0 then
  378.     Print("You are broke.\n");
  379.     else
  380.     Print("You have ");
  381.     IPrint(cash);
  382.     if cash = 1 then
  383.         Print(" bluto.\n");
  384.     else
  385.         Print(" blutos.\n");
  386.     fi;
  387.     fi;
  388.     if ShowList(me@p_pCarrying, "You are carrying:\n") then
  389.     Print("You are not carrying anything.\n");
  390.     fi;
  391.     if not me@p_pHidden and CanSee(Here(), me) then
  392.     OPrint(FormatName(me@p_pName) + " takes inventory.\n");
  393.     fi;
  394.     true
  395. corp;
  396.  
  397. Verb0(G, "inventory", 0, v_inventory)$
  398. Synonym(G, "inventory", "inv")$
  399. Synonym(G, "inventory", "i")$
  400.  
  401.  
  402. This routine returns a 'bool' (true/false) value, like other direct
  403. parsing routines. This is done so that if an error is encountered, the
  404. system can abort the handling of user input which contains several
  405. commands on one line, such as:
  406.  
  407.     go north. go east. west. get rope. go south. tie rope to rail
  408.  
  409. If such a parsing routine returns 'false', then the successive
  410. commands on the same line are not executed. In the case of
  411. 'inventory', there is nothing that can go wrong, so the function
  412. always returns 'true'.
  413.  
  414. This function has some local variables. They are valid only while the
  415. function is executing, and do not have to have names unique from local
  416. variables in other functions.
  417.  
  418. First, a local copy of the pointer to the current character, as
  419. yielded by calling the builtin "Me", is created. This is done since it
  420. is quicker to reference a local variable than to call a function.
  421. Next, the amount of money the character has is obtained. The '@'
  422. operator takes a 'thing' on the left and a property on the right, and
  423. returns the value of that property attached to the thing. Much more
  424. will be said about this later. The function then prints out an
  425. appropriate comment based on that amount. Next, it calls "ShowList",
  426. which is another routine in the scenario which prints the names of
  427. objects in a list, one per line, slightly indented. It is used here,
  428. when describing a room, and when looking inside a container. If the
  429. list is empty, it does not print anything, and returns 'true'. If the
  430. list is not empty, it prints its second parameter (here "You are
  431. carrying:\n") before printing the items in the list, and then returns
  432. 'false'. Thus, the code here will either print the list of objects the
  433. character is carrying (property 'p_pCarrying' on the character) headed
  434. by "You are carrying:\n", or will print "You are not carrying
  435. anything.\n" if the character is empty-handed.
  436.  
  437. The next 'if' statement is a bit more complicated. It's purpose is to
  438. allow other characters in the same room as the one doing the inventory
  439. to see what the first is doing, if appropriate. A character can be
  440. "hidden" (only wizards can do this in the current scenario), so that
  441. others cannot see them or what they are doing. 'CanSee' is another
  442. routine in the scenario, that determines whether or not there is light
  443. in the given room. There will be no light if the room is dark, no
  444. object in the room is emitting light, no character in the room is
  445. emitting light (wizards can make themselves glow), and no character in
  446. the room is carrying an object which is emitting light. 'OPrint' is a
  447. builtin function which displays the passed string to all characters,
  448. except the active one, in the same room as the active one.
  449. 'FormatName' is a builtin function which reformats a string from the
  450. AmigaMUD internal form into a more normal external form (e.g. turns
  451. "frog;small,green" into "small green frog"). Thus, if the active
  452. player is not a hidden wizard, and there is light in the current room,
  453. then all players in the current room will see the message "XXX takes
  454. inventory.\n", where XXX is the character's name.
  455.  
  456. The three lines after the function definition are directly executed
  457. statements which add the verbs "inventory", "inv" and "i" to the main
  458. grammar, as abbreviated by 'G'. 'Verb0' tells the system that there
  459. are no arguments expected for the verb. Other possibilities are
  460. 'Verb1' as in "examine <object>" and 'Verb2' as in "put the <object>
  461. into the <object>". The main grammar, G, is the one which is used to
  462. parse normal user commands when not in wizard mode. Other grammars are
  463. used for the building commands, etc. More details on parsing will be
  464. given later.
  465.  
  466.  
  467. Example - Code for the 'ShowList' Utility Routine
  468.  
  469.  
  470. (This is not a stand-alone example - it lives within the standard
  471. scenario.)
  472.  
  473. define t_util proc utility public ShowList(list thing lt;
  474.                        string starter)bool:
  475.     int i;
  476.     thing object;
  477.     string s;
  478.     bool first;
  479.  
  480.     first := true;
  481.     for i from 0 upto Count(lt) - 1 do
  482.     object := lt[i];
  483.     if not object@p_oInvisible then
  484.         if first then
  485.         first := false;
  486.         Print(starter);
  487.         fi;
  488.         Print("  " + FormatName(object@p_oName) + "\n");
  489.     fi;
  490.     od;
  491.     first
  492. corp;
  493.  
  494.  
  495. A list in AmigaMUD can be indexed like a one-dimensional array. The
  496. builtin 'Count' takes any kind of list as its argument, and returns
  497. the number of elements in it. This routine simply runs down the
  498. elements in the passed list, and looks for any objects that are not
  499. marked as invisible. It prints each such one out, indented by two
  500. spaces, after the header passed by the caller. If no visible objects
  501. were found, 'ShowList' returns true, else it returns false.
  502.  
  503.  
  504. Example - the Code for Killing a Monster
  505.  
  506.  
  507. (This is not a stand-alone example - it lives within the standard
  508. scenario.)
  509.  
  510. define t_fight proc KillMonster(thing theMonster)void:
  511.     string monsterName;
  512.     thing theKiller, other, here;
  513.     list thing lt;
  514.     int i;
  515.  
  516.     theKiller := Me();
  517.     monsterName := CharacterNameS(theMonster);
  518.     Print(Capitalize(monsterName) + " is killed!\n");
  519.     if theKiller@p_pHidden then
  520.     OPrint(Capitalize(monsterName) + " is killed!\n");
  521.     else
  522.     OPrint(Capitalize(CharacterNameS(theKiller)) + " kills " +
  523.         monsterName +"!\n");
  524.     fi;
  525.     theKiller -- p_pCurrentTarget;
  526.     other := theMonster@p_pCurrentTarget;
  527.     if other ~= nil and other ~= theKiller then
  528.     if other@p_pCurrentTarget = theMonster then
  529.         other -- p_pCurrentTarget;
  530.     fi;
  531.     fi;
  532.     lt := theMonster@p_pCarrying;
  533.     if lt ~= nil then
  534.     here := Here();
  535.     i := Count(lt);
  536.     while i ~= 0 do
  537.         i := i - 1;
  538.         ignore DoDrop(here, theMonster, lt[i]);
  539.     od;
  540.     fi;
  541.     if theMonster ~= theKiller then
  542.     i := theMonster@p_pMoney;
  543.     if i ~= 0 then
  544.         FindLoot((i + 1) / 2 + Random((i + 1) / 2));
  545.     fi;
  546.     fi;
  547.     ignore ForceAction(theMonster, DoUnShowIcon);
  548. corp;
  549.  
  550. This routine is executed whenever a character in the combat area (the
  551. "Proving Grounds") successfully vanquishes a monster. The routine
  552. prints informative messages to the player and anyone else around,
  553. causes all of the monster's possessions to be dropped, and gives the
  554. character a possible monetary reward. The final line of the function
  555. needs a bit more explaining. The builtin function 'ForceAction' forces
  556. the indicated character or NPC to execute the function passed as the
  557. second argument. This means that any code that affects "everyone else
  558. in the room" will also affect whoever is killing the monster. In this
  559. case, the routine called is responsible for removing the icon for the
  560. monster from the displays of everyone else in the room, which will
  561. include the character who killed the monster.
  562.  
  563.  
  564. Wizard-Mode Commands
  565.  
  566.  
  567. Most input entered while in wizard mode is either function definitions
  568. or statements in the programming language to be directly executed. A
  569. few special commands are available for convenience, however. They are:
  570.  
  571.     END-OF-FILE - an end-of-file condition will cause the client to
  572.     exit.
  573.  
  574.     bye - this command will cause the client to exit. Note that the
  575.     server keeps track of whether a character is in wizard mode
  576.     or not, so on the next connection, it will enter wizard mode
  577.     if that is the mode the character was last in. When not in
  578.     wizard mode, special scenario actions can be taken when a
  579.     character exits the game and when the character re-enters the
  580.     game. These are not performed when in wizard mode. Thus,
  581.     things like the initial display of the current location will
  582.     not happen automatically, and it may be necessary to look
  583.     around and/or move around to get it to appear.
  584.  
  585.     public
  586.     private
  587.     define/def - these three commands are used to define a symbol.
  588.     'public' will put the symbol into the global public symbol
  589.     table. 'private' will put the symbol into your private symbol
  590.     table, and 'define' will put the symbol into whatever table
  591.     you specify. There are two kinds of symbol definitions that
  592.     can be made. The first kind consists of a name for the symbol
  593.     followed by the definition of it, followed by a period.
  594.     Examples:
  595.  
  596.         public G CreateGrammar()$
  597.         public p_pName CreateStringProp()$
  598.         private HIT_LIMIT 72$
  599.         private room_table CreateTable()$
  600.         define room_table westRoom CreateThing(genericRoom)$
  601.         define room_table eastRoom CreateThing(genericRoom)$
  602.  
  603.     The second kind of symbol definition defines a function. This
  604.     is done by using the reserved word 'proc' followed by the
  605.     function definition. See the previous example sections for
  606.     some of these. They will be discussed in more detail later.
  607.  
  608.     delete/del <table-name> <symbol> - this command will delete the
  609.     given symbol from the given table, if it can. It is similar
  610.     to running the 'DeleteSymbol' builtin. <table-name> can be
  611.     "private" or "public" as well as the name of a table.
  612.  
  613.     use <table-expression> - this command adds the specified symbol
  614.     table to the set of currently in-use tables. It is equivalent
  615.     to calling the 'UseTable' builtin. See the discussion of
  616.     tables in the 'Building' document. See the documentation of
  617.     'UseTable' for a warning.
  618.  
  619.     unuse <table-expression> - this command removes the specified
  620.     symbol table from the set of currently in-use tables. It is
  621.     equivalent to calling the 'UnUseTable' builtin.
  622.  
  623.     source <filename> - this command causes the contents of the named
  624.     file (on the client machine) to be read and processed. Files
  625.     sourced in this way can in turn contain other 'source'
  626.     commands. Doing this allows a large scenario to be split up
  627.     into a number of logical (and smaller) pieces. The filename
  628.     can be any legal AmigaDOS file path. Examples:
  629.  
  630.         source AmigaMUD:Src/go
  631.         source df0:AmigaMUD/examples/speech.m
  632.  
  633.     When using the "MUD" client program, the 'Source' menu item is
  634.     equivalent to the 'source' command. Do not try to switch
  635.     between wizard mode and normal mode while sourcing files,
  636.     however, since the operation is asynchronous and will
  637.     probably not occur when you want it to.
  638.  
  639.     describe/desc/d <expression>$ - this command prints out
  640.     information about the value of the requested expression. It is
  641.     the wizard mode command most often used interactively. The
  642.     output will depend on the type of the expression:
  643.  
  644.         void - a void value, i.e. no value, is printed as '<VOID>'
  645.  
  646.         status - a status value is printed symbolically, as
  647.         'succeed', 'continue' or 'fail'
  648.  
  649.         character - output for a character value is quite lengthy.
  650.         It consists of:
  651.  
  652.             - the character's sponsor - this is the character
  653.             who promoted this character to its current
  654.             status, if any.
  655.  
  656.             - the character's current location. This will be
  657.             the name of the location (room) the character
  658.             is in, if that room has a name, and a table
  659.             containing that name is in-use. Otherwise it
  660.             will just be '<THING>'.
  661.  
  662.             - the character's input action. This is the action
  663.             that all non-wizard-mode text input from the
  664.             player is passed to. It is normally some
  665.             general scenario parsing routine. The output
  666.             will be the name of the function if a table
  667.             containing that function is in-use, otherwise
  668.             it will be '<ACTION>'.
  669.  
  670.             - the character's raw key action. This is the
  671.             action which is called to process raw key
  672.             events occuring when the player hits a special
  673.             key, such as 'HELP', or a numeric keypad key.
  674.  
  675.             - the character's mouse down action. This is the
  676.             action which is called to process left-mouse-
  677.             button hits over identified regions of the
  678.             graphics window.
  679.  
  680.             - the character's button action. This is the
  681.             action which is called to process button hits
  682.             done with the mouse. Button-hits are clicks on
  683.             scenario-created "mouse-buttons" in the
  684.             graphics window.
  685.  
  686.             - the character's idle action. This is the action
  687.             which is called when the player leaves the
  688.             game when not in wizard mode.
  689.  
  690.             - the character's active action. This is the
  691.             action which is called when the player re-
  692.             enters the game not in wizard mode. It is
  693.             often used to do a 'look around' to establish
  694.             the display for the current location.
  695.  
  696.             - the character's status. This is one of:
  697.  
  698.             - normal
  699.             - apprentice
  700.             - wizard
  701.  
  702.             - the character's usecount. This indicates the
  703.             number of references to the character data
  704.             structure currently contained in the database.
  705.             There are many indirect references to the
  706.             character as "owner" pointers, but these do
  707.             not contribute to this count.
  708.  
  709.             - the character's current non-wizard-mode prompt
  710.  
  711.             - the character's current password. This will only
  712.             be displayed for SysAdmin.
  713.  
  714.             - if the character is currently in wizard mode,
  715.             then '(in wizard mode)' is displayed
  716.  
  717.             - if the character is a new character, i.e. has
  718.             not yet connected and been initialized, then
  719.             '(new player)'.
  720.  
  721.             - the character's "thing" is displayed. This is
  722.             where all other changeable properties of the
  723.             character are stored. See the section here on
  724.             thing output for details.
  725.  
  726.         bool - a boolean value is printed as 'true' or 'false'
  727.  
  728.         int - an integer value is printed in decimal
  729.  
  730.         fixed - a fixed point value is printed in decimal with a
  731.         decimal point always present
  732.  
  733.         string - a string value is printed in quotes, with special
  734.         characters escaped as in source form
  735.  
  736.         thing - the output for a thing consists of a header
  737.         section, showing the fixed values that make up a
  738.         thing, followed by some number of property-value pairs
  739.         which are the contents of the thing. The fixed header
  740.         contains:
  741.  
  742.             - the thing's parent. This is the thing which this
  743.             thing starts inheriting properties from.
  744.  
  745.             - the thing's owner. This is the character who
  746.             currently owns the thing. When a thing is
  747.             created, it's owner is set to the effective
  748.             character at the time.
  749.  
  750.             - the thing's usecount. This is the number of
  751.             references to the thing from other entities in
  752.             the database. If this count goes to zero, then
  753.             the thing can be destroyed.
  754.  
  755.             - the thing's property count. This is the count of
  756.             the number of properties attached to the
  757.             thing. This does not count any properties that
  758.             may be inherited from ancestors.
  759.  
  760.             - the thing's status. This is one of:
  761.  
  762.             ts_private - only the owner of the thing can
  763.                 examine or change it
  764.  
  765.             ts_readonly - only the owner of the thing can
  766.                 change it, but anyone can examine it
  767.  
  768.             ts_wizard - any character with wizard status
  769.                 (or code running with that status) can
  770.                 change the thing, and anyone can examine
  771.                 the thing
  772.  
  773.             ts_public - anyone can change or examine the
  774.                 thing
  775.  
  776.         The contents of the thing, i.e. its properties, are
  777.         then displayed, indented two spaces. Each property
  778.         consists of the property, a colon and the value of
  779.         that property. If the property is defined in any in-
  780.         use table, then the name of the property is printed,
  781.         otherwise '<PROPERTY>' is printed. The value of the
  782.         property is printed much as being described here,
  783.         except that things are not shown expanded, but are
  784.         shown as a name, if one is found in an in-use table,
  785.         or as '<THING>'. Note that properties not known to the
  786.         current character are not displayed, unless the
  787.         current character is SysAdmin. Thus, adding more
  788.         tables to the "in-use" list can cause more properties
  789.         to be displayed on things. However, if a property is
  790.         not publically exported by the wizard who created it,
  791.         only that wizard and SysAdmin can see its value.
  792.  
  793.         action - actions, or functions, or procedures, are printed
  794.         with a short header describing the function. This header
  795.         contains:
  796.  
  797.             - the owner of the function. This is the character
  798.             who defined it.
  799.  
  800.             - the usecount of the function. An function cannot
  801.             be deleted unless this count goes to zero.
  802.  
  803.         Following this header is the definition of the
  804.         function, as pretty-printed by the system. For builtin
  805.         functions, which are pre-implemented, no function body
  806.         is shown. Also, if the owner of the function has made
  807.         it available in some public symbol table, but has not
  808.         marked the function itself as "public", the body is
  809.         not shown, unless it is SysAdmin who is looking. See a
  810.         later section on "Declarations" for an explanation of
  811.         the syntax of functions.
  812.  
  813.         table - only a header is printed for a table. The symbols
  814.         in the table can be displayed using the 'ShowTable'
  815.         builtin. The header for a table contains:
  816.  
  817.             - the owner of the table
  818.  
  819.             - the usecount of the table
  820.  
  821.             - the number of entries in the table
  822.  
  823.         grammar - a grammar is described much the same as a table.
  824.         The words in the grammar can be displayed using the
  825.         'ShowWords' builtin. The header for a grammar
  826.         contains:
  827.  
  828.             - the owner of the grammar
  829.  
  830.             - the usecount of the grammar
  831.  
  832.             - the number of words in the grammar
  833.  
  834.         lists - AmigaMUD has three kinds of lists: lists of 
  835.         integers, lists of things, and lists of actions. Each
  836.         is displayed as a list of values enclosed in braces.
  837.         Integers are shown directly in decimal, and things and
  838.         actions are shown as a symbol, if one is found in the
  839.         in-use tables, or as '<THING>' or '<ACTION>'.
  840.  
  841.         properties - properties are displayed symbolically if a
  842.         symbol for them is found in the set of in-use tables,
  843.         or just as '<PROPERTY>'.
  844.  
  845.         thing-status - a thing status (as returned by the builtin
  846.         'GetThingStatus') is displayed as one of:
  847.  
  848.             ts_private
  849.             ts_readonly
  850.             ts_wizard
  851.             ts_public
  852.  
  853.     edit/ed/e <function-name> - this command is used to interactively
  854.     edit a function. Only the body of a function can be changed -
  855.     its header can only be changed by deleting the function and
  856.     recreating it. Editing can only be done when using the "MUD"
  857.     client program, either locally or remotely, or when using the
  858.     "SMUD" client program locally. "SMUD" will always use an
  859.     external editor, as indicated by your "MUDEDITOR" and "EDITOR"
  860.     environment variables, and "MUD" will use either an internal
  861.     one or an external one, depending on the "Editor" menu
  862.     setting. See the "MUD" document for details on how to use the
  863.     internal editor.
  864.  
  865.     When the editing is done, the AmigaMUD programming language
  866.     parser attempts to "compile" the function. This can fail,
  867.     because of syntax or other errors, in which case the function
  868.     is left unchanged. With the "MUD" internal editor, the errors
  869.     are pointed out one at a time and the user can resubmit the
  870.     function at any point. When using an external editor, the user
  871.     can re-issue the 'edit' command, without giving a function
  872.     name, and will be left editing the file as it was when it was
  873.     submitted for compiling. This cycle can be repeated until the
  874.     function compiles, or the user gives up.
  875.  
  876.     replace <function-definition> - this command can be used, even
  877.     when not using the "MUD" or "SMUD" client programs, to change
  878.     the body of a function. A table containing the function symbol
  879.     must be in-use at the time of the replacement. The entire
  880.     function must be re-entered, including its header. E.g.
  881.  
  882.         > private proc doit()void:
  883.         :      Print("Hello\n");
  884.         : corp;
  885.         >
  886.         > replace doit()void:
  887.         :      int i;
  888.         :      for i from 1 upto 10 do
  889.         :          Print("i = " + IntToString(i) + "\n");
  890.         :      od;
  891.         : corp;
  892.         >
  893.  
  894.     This kind of editing is expected to be most useful in
  895.     conjunction with a terminal program which can do an ASCII-put
  896.     from a file on the remote machine. As with function editing,
  897.     the header of the function cannot be changed.
  898.  
  899.     The replace command can also be useful within source files as
  900.     part of "forward declaring" a function. This is useful when a
  901.     pair (or set) of functions reference each other. E.g.
  902.  
  903.         define myTable proc test1()void: corp;
  904.  
  905.         define myTable proc test2()void:
  906.         ...
  907.         <call to test1>
  908.         ...
  909.         corp;
  910.  
  911.         replace test1()void:
  912.         ...
  913.         <call to test2>
  914.         ...
  915.         corp;
  916.  
  917.  
  918. Data Types
  919.  
  920. There are a number of data types in the AmigaMUD programming language.
  921. Not all are useable in all circumstances. The types are:
  922.  
  923.     void - this is not really a type. It is used as a function return
  924.     type to indicate that the function does not return a value
  925.     (and hence is actually a procedure and not a function). It is
  926.     also the type returned by statements, such as a 'for' loop.
  927.  
  928.     nil - this also is not really a type. It is the type of the
  929.     reserved word 'nil', which represents a non-value for things,
  930.     actions, tables, grammars and lists. This allows values of
  931.     those types to be tested for validity. No other use of this
  932.     type can occur.
  933.  
  934.     status - this type is a three-valued type, with values 'succeed',
  935.     'fail' and 'continue'. The interpretation of these three
  936.     values is at the discretion of the programmer, but a number of
  937.     builtin functions, such as 'FindName', return status values
  938.     with fixed interpretations on the values. It is suggested that
  939.     programmers use similar interpretations to avoid confusion:
  940.  
  941.         'succeed' - the operation has completed successfully
  942.         'fail' - the operation has failed
  943.         'continue' - the operation can be continued
  944.  
  945.     character - this type represents a reference to a player
  946.     character. It is used by a few builtin functions, such as
  947.     'Owner', 'Character', etc. Such a reference is not equivalent
  948.     to a reference to the character thing, such as is returned by
  949.     the 'Me' builtin. Builtins 'CharacterThing' and
  950.     'ThingCharacter' can be used to return one from the other.
  951.  
  952.     bool - this type is a two-valued type, with values 'true' and
  953.     'false'. It is the result of a comparison, and is the required
  954.     type for the condition in an 'if' construct or 'while'
  955.     statement. It is also used with the parsing builtins.
  956.  
  957.     int - this type is a signed 32 bit integer. In the programming
  958.     language, integers can be entered in decimal, hexadecimal,
  959.     octal, or binary. Only decimal conversions are provided as
  960.     builtins.
  961.  
  962.     fixed - this type is a signed 32 bit integer, which has been
  963.     split into two 16 bit halves, the upper half being the whole
  964.     number portion, and the lower half being the fractional part.
  965.     Fixed values are used for graphical coordinates, so that
  966.     drawing commands can be automatically scaled to the actual
  967.     size of the client graphics area.
  968.  
  969.     string - this type represents a character string. The current
  970.     implementation limits strings to about 4000 characters in
  971.     length. Empty strings are allowed. In the programming
  972.     language, strings are surrounded by quotation marks (") and
  973.     may contain escapes for some non-printable characters.
  974.  
  975.     thing - this type represents a pointer to a thing. Things are the
  976.     basic database entity used to represent concepts such as
  977.     rooms and objects. There is a thing associated with each
  978.     player character or NPC. To the programmer, a thing is just a
  979.     set of attribute-value pairs. The attributes are properties
  980.     defined in the database by programmers, and their values can
  981.     be actions (functions), strings, integers, references to other
  982.     things, etc. Each thing also has an owner (the character who
  983.     currently owns it), and a parent (the thing, if any, to start
  984.     inheriting other properties from).
  985.  
  986.     action - actions are just functions or procedures. In AmigaMUD
  987.     they are first-class objects in that they can be stored in the
  988.     database, passed as parameters, and called indirectly. When a
  989.     function is called directly by another, the types and number
  990.     of the parameters and result are checked during the
  991.     compilation of the calling function. When a function is called
  992.     indirectly at runtime, this checking must be done dynamically,
  993.     after the called function has been identified. Thus, there can
  994.     be function-calling errors at runtime. Also, several builtins
  995.     take actions as parameters, and they check the parameters and
  996.     result of such actions at runtime.
  997.  
  998.     table - a table is a symbol table. It is a mapping from strings
  999.     (the symbols) to their values. Such tables are dynamic
  1000.     entities and can be created, manipulated and destroyed at
  1001.     runtime. They are stored in the database along with things,
  1002.     properties, actions, etc. Since tables are values, it is
  1003.     possible to have a symbol in a table whose value is another
  1004.     table. This allows the construction of trees of symbol tables,
  1005.     which is quite useful when organizing a large number of
  1006.     symbols.
  1007.  
  1008.     grammar - a grammar is much like a table, in that it contains a
  1009.     mapping from strings to values. In a grammar, however, the
  1010.     values are special internal ones which the AmigaMUD system can
  1011.     use to parse player input. The use of grammars is described in
  1012.     the section on parsing.
  1013.  
  1014.     list int
  1015.     list fixed
  1016.     list thing
  1017.     list action - lists in AmigaMUD are somewhat of a cross between
  1018.     linked lists and arrays. The size of them is dynamic, and
  1019.     there are builtins to add and remove elements from both ends.
  1020.     Their elements can be retrieved and modified by direct
  1021.     indexing. Such indexing cannot extend the size of the list,
  1022.     however.
  1023.  
  1024.     property bool
  1025.     property int
  1026.     property fixed
  1027.     property string
  1028.     property thing
  1029.     property action
  1030.     property table
  1031.     property grammar
  1032.     property list int
  1033.     property list fixed
  1034.     property list thing
  1035.     property list action - properties in AmigaMUD are the identifiers
  1036.     for attribute-value pairs attached to things. The properties
  1037.     are themselves first-class objects, however, so they can be
  1038.     passed to functions as parameters, and returned as results.
  1039.     Note that only certain types can be attached to things in
  1040.     attribute-value pairs.
  1041.  
  1042.     <thing-status> - this type is not a full type in the language. It
  1043.     has values 'ts_private', 'ts_readonly', 'ts_wizard' and
  1044.     'ts_public'. It is only used as the result type of the builtin
  1045.     'GetThingStatus' and the parameter to 'SetThingStatus'.
  1046.  
  1047. A few other types exist internally, but they are not generally visible
  1048. to the programmer.
  1049.  
  1050.  
  1051. Lexical Entities
  1052.  
  1053.  
  1054. The bottom-level sequences of characters that are known by a
  1055. programming language are called the tokens or lexemes of that
  1056. language. In the AmigaMUD programming language, spaces, tabs and
  1057. newlines are used to separate tokens that would otherwise appear to be
  1058. single tokens, but are otherwise ignored. In other words, the system
  1059. does not care, or even notice, what kind of indentation you use.
  1060.  
  1061. There are two kinds of comments in the language. One is the C-like
  1062. form consisting of characters enclosed within an opening "/*" and a
  1063. closing "*/". Unlike C, however, this kind of comment can be nested in
  1064. AmigaMUD, so that you can comment out a piece of code without worrying
  1065. about whether it has comments inside it. These comments are discarded
  1066. very early in the compilation process, so they do not affect runtime
  1067. at all. The second kind of comment is the 'note' statement. These are
  1068. actually stored in the database and displayed when the function
  1069. containing them is printed out. They also slow down execution of
  1070. functions containing them by a very small amount.
  1071.  
  1072. Newlines are normally ignored when you are in wizard mode. They are
  1073. significant, however, when typing wizard mode commands which accept
  1074. something other than a dollar-terminated expression as their
  1075. parameter. For example, entering just 'source' as an input line in
  1076. wizard mode will yield an error message about a missing file name.
  1077.  
  1078. The reserved words in the AmigaMUD programming language (those symbols
  1079. that cannot be used as regular identifiers by programmers) are:
  1080.  
  1081.     and, or, not, if, then, elif, else, fi, while, do, od, for,
  1082.     from, upto, case, incase, default, esac, ignore, call, note,
  1083.     proc, utility, wizard, public, corp, void, bool, int, fixed,
  1084.     string, thing, status, grammar, character, table, action, list,
  1085.     property, true, false, succeed, fail, continue, nil,
  1086.     ts_private, ts_readonly, ts_wizard, ts_public
  1087.  
  1088. Identifiers (user symbols) look like reserved words, but they aren't
  1089. give any predefined meaning by the system. They can be of any length,
  1090. and are composed of letters, digits and underscores. They must not
  1091. start with a digit. The following are legal identifiers:
  1092.  
  1093.     Fred ThisIsALongIdentifier so_is_this_one fazz_79 x3
  1094.  
  1095. Note that the interpretation of reserved words and identifiers is case
  1096. sensitive; 'And' and 'AND' are valid and different (but badly chosen!)
  1097. identifiers, while 'and' is the reserved word.
  1098.  
  1099. Integers (numbers) can be entered in several forms in the AmigaMUD
  1100. programming language. The normal form is decimal (base 10). A number
  1101. can be prefixed with '0x' for hexadecimal (base 16) interpretation,
  1102. '0o' for octal (base 8) interpretation or '0b' for binary (base 2)
  1103. interpretation. The following are all valid integer constants:
  1104.  
  1105.     1234567890
  1106.     0xcaf4A
  1107.     0o777
  1108.     0b1010101010001010111
  1109.  
  1110. Integers are signed 32 bit quantities in AmigaMUD. Minus signs are not
  1111. part of integer constants - they are unary operators that can be
  1112. applied to them. Thus
  1113.  
  1114.     x := -13;
  1115.  
  1116. is perfectly legal - '-13' is interpreted as the unary '-' operator
  1117. and the integer constant 13.
  1118.  
  1119. Fixed constants are the same as integer constants, except that they
  1120. must contain a decimal point:
  1121.  
  1122.     12.0
  1123.     0.743
  1124.     137.2984
  1125.  
  1126. String constants in AmigaMUD are similar to those in most programming
  1127. languages. They consist of any number of any characters enclosed in
  1128. quotation marks ("). Quotation marks and some unprintable characters
  1129. can be put inside string constants using an escape mechanism. Inside a
  1130. string, a backslash (\) is handled specially, depending on the
  1131. character following the backslash, as follows:
  1132.  
  1133.     \n - a newline character appears in the string
  1134.     \t - a tab character appears in the string
  1135.     \X, where X is any other character - a single X appears in the
  1136.     string. This is how backslashes and quotation marks can be put
  1137.     in string constants.
  1138.  
  1139. An important feature of string constants is the concept of a string
  1140. break. Two string constants, separated only by whitespace and /* */
  1141. comments, are concatenated together into one string constant. This is
  1142. done at "compile" time, and the internal representation used will be
  1143. that of a single string constant. When a function containing a long
  1144. string constant is printed, the string constant will be broken up
  1145. using string breaks in order to fit on the output lines. Such long
  1146. string constants are most often used in output messages, as in:
  1147.  
  1148.     Print("As you open the small wooden door, you detect a strange "
  1149.       "odour coming from the room beyond. The odour seems "
  1150.       "familiar, and you are about to identify it when you fall "
  1151.       "unconscious.");
  1152.  
  1153. Note the spaces within the quotes at the end of the first three lines.
  1154. These are needed to prevent the words from being squished together, as
  1155. e.g. "strangeodour" instead of "strange odour".
  1156.  
  1157. The following operator and punctuation tokens are also recognized:
  1158.  
  1159.     $          used to end input in wizard mode
  1160.     =          simple equality test for various types
  1161.     ==          case ignoring comparison for strings
  1162.     ~          bitwise invert
  1163.     ~=          simple inequality test for various types
  1164.     < <= > >= comparison tests for integers and strings
  1165.     << >>     bitwise shift operators
  1166.     ><          bitwise exclusive-or operator
  1167.     :          punctuation in function headers, after the result type
  1168.     :=          assignment construct
  1169.     +          addition and string concatenation operator
  1170.     --          property deletion operator
  1171.     - * / %   integer arithmetic operators
  1172.     & |       integer bitwise operators
  1173.     ( )       parentheses for subexpressions, function calls, etc.
  1174.     , ;       separators for expressions and statements
  1175.     @          property lookup operator
  1176.     [ ]       brackets for list indexing
  1177.  
  1178.  
  1179. Declarations
  1180.  
  1181.  
  1182. The term "declaration" in the AmigaMUD programming language includes
  1183. the declaration and definition of functions, and the declarations of
  1184. local variables inside a function. AmigaMUD does not have global
  1185. variables - you must use properties attached to things instead.
  1186. Several examples of function (proc, action) definitions have already
  1187. been seen as examples. They consist of:
  1188.  
  1189.     - 'proc'
  1190.     - <optional 'utility'>
  1191.     - <optional 'public'>
  1192.     - <optional 'wizard'>
  1193.     - <the symbol for the proc>
  1194.     - '('
  1195.     - <formal parameter list>
  1196.     - ')'
  1197.     - result type
  1198.     - <optional local variable declarations>
  1199.     - <proc body>
  1200.     - 'corp'
  1201.  
  1202. The 'utility'/'public'/'wizard' tokens can be given in any order. If
  1203. the result type of the proc is 'void', then the <proc body>, which is
  1204. a semi-colon separated list of statements, must end in a statement. If
  1205. the result type of the proc is not void, then the <proc body> must end
  1206. in an expression of that type. That expression will yield the result
  1207. of the proc when the proc is executed. The <formal parameter list> is
  1208. just a semi-colon separated list of declarations, indicating the names
  1209. and types of the parameters that the proc will take when called. The
  1210. list is empty if the proc has no parameters. Note that, unlike some
  1211. languages, like Pascal, when calling a proc with no parameters, the
  1212. parentheses must still be given. This allows the system to distinguish
  1213. calling a proc from the use of the proc as a value (of type 'action').
  1214.  
  1215. A declaration of local variables or proc formal parameters consists of
  1216. at type followed by a comma-separated list of identifiers, and a
  1217. terminating semi-colon. Examples:
  1218.  
  1219.     int i, j, k;
  1220.     action a;
  1221.     property list int pli, l2prop;
  1222.     bool found, ok;
  1223.  
  1224. 'void' is not a valid type for a variable or parameter. When declaring
  1225. formal parameters to a function, the semicolon at the end of the last
  1226. set (before the ')') can be omitted.
  1227.  
  1228. If a function is defined in a private table (one that is not available
  1229. to other wizards and apprentices), then there is no way for others to
  1230. look at it, unless it is attached to a thing as an action property, or
  1231. added to a visible action list. This does not prevent others from
  1232. executing it, however, such as when called by some other function. If
  1233. the proc is visible to others, they can use the 'describe' command, or
  1234. the DescribeSymbol builtin, to look at it. Normally, however, they
  1235. will only be able to see the proc header. If the owner adds 'public'
  1236. when defining the function, then others will be able to see the full
  1237. body of the function, printy-printed for them.
  1238.  
  1239. Normally, when a function is called, the effective character and the
  1240. effective status are set to be the owner of the function. This gives
  1241. the function full access to properties, etc. owned by that character.
  1242. Sometimes, however, especially when SysAdmin is writing functions, the
  1243. setting of the effective state is not desired. In that case, the token
  1244. 'utility' can be added to the declaration. This arranges things so
  1245. that no change of effective character or status is done when the
  1246. function is called. This avoids giving access to private properties,
  1247. etc. The body of the function, however, must be careful to only use
  1248. publicly accessible properties.
  1249.  
  1250. If the token 'wizard' is added to a function definition, then the
  1251. function can only be called when the effective character is a wizard.
  1252. This allows wizards (and apprentices, although that isn't of much use)
  1253. to write wizard-only functions, just like some of the builtin ones.
  1254.  
  1255.  
  1256. Language Constructs
  1257.  
  1258.  
  1259. A number of constructs in AmigaMUD accept a sequence of statements or
  1260. an expression as a part of them. As in many programming languages,
  1261. statements in a sequence of statements are separated by semicolons.
  1262. Such a sequence can have an expression as its final element instead of
  1263. a statement, and thus the entire sequence can be used as an
  1264. expression. This is most often seen as the body of a function. Note
  1265. that this can only happen where specifically indicated - it is not
  1266. legal to replace any arbitrary expression with a sequence of
  1267. statements and an expression. This is trivial to implement, but I
  1268. deliberately did not do so, because of the confusion it can cause.
  1269. AmigaMUD does not have any constructs which only accept a single
  1270. statement as part of them, and thus it does not have any problem with
  1271. "dangling else"'s. All constructs are fully bracketed with reserved
  1272. words, hence there are no "begin"/"end" or "{"/"}" brackets needed.
  1273.  
  1274.  
  1275. The 'if' Construct
  1276.  
  1277.  
  1278. The AmigaMUD programming language has a standard set of language
  1279. constructs, including 'if's, 'while's, 'for's and 'case's. 'if's and
  1280. 'case's can be used as both statements and expressions, i.e. can
  1281. return a value or not return a value. An 'if' construct consists of:
  1282.  
  1283.     - 'if'
  1284.     - a bool expression (the condition)
  1285.     - 'then'
  1286.     - statements/expression to execute if condition is true
  1287.     - zero or more of:
  1288.     - 'elif'
  1289.     - a bool expression (the condition)
  1290.     - 'then'
  1291.     - statements/expression to execute if condition is true
  1292.     - optional:
  1293.     - 'else'
  1294.     - statements/expression to execute if all conditions are false
  1295.     - 'fi'
  1296.  
  1297. A simple example of an 'if' is:
  1298.  
  1299.     if flag then
  1300.     Print("Flag is true.\n");
  1301.     fi;
  1302.  
  1303. A more complex 'if' statement:
  1304.  
  1305.     if a <= b and not flag2 then
  1306.     if a = b then
  1307.         Print("Found!\n");
  1308.     else
  1309.         Print("Not found yet.\n");
  1310.     fi;
  1311.     elif a <= b or not flag2 then
  1312.     Print("Partly found.\n");
  1313.     else
  1314.     Print("No result.\n");
  1315.     fi;
  1316.  
  1317. Note that 'if' constructs can be nested. This is true in general of
  1318. the programming language - there are no limitations other than memory
  1319. available (nesting of constructs is limited only by the available
  1320. stack space - the required space is sufficient for a lot of nesting).
  1321. 'if' expressions can be used like this:
  1322.  
  1323.     max := if b > a then b else a fi;
  1324.  
  1325. An 'if' expression must always have an 'else' part, since there must
  1326. always be some value yielded. The various branches of an 'if'
  1327. expression must all yield the same type of value. The branches of an
  1328. 'if' expression can have statements preceeding the final result, all
  1329. separated by semicolons. E.g.
  1330.  
  1331.     result :=
  1332.     if a < b or b < c then
  1333.         Print("first case\n");
  1334.         a := b;
  1335.         c
  1336.     elif a < b then
  1337.         Print("second case\n");
  1338.         b := a;
  1339.         c
  1340.     else
  1341.         Print("third case\n");
  1342.         a := b;
  1343.         c := b;
  1344.         a
  1345.     fi;
  1346.  
  1347. This kind of construct works fine, but can be a little confusing, so
  1348. they should be used with care. Such large 'if' expressions are most
  1349. often used as the bodies of functions that return a result which
  1350. conditionally depends on something.
  1351.  
  1352.  
  1353. The 'while' Construct
  1354.  
  1355.  
  1356. A 'while' statement consists of:
  1357.  
  1358.     - 'while'
  1359.     - a bool expression (the condition)
  1360.     - 'do'
  1361.     - the loop body statement-sequence
  1362.     - 'od'
  1363.  
  1364. A 'while' loop is executed repeatedly until the condition yields
  1365. false. A 'while' loop does not return any value, i.e. it yields
  1366. 'void'. The condition can have statements before the final 'bool'
  1367. value, thus yielding a loop with its exit test in the middle. E.g.
  1368.  
  1369.     i := 10;
  1370.     while
  1371.     i := retrieveValue(i);
  1372.     i ~= 0
  1373.     do
  1374.     processValue(i);
  1375.     od;
  1376.  
  1377. Here, the sequence of execution will be:
  1378.  
  1379.     i := retrieveValue(10);    /* lets say this returns 8 */
  1380.     processValue(8);
  1381.     i := retrieveValue(8);    /* lets say this returns 3 */
  1382.     processValue(3);
  1383.     i := retrieveValue(3);    /* lets say this returns 0 */
  1384.  
  1385. and 'i' will be 0 after the 'while' loop. Programmers should use care
  1386. when using 'while' loops, since it may not be obvious when the loop
  1387. exits. The AmigaMUD server places an execution time limit on all
  1388. execution, so an infinite loop will be aborted, but, depending on what
  1389. SysAdmin has set that limit to, bad loops can have serious effects on
  1390. the performance of the server for other users. Also, aborting
  1391. execution can leave wizard-created data structures in an inconsistent
  1392. state.
  1393.  
  1394.  
  1395. The 'for' Construct
  1396.  
  1397.  
  1398. A 'for' statement consists of:
  1399.  
  1400.     - 'for'
  1401.     - local int variable name
  1402.     - 'from'
  1403.     - int expression (the start value)
  1404.     - 'upto'
  1405.     - int expression (the limit value)
  1406.     - 'do'
  1407.     - the loop body statement-sequence
  1408.     - 'od'
  1409.  
  1410. Like a 'while' loop, the 'for' loop does not return any value. The
  1411. start and limit expressions are evaluated once at the beginning of the
  1412. loop, and then the int variable is stepped by ones from the start
  1413. value upto the limit value, with the loop body executed once for each
  1414. such value. If the limit value is less than (signed integer
  1415. comparison) the start value, then the loop body is never executed.
  1416.  
  1417. 'for' loops are useful for stepping over fixed ranges, or through the
  1418. entries of a list, as in:
  1419.  
  1420.     GSetPen(nil, C_BLACK);
  1421.     for i from 1 upto 10 do
  1422.     GAMovePixels(nil, i * 2, 30);
  1423.     for j from 1 upto 20 do
  1424.         GRMovePixels(nil, 0, 1);
  1425.         GRDrawPixels(nil, 0, 1);
  1426.     od;
  1427.     od;
  1428.  
  1429.     sum := 0;
  1430.     for j from 0 upto Count(listOfThings) - 1 do
  1431.     sum := sum + listOfThings[j]@intProperty;
  1432.     od;
  1433.     Print("Sum of values = ");
  1434.     IPrint(sum);
  1435.     Print(".\n");
  1436.  
  1437. When using a 'for' loop to scan down a list, make sure that code
  1438. executed in the body of the loop cannot modify the list itself. If it
  1439. can, you must use a 'while' loop, since the 'Count' of the elements in
  1440. the list will be changing.
  1441.  
  1442.  
  1443. The 'case' Construct
  1444.  
  1445.  
  1446. The 'case' construct is in some ways a generalization of the 'if'
  1447. construct. In other ways it is less general. It consists of:
  1448.  
  1449.     - 'case'
  1450.     - int expression (the selector)
  1451.     - one or more "case alternatives", which are:
  1452.     - 'default'
  1453.     - ':'
  1454.     - the alternative statements/expression
  1455.     or
  1456.     - a sequence of "case indexes", which are:
  1457.         - 'incase'
  1458.         - integer constant
  1459.         - ':'
  1460.     - the alternative statements/expression
  1461.     - 'esac'
  1462.  
  1463. Only one 'default' alternative can occur in any given 'case', and if
  1464. the 'case' is a 'case' expression, a 'default' alternative must occur.
  1465. Some examples:
  1466.  
  1467.     case whichButton
  1468.     incase LEFT_BUTTON:
  1469.     doMove(MOVE_LEFT);
  1470.     lastDirection := MOVE_LEFT;
  1471.     incase RIGHT_BUTTON:
  1472.     doMove(MOVE_RIGHT);
  1473.     lastDirection := MOVE_RIGHT;
  1474.     incase EXIT_BUTTON:
  1475.     incase LEAVE_BUTTON:
  1476.     incase OUT_BUTTON:
  1477.     doMove(MOVE_EXIT);
  1478.     lastDirection := MOVE_EXIT;
  1479.     default:
  1480.     if lastDirection ~= -1 then
  1481.         Print("You can't go that way.\n");
  1482.         lastDirection := -1;
  1483.     else
  1484.         Print("You still can't go that way.\n");
  1485.     fi;
  1486.     esac;
  1487.  
  1488.     result :=
  1489.     case retrieveThing()@intProperty
  1490.     incase 0:
  1491.         1
  1492.     incase 1:
  1493.         20
  1494.     default:
  1495.         Print("Illegal value encountered!\n");
  1496.         -1
  1497.     esac;
  1498.  
  1499. C programmers are cautioned that AmigaMUD case alternatives do not
  1500. fall through to the one beneath them. All 'case expressions' must have
  1501. a 'default' part, since some value must always result. 'case
  1502. statements' need not have one, and if the selector does not match any
  1503. of the case indexes, and the 'case' has no 'default' alternative, no
  1504. action is taken.
  1505.  
  1506.  
  1507. Function Calls
  1508.  
  1509.  
  1510. Function calls, whether to a builtin or to a user-defined function,
  1511. consist of the name of the function followed by a left parenthesis, a
  1512. comma separated list of the function parameters, and a right
  1513. parenthesis. The parentheses must be given even if the function has no
  1514. parameters. If no parentheses are given after a function name, then
  1515. the function itself is the value, with type 'action'. All function
  1516. parameters must be given on a call, and must be of the same type as
  1517. required by the function header. If the function has a return-type of
  1518. 'void', then the function call itself yields 'void', i.e. it is a
  1519. statement. Otherwise, the function call yields the type of the
  1520. function result. Examples:
  1521.  
  1522.     Assume:
  1523.     proc f1(int i, j)int
  1524.     proc f2(string s1, s2)string
  1525.     proc f3(int i, string s)void
  1526.  
  1527.     Then:
  1528.  
  1529.     i := f1(1, 2);
  1530.     i := f1(j + 7, k * (13 + l));
  1531.     str := f2("string 1", "string 2");
  1532.     Print(f2("Hello" + f2(str, "out")));
  1533.     f3(0x32af9, "done!");
  1534.     f3(f1(6, j + 7), f2("hello", "there") + "world");
  1535.  
  1536. If the function to be called is not known until run time, then the
  1537. above syntax cannot be used, since the result type of the function is
  1538. not known. Instead, the 'call' construct can be used. This form
  1539. consists of:
  1540.  
  1541.     - 'call'
  1542.     - '('
  1543.     - action expression (returns the function to call)
  1544.     - ','
  1545.     - the expected result type of the action
  1546.     - ')'
  1547.     - '('
  1548.     - the parameters for the function call
  1549.     - ')'
  1550.  
  1551. Since the expected result type is given explicitly, the system can
  1552. assume that type at "compile" time, and can check for it at run time.
  1553. The parameter count and types of the called function will always be
  1554. checked at run time. Examples:
  1555.  
  1556.     Print(call(Me()@p_pDescAction, string)() + "\n");
  1557.     i := i + call(if wantMax then max else min fi, int)(j, k);
  1558.  
  1559.  
  1560. Miscellaneous Constructs
  1561.  
  1562.  
  1563. Sometimes a function or a builtin yields a result that is not always
  1564. wanted - the call is being done for its side effects. In these cases,
  1565. it can be desireable to make it perfectly clear that the result is
  1566. being discarded, so, instead of assigning the result to some dummy
  1567. variable, the 'ignore' construct can be used. It consists of the
  1568. reserved word 'ignore' followed by any expression whose result is to
  1569. be discarded. 'ignore' always returns 'void'. E.g.
  1570.  
  1571.     ignore FindName(Me()@p_pCarrying, p_oName, "bottle");
  1572.     theBottle := FindResult();
  1573.  
  1574. As mentioned previously, there are two kinds of comments in the
  1575. AmigaMUD programming language. The first is the C-like one consisting
  1576. of an opening /*, comment text, and a closing */. The second kind of
  1577. comment is the 'note', which consists of all of the characters after
  1578. the 'note' keyword up to the end of the line. A 'note' comment is
  1579. stored in the database and will appear when the function containing it
  1580. is printed. For example:
  1581.  
  1582.     public proc complicated(thing th)void:
  1583.     note We are doing something complicated here, so be careful!
  1584.     if th@flag then
  1585.         ...
  1586.     else
  1587.         note flag not set, so don't try the tricky stuff.
  1588.         Print("The easy stuff!\n");
  1589.     fi;
  1590.     corp;
  1591.  
  1592. It is not necessary to put a semicolon after a note - they delimit
  1593. themselves, so the parser can recognize them.
  1594.  
  1595. The AmigaMUD system has limited support for direct, unnamed actions.
  1596. These are values of type 'action' and can be assigned and called. They
  1597. are typically only used in specialized circumstances, such as one-shot
  1598. actions produced by the "StringToAction" builtin. They consist of:
  1599.  
  1600.     - 'proc'
  1601.     - optional body statements
  1602.     - result expression
  1603.     - 'corp'
  1604.  
  1605. For example, it is legal to do:
  1606.  
  1607.     myThing@actionProp :=
  1608.     proc
  1609.         Print("Hello there world!\n");
  1610.         void
  1611.     corp;
  1612.     ignore call(myThing@actionProp, void)();
  1613.  
  1614. Such procs have no symbol, so are usually less useful than normal
  1615. functions. Also, the lack of parameters or local variables are a
  1616. limiting factor. The run-time compilation form available through the
  1617. builtin "StringToProc" is much more powerful.
  1618.  
  1619. The most common construct in the AmigaMUD programming language is the
  1620. assignment statement. Assignment statements consist of:
  1621.  
  1622.     - <assignment-left-hand-side>
  1623.     - ':='
  1624.     - <expression>
  1625.  
  1626. Assignment statements do not return any value, hence the concept of
  1627. "nested assignments" does not exist. Several different kinds of
  1628. <assignment-left-hand-side>'s are possible:
  1629.  
  1630.     - local variable or parameter name
  1631.     or
  1632.     - <list-expression>
  1633.     - '['
  1634.     - <int-expression>
  1635.     - ']'
  1636.     or
  1637.     - <thing-expression>
  1638.     - '@'
  1639.     - <property-expression>
  1640.  
  1641. The first variant is the obvious one of assigning a new value to a
  1642. local variable or parameter. The second is that of assigning a new
  1643. value to a specific element of a list. Note that the element indexed
  1644. by the <int-expression> must already be present in the list, else a
  1645. run-time indexing error will occur. Such indexing starts with 0 as the
  1646. first index, and "Count(<list>) - 1" as the last index.
  1647.  
  1648. The third form is used to assign a value to a property on a thing. The
  1649. property does not need to already exist - this method is the method
  1650. used to add new properties also.
  1651.  
  1652. Note that there are no global variables in AmigaMUD - values needed
  1653. outside of a single function must be stored as properties attached to
  1654. some thing.
  1655.  
  1656. Example assignment statements (all are of integer values, but the
  1657. same rules hold for any type of value):
  1658.  
  1659.     private th CreateThing(nil)$
  1660.     private intProp CreateIntProp()$
  1661.     private listProp CreateIntListProp()$
  1662.  
  1663.     private proc testProc(int n)void:
  1664.     int i;
  1665.     list int li;
  1666.     
  1667.     i := 10;
  1668.     n := 100;
  1669.     li := CreateIntList();
  1670.     AddTail(li, 10);
  1671.     Addtail(li, 20);
  1672.     li[0] := 1;
  1673.     li[1] := 2;
  1674.     li(otherFunc()] := 6;
  1675.     th@intProp := 7;
  1676.     th@if i < 2 then intProp else otherIntProp fi := 8;
  1677.     th@listProp := li;
  1678.     th@listProp[1] := 9;
  1679.     call(th@thingProp@actionProp, list int)()[n] := i;
  1680.     corp;
  1681.  
  1682. Properties can be removed from things using the '--' construct:
  1683.  
  1684.     - <thing-expression>
  1685.     - '--';
  1686.     - <property-expression>
  1687.  
  1688. This construct is a statement - it does not return any value. Note
  1689. that it is not an error to try to delete a property from a thing when
  1690. that property does not exist on that thing. Examples:
  1691.  
  1692.     th1--intProp;
  1693.     thingFunc() -- thingPropFunc();
  1694.  
  1695.  
  1696. Expressions
  1697.  
  1698.  
  1699. Many examples of expressions have already been seen. This section will
  1700. simply list the full set of operators, in order of decreasing
  1701. precedence. The precedence of an operator is an indication of how
  1702. strongly it binds to its operands. A simple example is the following
  1703. expression:
  1704.  
  1705.     2 * 4 + 6 * 8
  1706.  
  1707. The value of this expression is 56, the sum of 2 * 4 and 6 * 8. This
  1708. is because the multiplications are done before the addition. The
  1709. multiplication operator, '*', has higher precedence than the addition
  1710. operator, '+'. The evaluation order of an expression can be changed by
  1711. the use of parentheses around a subexpression, as in:
  1712.  
  1713.     2 * (4 + 6) * 8
  1714.  
  1715. which has value 160, the product of 2, 4 + 6, and 8. So, for the
  1716. operators in the following descriptions, those described first will be
  1717. done before those described later, unless parentheses are introduced
  1718. to change the order of evaluation.
  1719.  
  1720. All expressions must start with bottom-level items. These are: 'if'-
  1721. expression, 'case'-expression, function call result, inline action,
  1722. parenthesized sub-expression, list reference, property reference,
  1723. identifier, string constant, integer constant, fixed constant, or
  1724. any of the reserved words 'false', 'true', 'succeed', 'fail',
  1725. 'continue', 'nil', 'ts_private', 'ts_readonly', 'ts_wizard',
  1726. 'ts_public'.
  1727.  
  1728. 'if'- expressions, 'case'-expressions, function calls, inline actions
  1729. and parenthesized sub-expressions have all been covered previously.
  1730. Similarly, the bottom-level items were explained in the section on
  1731. lexical entities.
  1732.  
  1733. A list reference used as an expression looks exactly like the left-
  1734. hand-side of an assignment to a list element. The same rule holds -
  1735. the indexed element must exist in the list.
  1736.  
  1737. A property reference also looks just like the corresponding assignment
  1738. left-hand-side. When a property is being searched for on a thing, it
  1739. might not be found. If the thing has a parent thing (established when
  1740. the thing is created), then the search will continue with that parent
  1741. thing. Any value found on the parent will be used. Similarly, if the
  1742. value is not found on the parent, then the parent's parent will be
  1743. searched, etc. This "inheritance" of properties can be used to save
  1744. considerable space in the database, and to save a lot of effort when
  1745. creating new things which are all similar. Note that things can only
  1746. have a single parent - AmigaMUD does not have "multiple inheritance".
  1747.  
  1748. Good examples of the use of inheritance are the monsters in the
  1749. Proving Grounds in the standard scenario. Each monster has a model,
  1750. defined in the file "monsters.m", and when examples of that monster
  1751. are needed, they inherit most of their properties (name, description,
  1752. actions, speed, armour class, special actions, etc.) from the model.
  1753. Only values which need to be different (such as current hit points)
  1754. are stored on the specific instance. The fact that property assignment
  1755. only assigns to the descendant thing makes this use automatic.
  1756.  
  1757. A tricky use of inheritance can occur with things which inherit from
  1758. an ancestor, as in:
  1759.  
  1760.     private ancestor CreateThing(nil)$
  1761.     private child CreateThing(ancestor)$
  1762.     private intProp CreateIntProp()$
  1763.  
  1764.     ancestor@intProp := 100$
  1765.  
  1766.     ...
  1767.  
  1768.     child@intProp := child@intProp - 1;
  1769.     if child@intProp = 0 then
  1770.         child -- intProp;
  1771.     fi;
  1772.  
  1773. This assignment statement will get the 100 value from the ancestor
  1774. thing the first time it is executed, and will add the property with
  1775. value 99 to the child. On successive executions, it will modify the
  1776. property on the child. When the value reaches 0, the property is
  1777. deleted, and will again inherit the 100 from the ancestor. Although
  1778. this works, most programmers would just set the child value to 100
  1779. directly, rather than deleting the child's property. If values
  1780. different from the parent value are very rare, however, and there are
  1781. a lot of child things around, using the inheritance trick can save
  1782. some space in the database.
  1783.  
  1784. If a property which is not present on the thing is referenced, the
  1785. value yielded depends on the type of the property:
  1786.  
  1787.     status - fail
  1788.     bool - false
  1789.     int - 0
  1790.     fixed - 0.0
  1791.     string - "" (an empty string)
  1792.     thing, action, grammar, list - nil
  1793.  
  1794. This defaulting of values is usually useful, but can occasionally be a
  1795. bit of a nuisance. The main use is to save storage - the programmer
  1796. can count on these values for missing properties, and hence can
  1797. arrange to not store them explicitly. This works quite well for flag
  1798. values.
  1799.  
  1800.  
  1801. Unary Negation: -
  1802. Unary BitWise Invert: ~
  1803.  
  1804.     The negation operator appears before an int expression and negates
  1805.     the value of the expression. E.g.
  1806.  
  1807.     -6
  1808.     -(intvar * 7)
  1809.     -th@func(7, -6)
  1810.  
  1811.     The bitwise invert operator similarly takes an int expression, but
  1812.     yields a result in which all 32 bits are flipped. E.g.:
  1813.  
  1814.     ~ 0b10110 => 0b11111111111111111111111111101001
  1815.     ~ -1 => 0b0
  1816.  
  1817. Bitwise And: &
  1818. Bitwise Exclusive-Or: ><
  1819. Bitwise Shift Left: <<
  1820. Bitwise Shift Right: >>
  1821.  
  1822.     These operators all operate on int values. They all have the same
  1823.     precedence, so are evaluated left-to-right when used together in
  1824.     an expression. The Bitwise And operator combines two int values in
  1825.     a bit-by-bit fashion - each of the 32 bits of the result is a '1'
  1826.     bit only if both of the corresponding bits in the operands were
  1827.     also '1' bits. The Bitwise Exclusive-Or operator yields a '1' bit
  1828.     in the result only if the corresponding bits in the operands are
  1829.     different. The Shift-Left operator shifts its left-hand operand
  1830.     left by the number of bits specified in its right-hand operand.
  1831.     Similarly, the Shift-Right operator shifts its left-hand operand
  1832.     right by the number of bits specified in its right-hand operand.
  1833.     If the right-hand operand to a shift operator is negative, it is
  1834.     not defined what the result will be. Also, if the right-hand
  1835.     operand is greater than 32 (the number of bits in the left-hand
  1836.     operand), the result is not defined. E.g.
  1837.  
  1838.     0b1100 & 0b0101 => 0b0100
  1839.     0b1100 >< 0b0101 => 0b1001
  1840.     0b001100 << 2 => 0b110000
  1841.     0b001100 << 3 => 0b1100000
  1842.     0b001100 >> 2 => 0b000011
  1843.  
  1844.     a & b >< c << d >> e == ((((a & b) >< c) << d) >> e)
  1845.  
  1846.     Note that both shift directions are unsigned shifts, even though
  1847.     the 'int' type is a signed value. This means that on a right
  1848.     shift, the value shifted in on the left-hand-end is all zero bits.
  1849.  
  1850. Bitwise Inclusive-Or: |
  1851.  
  1852.     This operator requires two int operands and returns an int result.
  1853.     Each of the 32 bits in the result is a '1' if the corresponding
  1854.     bit in either of the operands is a '1'. E.g.
  1855.  
  1856.     0b1100 | 0b0101 => 0b1101
  1857.     a & b | c << d | e == (a & b) | (c << d) | e
  1858.  
  1859. Integer Multiplication: *
  1860. Integer Division: /
  1861. Integer Remainder: %
  1862. Fixed Multiplication: *
  1863. Fixed Division: /
  1864.  
  1865.     These operators take a pair of int or fixed operands and yield
  1866.     an int (or fixed) result. Division or remainder by zero will
  1867.     be trapped at runtime.
  1868.  
  1869. Integer Addition: +
  1870. Integer Subtraction: -
  1871. Fixed Addition: +
  1872. Fixed Subtraction: -
  1873. String Concatenation: +
  1874.  
  1875.     Note that both numeric addition and string concatenation have the
  1876.     same operator symbol. The operations are distinguished by the
  1877.     types of their operands. E.g.
  1878.  
  1879.     6 + 128 => 134
  1880.     6 - 128 => -122
  1881.     12.7 + 128.003 => 140.703
  1882.     "hello" + "world" => "helloworld"
  1883.     "hello " + "world" => "hello world"
  1884.     "" + "" => ""
  1885.  
  1886. Integer Comparisons: <= < = ~= > >=
  1887. Fixed Comparisons: <= < = ~= > >=
  1888. String Comparisons: <= < = ~= == > >=
  1889. Other Comparisons: = ~=
  1890.  
  1891.     All comparisons yield a bool value. All comparisons must have
  1892.     operands which are both of the same type. The integer comparisons
  1893.     are 32 bit signed integer comparisons. The string comparisons use
  1894.     comparisons based on the ASCII values of the characters in the
  1895.     strings. The '==' operator converts all letters to upper case (or
  1896.     lower case if you prefer!) before doing the comparison. It is
  1897.     useful when dealing with user input that might be capitalized.
  1898.     Things, actions, lists, properties, etc. can be compared for
  1899.     equality or inequality. E.g.
  1900.  
  1901.     6 < 12 => true
  1902.     -6 < -12 => false
  1903.     12.7 < 12.65 => false
  1904.     "hello" = "hello" => true
  1905.     "hello" <= "hello" => true
  1906.     "hello" = "Hello" => false
  1907.     "hello" == "Hello" => true
  1908.  
  1909. Logical Not: not
  1910.  
  1911.     This prefix operator reverses the logical value of its bool
  1912.     operand. E.g.
  1913.  
  1914.     not true => false
  1915.     not false => true
  1916.     not 6 < 10 => false
  1917.  
  1918. Logical And: and
  1919.  
  1920.     This operator takes two bool operands and returns a bool result
  1921.     that is true only if both operands are true. Technically, this is
  1922.     a language construct rather than a true operator, since the
  1923.     AmigaMUD interpreter will not even try to evaluate the right-hand
  1924.     operand if the left-hand operand evaluates to false, since it
  1925.     knows that the right-hand operand will not affect the final
  1926.     result. This behaviour is part of the language definition and will
  1927.     not change; thus the programmer is correct to write things like:
  1928.  
  1929.     th ~= nil and th@field = 2
  1930.  
  1931. Logical Or: or
  1932.  
  1933.     This operator takes two bool operands and returns a bool result
  1934.     that is true if either of its operands is true. Similar to the
  1935.     'and' operator, the 'or' operator will not evaluate its right-hand
  1936.     operand if its left-hand operand is "true".
  1937.  
  1938.  
  1939. Further Reading
  1940.  
  1941. This document has informally defined the AmigaMUD programming
  1942. language. This information allows wizards and apprentices to write and
  1943. run valid AmigaMUD programs, but it has not given enough information
  1944. to allow them to write meaningful programs, or programs that fit in
  1945. with the supplied standard scenario. Further documents relevant to
  1946. programming are:
  1947.  
  1948.     ProgConcepts.txt - discusses some classes of builtin functions and
  1949.     how to use them. This includes parsing, effects handling,
  1950.     graphics, character manipulation, etc.
  1951.  
  1952.     Builtins.txt - this is a reference manual for the builtin
  1953.     functions. It lists and describes all of the builtins, in
  1954.     alphabetical order.
  1955.  
  1956.     Scenario.txt - this document is a rambling discussion of how the
  1957.     standard scenario is set up, the utility functions it
  1958.     provides, how to build from it, and how to change how it
  1959.     works.
  1960.