MUCK.doc -------- Terminology: + MUCK additon * Wizard only # Restricted with GOD_PRIV B Builder command -- may be restricted P Programmer command -- restricted unless MUCKER_ALL ~ Optional % Special @ACTION [+B] @action =. Creates a new action and attaches it to the thing, room, or player specified. You may only attach actions you control to things you control. Creating an action costs 1 penny. The action can then be linked with the command @LINK. @ATTACH [+B] @attach =. Removes the action from where it was and attaches it to the new source. You must control the action in question. @BOOT [*] @boot . Disconnects a player from the game. If a player is connected more than once it affects the most recent connection. @CHOWN [%] @chown [=]. Changes the ownership of to , or if no player is given, to yourself. If the MUCK is compiled with PLAYER_CHOWN, all players are allowed to take possession of objects, rooms, and actions, provided the CHOWN_OK flag is set. Mortals cannot take ownership of a room unless they are standing in it, and may not take ownership of an object unless they are holding it. Wizards have absolute power over all ownership. @CREATE [B] @create [=]. Creates a new object and places it in your inventory. This costs at least ten pennies. If is specified, you are charged that many pennies, and in return, the object is endowed with a value according to the formula ((cost / 5) - 1). Usually the maximum value of an object is 100 pennies, which would cost 505 pennies to create. @DESCRIBE @describe [=]. Sets the description field of to . If is not specified, the description field is cleared. @DIG [B] @dig [=]. Creates a new room and sets its parent. If no parent is given it defaults to the global environment which is typically room #0. Digging a room costs 10 pennies, and you must be able to link to the parent room if specified. @DROP [+] @drop [=]. Sets the drop field of to . If is not specified, the drop field is cleared. The drop message on an object is displayed when you drop it. On an exit, it is displayed upon entering the destination room. On a player it is displayed to whoever kills them. On a room, it is displayed when an object is dropped there. @DUMP [*] @dump. Saves the database to disk. This is done automatically every hour or so, and after an @shutdown. @EDIT [+P] @edit . Searches for a program and if a match is found, puts the player into edit mode. Programs must be created with @PROG. @FAIL @fail [=]. Sets the fail field of to . If is not specified, the fail field is cleared. @FIND @find []. Searches through the entire database for rooms, things, players, and programs you control, optionally matching their names to if given. This usually costs at least a penny due to the computing power involved. @FORCE [*#] @force =. Causes the game to process as if typed by . With the compile option GOD_PRIV, God cannot be forced by his/her sub-wizards. @LINK @link = [; ; ... ]. Links to , provided you control , and is either controlled by you or linkable. Actions may be linked to more than one thing, specified in a list separated by semi-colons. @LIST @list [=[line1] [-] [line2]]. Lists lines in a program, provided you control it or it is LINK_OK. Zero, one, or two line numbers may be specified, denoting the range of lines to list. If no lines are given, the entire program is listed. @LOCK @lock =. Sets the key for to that specified by . is a full boolean expression, which may contain any of the characters: ! | & ( ). @NAME @name = []. Sets the name field of to . cannot be empty; a null name is illegal. must be supplied to rename a player. Wizards can rename any player but still must include the password. @NEWPASSWORD [*#] @newpassword [=]. Sets the password field of to . If is not specified, the password field is cleared. A player with no password cannot rename him/herself. If GOD_PRIV was defined, nobody can change God's password. @ODROP [+] @odrop [=]. Sets the odrop field of to . If is not specified, the odrop field is cleared. Odrop on an object is displayed prefixed by the player's name when s/he drops that object. On an exit, it is displayed upon a player's arrival to the destination room (or the location of the destination player). On a player, it is displayed after the `name killed victim!' message. On a room, it is displayed when an object is dropped there, prefixed by the object's name. @OFAIL @ofail [=]. Sets the ofail field of to . If is not specified, the ofail field is cleared. @OPEN [B] @open [= [; ; ... ]]. Opens an exit in the current room, optionally attempting to link it simultaneously. Opening an exit costs a penny, and an extra penny to link it, and you must control the room where it is being opened. @OSUCCESS @osucc [=]. Sets the osuccess field of to . If is not specified, the osuccess field is cleared. @OWNED @owned []. Lists everything you own, or Wizards may specify a player argument. This list includes exits, unlike @FIND. @PASSWORD @password =. Change your password. @PCREATE [*#~] @pcreate =. This command is only used under the compile option REGISTRATION. Create a new player named with . @PROG [+P] @prog . Create a new program, or enter edit mode on an existing one. See @EDIT and Programmer's Reference. @RECYCLE [+~] @recycle . Destroy an object and remove all references to it within the database. The object is then added to a free list, and newly created objects are assigned from the pool of recycled objects first. You *must* own the object being recycled, even wizards must use the @chown command to recycle someone else's belongings. @SET @set = [!] -or- @set = : [ ] -or- @set = : @set does one of three things on TinyMUCK, it can modify flags, add properties to an object, or remove properties from an object. Using the first format, you may set flags, which are: WIZARD, LINK_OK, DARK [DEBUG], FILTER, STICKY [SETUID], or JUMP_OK. Optional flags which may or may not be on a given site are: BUILDER, CHOWN_OK, HAVEN, ABODE, or MUCKER. The second format sets on to , or if is not given, removes . The third format removes all properties from an object. @SHUTDOWN [*] @shutdown. Dumps the database and shuts the game down. @STATS @stats []. For mortal players, returns the highest number in the database, which includes garbage that has been generated with @recycle. For Wizards, gives this number as well as a breakdown of each type of object: rooms, exits, things, programs, players, and garbage. Wizards may also specify which returns a similar display limited to the possessions of . @SUCCESS @succ [=]. Sets the success field of to . If is not specified, the success field is cleared. @TELEPORT @teleport [=]. Moves to , if is not given, moves you to . Wizards may teleport anything to anywhere, provided it makes sense, and mortals are allowed to do two things: teleport rooms to change their parent fields, and the may teleport things to a room they can link to, provided they control either the thing or its location. @TOAD [*] @toad . Turns into a slimy toad, destroying his/her character and disconnecting him/her from the game. @TRACE [+] @trace [=]. Starts with and traces all location fields, until the global-environment room is reached or the optional is specified. This is generally useful for finding which rooms are parents in your heirarchy. If you cannot link to a particular location its name is replaced by stars ***. @UNLINK [B] @unlink . Removes any and all destination fields of the specified . @UNLOCK @unlock . Removes any and all locks on the specified . @WALL [*] @wall . Shouts a message to every player in the game. DROP drop . Drops the if you are holding it. It moves the object to the room you are in, unless its STICKY flag is set, or the room has a drop-to. Programs are much like objects but are not affected by room droptos or STICKY flags. EXAMINE examine . If you control , a complete breakdown of all fields, flags, properties, etc. associated with the object is displayed. Program-executing fields are displayed as their true text, rather than executing the program in question. If you do not control , however, it prints the owner of the object in question, and, again, displays the true text of the description. GET get . Attempts to pick up . The lock on is checked for a success (true), and the normal path of success/fail is then taken. On success the object is placed in your inventory. GIVE give =. Gives pennies from your supply to . Mortals may only give positive amounts and may not cause a player to have more than 10000 pennies. Wizards do not affect their penny supplies by giving to others, and may also give pennies to objects, changing that object's value. GOTO goto . Attempts to find an exit by that name. Goto is unnecessary and much like LET in Basic (read: silly). GRIPE gripe . Sends to the system maintainer. HELP help. Displays the help file. INVENTORY inventory. Lists the objects you are carrying, as well as how many pennies you have. KILL kill [=]. A successful kill sends the player home, sends all objects in the player's inventory to their respective homes. The probability of killing the player is percent. Spending 100 pennies always works except against Wizards who cannot be killed. Players cannot be killed in rooms which have the HAVEN flag set. LOOK look . Looks around at the current room, or at if specified. For players, displays their description and inventory, for things, their description, and for rooms, their name, description, succ/fail message, and contents. Also triggers osucc/ofail messages on rooms. Programs are triggered accordingly on desc/succ/fail fields. MOVE move . See GOTO. MAN [+] man. Displays the programmer's manual or a quick reference. NEWS news. Displays the game's news file. OUTPUTPREFIX OUTPUTPREFIX [string]. Must be in all capitals, and must be typed in full. This prints the given string before the output of every command. OUTPUTSUFFIX [string]. Must be in all capitals, and must be typed in full. This prints the given string after the output of every command. PAGE page [=]. Costs a penny, and sends your name and location to , optionally passing them as well. A player who is set HAVEN cannot be paged, and will not be notified that you tried. POSE or : :. Displays your name, followed by . PUT put . See DROP. QUIT QUIT. Logs you off the game. Must be typed all capitals. READ read []. Synonym for LOOK. ROB rob . Attempts to steal a penny from . The lock on is checked, and you succeed or fail appropriately. If you succeed, the message `You stole a penny.' is always displayed. SAY or " ". Displays the message, says, "". SCORE score. Displays how many pennies you have. TAKE take . Synonym for GET. THROW throw . Synonym for DROP. WHISPER whisper =. Gives a private message, undetectable by others in the same room. WHO WHO []. List names of the players logged in, and their idle times. If is specified, only names that start with are displayed. Must be typed in all capitals. o . If is not specified, the ofail field is cleared. @OPEN [B] @open [= [; ; ... ]]. Opens an exit in the current room, optionally attempting to link it simultaneously. Opening an exit costs a penny, and an extra penny to link it, and you must control the room where it is being opened. @OSUCCMUCK.editor.help Program commands: ---------------- compile compile program delete delete lines insert insert program lines list list program lines uncompile disassemble program [not usually useful] Library commands: ---------------- abridged show list of library functions, names only kill kill library reference show show list of library functions, full display view view program header help this file Commands may be abbreviated to their first letter. The library comands work just like program commands, except that they take alphabetic parameters instead of integers. You would type: bar garply show to see all the library routines between "bar" and "garply", much as you would type: 1 23 list to list all the lines of your program between 1 and 23. The "view" command lets you know more about a library routine you might find using "show" or "abridged". View takes a numeric argument-- the object number of the program you want to look at. It will print out the program header and that only-- which should give you all the information you need to use it, provided that the library routines are well-written. Kill (which may only be used by wizards) deletes a library entry. es the object to the room you are in, unless its STICKY flag is set, or the rMUCK.forth.ref -or- Reference manual for MUCK Forth ("MUF") -terse v2.2 August 4, 1990 ENTERING EDITING MODE @prog (creates a new program if none match) @edit EDITING COMMANDS i insert before . exit insert mode c compile l list d delete a show macros (abridged) s show macros (long) v view program header h help on edit mode u uncompile q quit editor mode PRIMITIVE TERMINOLOGY v type variable d type dbref i type int (boolean) s type string a type address (word) SYNTAX ( ... ) commments : begin user-def word ; end user-def word var variable declaration if ( i -- ) else ( -- ) then ( -- ) exit ( -- ) execute ( a -- ??? ) pop ( x -- ) dup ( x -- x x ) swap ( x y -- y x ) over ( x y -- x y x ) rot ( x y z -- y z x ) rotate ( ni ... n1 i -- n(i-1) ... n1 ni ) pick ( ni ... n1 i -- n1 ni ) put ( ni ... n1 x i -- x ... n1 ) ! ( x v -- ) store value x in var v. value may be any type data @ ( v -- x ) fetch value x from var v atoi ( s -- i ) string --> integer intostr ( i -- s ) integer || dbref --> string dbref ( i -- d ) integer --> dbref int ( x -- i ) VAR || object --> integer variable ( i -- v ) integer --> VAR ref + - * / % ( i1 i2 -- i ) < > = <= >= ( i1 i2 -- i ) strcmp, stringcmp ( s1 s2 -- i ) strcmp == case sens. strncmp ( s1 s2 n -- i ) compares only n letters number? ( s -- i ) dbcmp ( d1 d2 -- i ) and or ( i1 i2 -- i ) not ( i -- i' ) strlen ( s -- i ) strcat ( s1 s2 -- s ) instr ( s1 s2 -- i ) finds string s2 within s1 strcut ( s i -- s1 s2 ) cuts string at pos. i explode ( s1 s2 -- ... i ) s2 is the partition, len >0 subst ( s1 s2 s3 -- s ) string, replacement, tobesub pronoun_sub ( d s -- s' ) does % subs a la osucc/ofail read ( -- s ) notify ( d s -- ) player, message notify_except ( d1 d2 s -- ) place, player, message pennies ( d -- i ) addpennies ( d i -- ) player, pennies random ( -- i ) getpropval ( d s -- i ) zero if none getpropstr ( d s -- s ) "" if none addprop ( d s1 s2 i -- ) ignores i unless s2 is "" remove_prop ( d s -- ) desc, name, succ, fail, drop, osucc, ofail, odrop: ( d -- s ) retrieve message setname, setdesc, setsucc, setfail, setdrop, setosucc, setofail: ( d s -- ) set message player?, thing?, room?, program?, exit?, ok?: ( d -- i ) boolean location ( d -- d' ) owner ( d -- d' ) moveto ( d1 d2 -- ) moves d1 to d2 set ( d s -- ) object, string (flag) flag? ( d s -- i ) object, string, boolean call ( d -- ??? ) call remote program match ( s -- d ) thing, dbref (#-1 = NOTHING, #-2 = AMBIGUOUS, #-3 = HOME) rmatch ( d s -- d ) object, thing, dbref copyobj ( d -- d' ) returns dbref of new object contents ( d -- ... i ) returns stack of dbrefs and i lays their description and inventory, for things, their description, and for rooms, their name, description, succ/fail message, and contents. Also triggers osucc/ofaiMUF.examples which is an english description of the contents. For example, for Contents: a bell a book it would print: a bell, a book, and a candle. a candle Contents: Huey it would print: Huey and Dewey Dewey Contents: it would print: an apple an apple If there is nothing in the room, it will print "nothing." (english-list) (3 vars) ( list -- s ) ( ) ( list is a list of dbrefs with an integer on ) ( top [a la 'contents']; s is an English ) ( string describing said contents. ) ( ) var manysofar var howmany var accumulate : itemprelist dup 0 = if pop exit then (check to see if we're done. ) swap manysofar @ 1 + manysofar ! (count how many items we've seen.) name ", " manysofar @ howmany @ 1 - = if (separate items with a comma, ) pop ", and " then (unless there are only two or it ) howmany @ 1 = if pop " " then (is the last item in the list. ) howmany @ 2 = if pop " and " then manysofar @ howmany @ = if pop "." then (end with a period. ) strcat accumulate @ swap strcat accumulate ! (add the text to the new string. ) 1 - itemprelist (if not done, loop around. ) ; : itemlist dup howmany ! (howmany is the number of items in the list ) 0 manysofar ! (manysofar is how many we've counted; initialize. ) "" accumulate ! itemprelist (do the loop that concats the item names together.) accumulate @ "" strcmp if (return the value of accumulate, or "nothing' if ) accumulate @ (we didn't find anything in the room. ) then "nothing." ; (The next part actually puts the above program to use.) : show-contents-in-English me @ "In this room, you see " loc @ contents (get the list to pass to the function. ) itemlist pop strcat notify ; The next two are simple shortcuts to see if a player is male or female. ( male ) ( d -- i ) ( d is the player's dbref, i is a boolean. ) ( ) : male "sex" getpropstr "male" strcmp if 0 exit then 1 ; ( female ) ( d -- i ) ( d is the player's dbref, i is a boolean. ) ( ) : female "sex" getpropstr "female" strcmp if 0 exit then 1 ; This next is a little search-and-replace hack. ( search-and-replace ) (3 vars) ( s1 s2 s3 -- s ) ( ) ( Searches through s1 for all occurences of ) ( word s3 and replaces them with s2. Only ) ( occurences which stand alone [are bordered ) ( by spaces on both sides] are detected. ) ( Not case sensitive. ) ( Right now it's a bit tacky since it will ) ( miss words ending in punctuation; for this ) ( we need a strncmp primitive. ) ( ) var recurse var old_word var new_word : dostuff recurse @ 2 < if exit then ( If we're done, exit. ) swap dup old_word @ stringcmp not (If the word we're looking at now matches) if pop new_word @ then (the word we're looking for, pop it and ) " " swap strcat strcat (replace with new_word. ) (Concatenate whatever still happens to be) (there back onto the string we're re- ) (constructing. ) recurse @ 1 - recurse ! (Update our recursion counter. ) dostuff (Loop back and continue. ) ; : search-and-replace old_word ! (Set old_word and new_word to the parameters ) new_word ! (we were passed. ) " " explode (Explode the string we were passed [separate it) recurse ! ( into words] for the loop to use. ) dostuff (Do the loop. ) ; (Written by Stinglai) The next is an update [more readable, even] of the old one-armed bandit routine. : abs ( i -- i ) (absolute value) dup 0 < if -1 * then ; : amt ( -- i ) (random number between -100 and 100.) random 21 % 10 - 10 * ; : give ( d -- ) me @ swap addpennies (give the player some pennies) ; : msg ( i s -- d s ) swap abs intostr " pennies!" (make tail half of the message) strcat strcat me @ swap ; : winlose dup dup abs = dup (is the number we got = to its absolute ) if pop "win" exit (value? i.e., is it positive? ) then not if "lose" then ; (send the right message accordingly. ) : tell dup winlose "You " swap (print "You [win/lose] x pennies!" ) strcat " " strcat msg notify ; : announce dup loc @ swap me @ swap notify (Tell the player what happened. ) loc @ swap me @ swap notify_except (Tell everyone else what happened. ) ; : pull amt tell announce give (Main prog.) ; (Written by WhiteRabbit) item names together.) accumulate @ "" strcmp if (return the value of accumulate, or "nothing' if ) accumulate @ (we didn't find anMUF.manual This manual was compiled largely from the original MUF reference manual, with help from Black_Dougal. It is intended more as a reference work than as a tutorial, and should be current through TinyMUCK 2.1.1. Please feel free to e-mail me any errata or addenda at rawdon@rex.cs.tulane.edu. - Jethro Updated completely for TinyMUCK release 2.2 by me -- ChupChup DICTIONARY OF MUF EDITOR COMMANDS --------------------------------- See @PROG and @EDIT in the MUCK Reference Sheets for information about enterting the editor. i Enter insert mode before line #i. Any number of lines may be contiguously inserted. The old line #i will become the first line after the inserted lines. Blank lines are ignored and do not become part of the program. Entering the character `.' (period) alone on a line (not preceded or followed by any spaces) exits insert mode. The `.' does not become a line. l Display all lines from to inclusive. If only one is given, only that line will be displayed. d Delete all lines from to inclusive. If only one is given, only that line will be deleted. c Compile the program you are editing. This must be done before a program will run properly. u Unassemble program. This was used to test MUF during its development. It has no real use for programmers. n Toggle display of numbers in program listings. q Quit from the editor. @Q may also be used to do this. s Show macros in long format: name of macro, name of the person who entered it, and the body of the macro. `a z s' will show all macros, for instance. a Abridged macro display. Shows only the names of macros. DICTIONARY OF MUF PRIMITIVES ---------------------------- CONVENTIONS: d: database reference; i: integer; s: string; v: variable; a: function address; x, y: Any of the above. + - * / % ( i1 i2 -- i ) These words perform arithmetic operations on numbers. `+' = addition (i1 + i2); `-' = subtraction (i1 - i2); `*' = multiplication (i1 times i2, or i1 * i2); `/' = division (i1 divided by i2, or i1 / i2) with integer division truncation of fractions; `%' = modulo (remainder of i1 / i2, or i1 % i2) Please note: all these operations may also be performed where i1 is a variable type. This is mainly useful in calculating an offset for a variable array. < > = <= >= ( i1 i2 -- i ) Performs relational operations on integers i1 and i2. These return i as 1 if the expression is true, and i as 0 otherwise. @ ( v -- x ) Retrieves variable v's value x. ! ( x v -- ) Sets variable v's value to x. addpennies ( d i -- ) d must be a player or thing object. Adds i pennies to object d. Without Wizard permissions, addpennies may only give players pennies, limited to between zero and MAX_PENNIES. addprop ( d s1 s2 i -- ) Sets property associated with s1 in object d. Note that if s2 is null "", then i will be used. Otherwise, s2 is always used. All four parameters must be on the stack; none may be omitted. If the effective user of the program does not control the object in question and the property begins with an underscore `_', the property cannot be changed. The same goes for properties beginning with a dot `.' which cannot be read without permission. If you store values, you must ensure that it they are never zero. Otherwise, when the user stores a non-zero number into the string field, (users may only access string fields) the next time TinyMUCK is dumped and loaded up again, the value field will be replaced with atoi(string field). If it is necessary to store zero, it is safer to just add 1 to everything. and ( x y -- i ) Performs the boolean `and' operation on x and y, returning i as 1 if both i1 and i2 are TRUE, and returning i as 0 otherwise. atoi ( s -- i ) Turns string s into integer i. If s is not a string, then 0 is pushed onto the stack. call ( d -- ?? ) Calls another program d. d must have been compiled already. d will inherit the values of ME, LOC, TRIGGER, and all other variables. contents ( d -- d' ) Pushes the dbref of the first thing contained by d. This dbref can then be referenced by `next' to cycle through all of the contents of d. d may be a room or a player. copyobj ( d -- d' ) Creates a new object (returning d' on top of the stack), that is a copy of object d. Each program is allowed to create only one new object per run. dbcmp ( d1 d2 -- i ) Performs comparison of database objects d1 and d2. If they are the same object, then i is 1, otherwise i is 0. dbref ( i -- d ) Converts integer i to object reference d. desc ( d -- s ) Takes object d and returns its description (@desc) string field. drop ( d -- s ) Takes object d and returns its drop (@drop) string field. dup ( x -- x x ) Duplicates the item at the top of the stack. execute ( a -- ?? ) Executes the function pointed to by the address a on the stack. exit ( -- ) Exits from the word currently being executed, returning control to the calling word, at the statement immediately after the invokation of the call (exiting the program if applicable). exit? ( d -- i ) Returns 1 if object d is an exit object, 0 if otherwise. See also player?, program?, room?, thing?, ok?. exits ( d -- d' ) Returns the first exit in the linked exit list of room/player/object d. This list can be transversed with `next'. explode ( s1 s2 -- ... i ) s2 is the delimiter string, and s1 is the target string, which will be fragmented, with i pushed on top of the stack as the number of strings s1 was broken into. For instance: "Hello world" " " explode will result in "world" "Hello" 2 on the stack. (Note that if you read these items off in order, they will come out "Hello" first, then "world".) For TinyMUCK 2.2, s2 may be any length. But "" (null string) is not an acceptable string for parameter s2. fail ( d -- s ) Takes object d and returns its fail (@fail) string field. flag? ( d s -- i ) Reads the flag of object d, specified by s, and returns its state: 1 = on; 0 = off. Different flags may be supported in different installations. flag? returns 0 for unsupported or unrecognized flags. getlink ( d -- d' ) Returns what object d is linked to, or #-1 if d is unlinked. The interpretation of link depends on the type of d: for an exit, returns the room, player, program, action, or thing that the exit is linked to. For a player, program, or thing, it returns its `home', and for rooms returns the drop-to. getpropstr ( d s -- s ) s must be a string. Retrieves string associated with property s in object d. If the property is cleared, "" (null string) is returned. getpropval ( d s -- i ) s must be a string. Retrieves the integer value i associated with property s in object d. If the property is cleared, 0 is returned. if ... [ else ... ] then ( x -- ) Examines boolean value x. If x is TRUE, the sequence of statements after the 'if' up until the `then' (or until the `else' if it is present) performed. If it is FALSE, then these statements are skipped, and if an `else' is present, the statements between the `else' and the `then' are performed. Control continues as usual at the statement after the `then'. Note that checking the top of the stack actually pops it, so if you want to re-use it, you should dup (see DUP) it before the if. For every IF in a word, there MUST be a THEN, and vice-versa. ELSE is optional. instr ( s s1 -- i ) Returns the first occurrence of string s1 in string s, or -1 if s1 is not found. See also rinstr. int ( x -- i ) Converts variable or object x to integer i. intostr ( x -- s ) x must be an integer or a dbref. Converts x into string s. jmp ( a -- ) Jumps to address a. Used internally by the compiler for constructing else clauses, jmp cannot be generated by user code. location ( d -- d' ) Returns location of object d as object d'. match ( s -- d ) Takes string s, first checks all objects in the user's inventory, then checks all objects in the current room, as well as all exits that the player may use, and returns object d which contains string s. If nothing is found, d = #-1. If ambiguous, d = #-2. If HOME, d = #-3. moveto ( d1 d2 -- ) Moves object d1 to object d2. MOVETO is affected by the following rules: a) If the object being moved is !JUMP_OK and is it being moved by someone other than the object's owner, then the moveto fails. b) If the object being moved is a person and either the source or destination rooms (if not owned by the person being moved) are !JUMP_OK, the moveto fails. c) If the object being moved is not a player, is owned by the owner of either the source or destination rooms, and either room where the ownership matches is !JUMP_OK, the moveto fails. The moveto succeeds under any other circumstances. MOVETO rules follow the permissions of the current effective userid. name ( d -- s ) Takes object d and returns its name (@name) string field. next ( d -- d' ) Takes object d and returns the next thing in the linked contents/exits list of d's location. not ( x -- i ) Performs the boolean `not' operation on x, returning i as 1 if x is FALSE, and returning i as 0 otherwise. notify ( d s -- ) d must be a player object. s must be a string. Tells player d message s. If s is null it will print nothing. notify_except ( d1 d2 s -- ) d1 must be a room object, s must be a string. Tells everyone at location d1 except object d2 message s. If object d2 is not a player or NOTHING (#-1) all players are notified. If s is null it prints nothing. number? ( s -- i ) Returns 1 if string on top of the stack contains a number. Otherwise returns 0. odrop ( d -- s ) Takes object d and returns its odrop (@odrop) string field. ofail ( d -- s ) Takes object d and returns its ofail (@ofail) string field. ok? ( x -- i ) Takes x and returns 1 if x is a type dbref, as well as 0 or above, below the top of the database, and is not an object of type garbage. See also exit?, player?, program?, thing?. or ( x y -- i ) Performs the boolean `or' operation on x and y. Returns i as 1 if either x or y is TRUE, returns i as 0 otherwise. osucc ( d -- s ) Takes object d and returns its osuccess (@osucc) string field. over ( x y -- x y x ) Duplicates the second-to-top thing on the stack. This is the same as 2 pick. owner ( d -- d' ) d is any database object. Returns d', the player object that owns d. If d is a player, d' will be the same as d. pennies ( d -- i ) Gets the amount of pennies player object d has, or the penny value of thing d. pick ( ni ... n1 i -- ni ... n1 ni ) Takes the i'th thing from the top of the stack and pushes it on the top. 1 pick is equivalent to swap, and 2 pick is equivalent to over. player? ( d -- i ) Returns 1 if object d is a player object, otherwise returns 0. See also program?, room?, thing?, exit?, ok?. pop ( x -- ) Pops the top of the stack into oblivion. program ( d -- ) Internal instruction used to set permissions on called programs. Cannot be generated directly by user code. program? ( d -- i ) Returns 1 if object d is a program, otherwise returns 0. See also player?, room?, thing?, exit?, ok?. pronoun_sub ( d s -- s' ) Takes database object d and substitutes string s according to o-message rules. For example: me @ "%N has lost %p marbles." pronoun_sub would return: "Igor has lost his marbles." if the player's name was Igor and his sex were male. d does not have to be a player for the substitutions to work. random ( -- i ) Returns a random integer from 0 to the MAXINT of the system running the MUCK. In general this number is (2^31)-1 or 2,147,483,647 (2.1 billion). read ( -- s ) Reads a string s from the user. This command should not be used in a program that is locked (as opposed to linked) to an object, as the lock will always fail and print the fail messages at read time. It cannot be used in a program associated with a room object. remove_prop ( d s -- ) Removes property s from object d. If the property begins with an underscore, `_' or a dot `.', and the effective user does not have permission on that object, the call fails. rinstr ( s s1 -- i ) Returns the last occurrence of string s1 in string s, or -1 if s1 is not found. See also instr. rmatch ( d s -- d' ) Takes string s, checks all objects and actions associated with object d, and returns object d' which matches that string. For example, matches actions and inventory objects for a player object, actions on a thing object, etc. If nothing is found, d' = #-1. if ambiguous, d' = #-2. If HOME, d' = #-3. room? ( d -- i ) Returns 1 if object d is a room, otherwise returns 0. See also player?, program?, thing?, exit?, ok?. rot ( x y z -- y z x ) Rotates the top three things on the stack. This is equivalent to 3 rotate. rotate ( ni ... n1 i -- n(i-1) ... n1 ni ) Rotates the top i things on the stack. set ( d s -- ) Sets flag s to object d. Currently settable things are: abode, chown, dark, haven, jump, link, sticky. (haven and abode are not available in some places.) Boolean operations (e.g. `!abode') work as expected. setdesc setdrop setfail setname setodrop setofail setosucc setsucc ( d s -- ) Takes object d, and sets the string field specified to s. A program may only set string fields of objects that are owned by the effective user of the program, or any object if the program is Wizard. strcat ( s1 s2 -- s ) Concatenates two strings s1 and s2 and pushes the result s = s1s2 onto the stack. strcmp ( s1 s2 -- i ) Compares strings s1 and s2. Returns i as 0 if they are equal, otherwise returns i as the difference between the first non-matching character in the strings. For example, "a" "z" strcmp returns 25. This function is case sensitive, unlike stringcmp. See also strncmp. strcut ( s i -- s1 s2 ) Cuts string s after its i'th character. For example, "Foobar" 3 strcut returns "Foo" "bar" If i is zero or greater than the length of s, returns a null string in the first or second position, respectively. stringcmp ( s1 s2 -- i ) Compares strings s1 and s2. Returns i as 0 if they are equal, otherwise returns i as the difference between the first non-matching character in the strings. For example, "a" "z" stringcmp returns 25. This function is not case sensitive, unlike strcmp. strlen ( s -- i ) Returns the length of string s. strncmp ( s i -- i' ) Compares the first i characters in string s. Return value is like strcmp. subst ( s1 s2 s3 -- s ) s1 is the string to operate on, s2 is the string to change all occurences of s3 into, and s is resultant string. For example: "HEY_YOU_THIS_IS" " " "_" subst results in "HEY YOU THIS IS" s2 and s3 may be of any length in TinyMUCK 2.2. succ ( d -- s ) Takes object d and returns its success (@succ) string field s. swap ( x y -- y x ) Takes objects x and y on the stack and reverses their order. thing? ( d -- i ) Returns i as 1 if object d is a thing, otherwise returns i as 0. See also player?, program?, room?, exit?, ok?. time ( -- s m h ) Returns the time of day as integers on the stack, seconds, then minutes, then hours. var Var is not a `true' primitive in that it must always be used outside words and does not alter the stack in any way. When the compiler sees a `var' statement, it allows the use of as a variable in all words sequentially defined after the var declaration. See VARIABLES in the encyclopedia. variable ( i -- v ) Converts integer i to variable reference v. Of the pre-defined variables, `me' corresponds to integer 0, `loc' to 1, and `trigger' to 2. Thus: me @ and 0 variable @ will do the same thing (returning the user's dbref). User-defined variables are numbered sequentially starting at 3 by the compiler. Note that these variable numbers can be used even if variables have not been formally declared, making implementation of such things as arrays conveniently easy. See @, !, and VAR. ENCYCLOPEDIA OF MUF TERMS ------------------------- ADDRESSES: Each function in MUF has an address in memory. This address can be pushed on the stack with the construct: 'function. Thus: 'foobar will push a pointer to foobar on the stack. It can now be put in a variable, dup'ed, pop'ed, anything. To call the function pointed to by the address, use the EXECUTE primitive. In actuality, "'function EXECUTE" is the same as "function". @Q: If a program user enters this in response to a MUF prompt (e.g. from a read statement), the program will be exited. Also, typing @Q while in the editor will exit the editor, the same as `q' will. COMMAND-LINE ARGUMENTS: This only applies to exits that are linked to a program, not for objects that are locked to a program or call the program by @#. When a program is invoked by a player, this may be done with a command-line argument. This argument is pushed on the stack before the program is executed. For example, if an exit "get" is linked to a program, typing "get flower" will invoke the program with the argument "flower" pushed on the stack. Arguments are always strings - never integers. At invocation time, TinyMUCK will examine all exits in the room location of the user and attempt to find the exit with the longest name which will match a leftmost substring of the invocation string. For example, if the user types the invocation string "get flower", TinyMUCK will match an exit named "get flower" before matching "get". The remainder of the invocation string is pushed on the stack as one object. Thus, if "eat jelly doughnut" is matched with "eat", "jelly doughnut" will be pushed. explode can be used to separate "jelly" and "doughnut". TinyMUCK searches for exit matches in this order: room exits, room contents exits, player inventory exits, player exits. Even if an exact match is found (i.e., an exit named with the precise invocation string), a null string ("") is pushed on the stack. Thus, the stack ALWAYS has at least one element atop it at the begining of ANY program's execution. See EXECUTION, LINKING, LOCKING, and, in the dictionary, EXPLODE. COMMENTS: Comments in MUF are surrounded by parentheses. Any characters in a program between two parentheses (e.g. `(argle)') will be ignored by the compiler, and do not count as part of the program. DBREF: This stands for "database reference". It refers directly to an object in the TinyMUCK database. An integer is not an acceptable substitute, but the primitive dbref (q.v. in the dictionary) will convert an integer on top of the stack into a dbref. EXECUTION: If a program has had an exit linked to it or had an object locked to it, then whenever someone tries to use that object, it may be executed (see LINKING and LOCKING for more details). If a program is executed, the last word sequentially defined in the program is executed. Other words (or, indeed, other programs) may be executed by that word, or by words invoked by that word, and so on. If a word is not invoked in the sequential course of execution, it will never be executed. Whenever a word is executed, each statement in it will be executed in sequence, from first to last. Note that statements such as IF...THEN and EXIT may alter this flow of execution, but these are exceptions to the rule. When a program is initially executed by an exit that is linked to it, at least one word will always be on top of the stack. See COMMAND-LINE ARGUMENTS for more details. For programs executed by a locked object, in general the stack will be initially empty. See also STATEMENTS and WORDS. EXITS: Note that since you can both link and lock (see LINKING and LOCKING) an exit to a program, you may therefore have two programs executed per exit. HOME: Dbref #-3 on the stack always refers to the dbref of the home of a thing or player object. ITERATION: This can be accomplished through recursion. One way to do this is to use a variable as a counter. An example of iteration (also known as looping) is given at the end of these documents. See RECURSION. LINKING: You may @link exits (but nothing else) to a program. A program will then execute every time a player goes through that exit. Multiple exits may be linked to a single program. See EXECUTION, and various entries in the MUCK Reference Sheets including @ACTION, @LINK, @OPEN, ACTIONS and LINKING. LOCKING: You may @lock rooms, programs, exits, things or players to a program. A program will then execute every time a player TRIES to go through that exit or pick up that thing or look at that room. The program may define whether or not the object may be picked up or the exit traveled through. This is done by pushing 1 on top of the stack before the program terminates to indicate success, or pushing 0 to indicate failure. See EXECUTION and LINKING. PROPERTIES: All rooms, players and things have properties. These may be set by either players or programs. However, players may only set properties to strings, while programs may set them to either strings or integers. Thus, things such as hit points, dollars, strength, etc., can be set. Remember, though, that players can always `@set me = :' which erases all their properties. Be prepared to always set a default value on properties. The value 0 should never be stored in a property. See ADDPROP, GETPROPSTR, GET PROPVAL, and REMOVE_PROP in the dictionary, as well as PROPERTIES in the MUCK Reference Sheets. RECURSION: A word calling itself is called a recursive call. Such calls are best handled inside the if part of an if-then block, since there should always be an "escape clause" at which the recursion terminates. The subtleties of recursion are outside the scope of these documents. I suggest you find a book on the computer language Pascal to better familiarize yourself with the concept. See WORDS, and, in the dictionary, CALL. STACK: In MUF, all statements are pushed on the stack when a running program reaches them during execution, except primitives and user-defined words, which are executed, and variables, whose addresses are pushed on the stack (and may be operated on by the @ and ! primitives - see the dictionary). The maximum number of elements that can be pushed on the stack is about 500. See EXECUTION, STATEMENTS, VARIABLES and WORDS. STATEMENTS: A statement is a discrete sequence of characters. Any string of characters between double-quotes (e.g. "Hello. How are you?") is a statement. Without quotes, any string of characters between spaces is a statement. (E.g., `Hello.' is a statement. `Hello there.' is two statements.) See STACK and WORDS. USER: The person using the program (as opposed to the programmer). Non-setuid programs run according to the permissions of the user rather than the programmer who wrote owns the program. The variables ME and LOC refer to the user. See VARIABLES. VARIABLES: Usually, variables are not needed. A program can simply push and pop things from the stack. However, `real' variables may be defined, which can make program writing much easier. They MUST be declared outside of words using the `var' primitive (they are therefore global to all words in a program). When a variable name is a program statement, its address is pushed on the stack. The program can then use the primitive `@' to retrieve is value, or `!' to load a value into it. The variables ME, LOC and TRIGGER are pre-defined in MUF. ME stores the dbref of the program's user. LOC stores the dbref of his location. TRIGGER stores the dbref of the exit/thing which caused the program to be executed. See USER, WORDS, and, in the dictionary, @, !, VAR and VARIABLE. WORDS: A word in MUF begins with a colon (`:') and ends with a semicolon (`;'). The statement after the colon is the name of the word, and the remaining statements are the actual executed code of the word. Thus, a word's form is: : {word name} {body of word} ; Obviously, a program may contain many words. Calling a word is accomplished by including its name in a word. A word may not be called before it has been defined, though a word can call itself. See EXECUTION, RECURSION, STATEMENTS, and, in the dictionary, CALL. COMMON MUF EXECUTION ERRORS --------------------------- Below is a list of all known errors which can arise when running a MUF program, with brief descriptions. Input on how to make this list more useful would be appreciated. ADDPENNIES: would exceed MAX_PENNIES. All MUCKs have a value MAX_PENNIES above which the addpennies primitive cannot add more pennies to a player's penny count. COPYOBJ: Invalid object. The object trying to be copied is invalid in some way. Program not compiled. All programs must be compiled before they can run. This error could occur when a program is triggered or called and has not been compiled. SETNAME: Permission denied. Since renaming a player requires that the player's password may be supplied, MUF disallows this. MOVETO: object can't be moved. Self explanatory. The object being moved is not JUMP_OK. MOVETO: source (or destination) not JUMP_OK Under certain circumstances, when a MOVETO is attempted, one or both of these rooms or players must be set JUMP_OK for the command to succeed. See MOVETO in the dictionary. Non- argument: The specified command requires an argument of the specified as one of its parameters, and the item on the stack in the position of that parameter is not of that . Possible types that may be mismatched include: integer, object, player, room, string, variable, address. There are other errors which are similar to this error. These include: - argument is an exit (MOVETO) - invalid argument type (Arithmetic, Comparison, DBCMP, INT, CONTENTS, flag retreive, string field retreive and set, SET, RMATCH) - invalid object (Flag retreive) - invalid object type (COPYOBJ, MOVETO) Permission denied: The problem here probably has to do with ownership of the object being acted upon. This could apply to MOVETO, SET or SET. Program internal error: The program has been compiled improperly or the compiled code has been corrupted. This should never happen. Stack Overflow: An attempt was made to push an element on the stack when the stack was full. Stack Underflow: An attempt was made to pop an element from the stack when the stack was empty. Examples of Basic MUF Programming Techniques -------------------------------------------- A very simple program to add 2 and 3 and print the result to the user. Note that the result must be converted to a string before the notify primitive. (Tells the user the sum of two and three ) : simple 2 3 + (Add 2 + 3 ) intostr (Convert to string ) me @ swap (Order of the notify primitive ) notify ; ( necessitates the swap ) --- A simple example of the if-then primitive. This word looks at the top of the stack and prints "Hello!" if it is zero, and "Goodbye..." otherwise. Note the inclusion of the 'not' primitive to do this. : greeting not (Change logical value of top of stack) if (Check top of stack ) me @ "Hello!" notify (If it is nonzero, do this ) exit then me @ "Goodbye..." notify ; (If it is zero, do this ) --- A simple iterative loop: (This word, when called with a number on top of the stack, will print) (out 'Hello world!" to the user that number of times ) : iterator dup 0 <= if (Terminate if top of stack <= 0 ) exit then me @ "Hello world!" notify (Print "Hello world!" to user ) 1 - (Subtract one from counter ) iterator ; (Recursive call to iterator ) --- An alternate version of the above word, using a variable instead. The variable 'counter' must have been pre-initialized to a number. var counter : iterator-2 counter @ 0 <= if exit (Terminate if counter <= 0 ) then me @ "Hello world!" notify (Print "Hello world!" to user ) counter @ 1 - counter ! (Decrement counter ) iterator-2 ; (Recursive call to iterator ) --- A random-number generator: (This word pushes a random number from 1 to 100 on the stack) : random-100 random 100 % 1 + ; yers to aMUF.tutorial From: stinglai@bureau.World.GOV (Stinglai Ka'abi) Newsgroups: alt.mud Subject: Beginner's guide to MUF programming Keywords: MUD Muck MUF forth Atlantis and a partridge in a pear tree Date: 5 Jun 90 09:19:45 GMT Reply-To: blojo@ocf.berkeley.edu Distribution: alt [ Updated August 10th, 1990, by ChupChup for the release of TinyMUCK 2.2. ] Zen in the Art of the Towers of Hanoi (or The Basics of MUF in 10 megs or less.) This is an introduction to MUF, a dialect/subset of forth used to do really really neat things with TinyMuck 2.2. This intro was designed to be read before any of the other MUF information; it (hopefully) should supply you with a fair idea of what MUF is all about. It's written at a non-programming- stud level, all the better for understanding. All MUF programs work by performing operations on a stack. For all you non-programmer types, a stack is just a tool used to store information. Information is manipulated by "pushing" things onto the stack and "popping" things off. The last thing you've placed on a stack is always the next thing you would take off if you tried; it's like piling objects on top of each other, when the only thing you can remove >from the pile is the thing on top. For example, if you were to push the number 23, then push the number 42, and then pop a value off the stack, you would get 42. If you were to pop another value off the stack after this, you would get 23. If you were to try and pop another value, you would get an error, since the stack would now be empty. (This is a "stack underflow.") The basic procedural unit in MUF is called the word. A word is simply a sequence of instructions. In program text, a word always starts with a colon, then the word's name. A semicolon marks the end of a word. For example: : detonate_explosives (text of word here) ; would define a word called detonate_explosives. Parentheses are used to delineate program comments; everything inside comments is ignored by the computer. The detonate_explosives word above, if run as shown, would do absolutely nothing. Indentation in MUF is arbitrary and serves to make the program more readable to people. In MUF, there are three types of constant values: integers, strings, and database references. Each of these types is stored and retrieved from the stack as a single unit (The string "Hello, Sailor!", for example, would be stored on the stack in its entirety: "Hello, Sailor!"; it would not be stored byte-by-byte or word-by-word or in any other such silly way.) To push a constant onto the stack, you only need to state its value. The following is a completely legitimate procedure: : pointless_word "Old Man" "I'm" 37 "What?" 37 "Not old!" ; However, run by itself, it wouldn't do anything visible to the user. It would, however, create a stack which looks like this: ("Old Man" "I'm" 37 "What?" 37 "Not old!") In the above stack, "Old Man" is the value on the bottom. "Not old!" is the value on top of the stack, and would be the next value retrieved. Placement of values on the same line of a program is arbitrary. Since each value represents something being put on a stack, the word : example "Semprini?" "All right, wot's all this then!" ; is the same as: :example "Semprini?" "All right, wot's all this then!" ; Functions which are available in the standard MUF library take values from the top of the stack, do things with them, and usually leave something new back on top of the stack. The words +, -, swap, pop, and random provide good examples of this and are discussed here. The + routine takes the top two integers from the stack, adds them together, and leaves the result on top of the stack. In order to easily describe what functions like this do, a certain stack notation is used: for +, this would be (i1 i2 -- z). What's inside those parenthesis is a sort of "Before and After" synopsis; the things to the left of the double-dash are the "before", and those to the right are the "after". (i1 i2 -- i) says that the function in question takes two integers away and leaves one. The letters used here to tell what kind of data a stack object can be are: i for integer, d for database object, s for string, v for variable, and x or y to mean something that can be more than one type. Here are short descriptions of the procedures listed above so you can get the hang of how they work: + (i1 i2 -- i) Adds i1 and i2 together. The word : add_some_stuff 2 3 + ; will return 5. The word : add_some_more_stuff 2 3 4 5 + + + ; will return 14. When add_some_more_stuff first reaches the "+ + +" line, the stack looks like: (2 3 4 5). The first + changes the stack to look like: (2 3 9). The next causes: (2 12). The final plus returns: (14). - (i1 i2 -- i) Subtracts i2 from i1. : subtract_arbitrary_things 10 7 - ; will return 3 on top of the stack. swap (x y -- y x) Switches the top two things on the stack. This is useful for when you want to know the value of x but want to save y for later use. : swap_stuff_around 1 5 2 swap 3 "Three, sir!" swap "Boom!" ; will, before it gets to the first swap, create a stack of (1 5 2). After the swap, the stack looks like (1 2 5). It then accumulates another 3 and a string constant, to look like (1 2 5 3 "Three, sir!") It swaps the last two again and adds another string, so the stack looks like: (1 2 5 "Three, sir!" 3 "Boom!"). pop (x --) Throws away the value on top of the stack. As shown in the stack diagram, it returns nothing but takes something, and so decreases the stack's total size. Useful when you really really want to get to the next thing on the stack so bad you don't care what's on top. The word: : needless_popping_waste "Immanuel Kant" "Heideggar" pop "David Hume" "Schoppenhauer" "Hegel" pop pop ; would leave the stack looking like ("Immanuel Kant" "David Hume"). random (-- i) Doesn't even look at the stack, but piles a really really random integer on top. The word: : feel_lucky_punkP random random random ; would return a stack of three random numbers. Because of the way the stack works, variables aren't as necessary in MUF as they are in other languages, but they can be used to simplify stack-handling operations. To declare a variable, you simply add the line "var " at the beginning of your program. Variables are of no specific type; a variable which holds an integer can turn around the next second and hold a string if it's feeling haughty enough. The following words are important when dealing with variables: ! (x v --) Set variable v to hold value x. The program: var answer : multiply-and-store 6 9 * answer ! ; will give the variable "answer" the value 42. This is the same as: : multiply-and-store 6 9 * answer ! ; @ (v -- x) This word (pronounced "fetch") retrieves the value of a variable and puts it on the stack. You should remember this since a common mistake among beginning MUF programmers is to forget to put fetch symbols in their programs. The word garply by itself stands for the variable "garply", while the expression garply @ stands for the value of that same variable. If you're familiar with Lisp, this is analogous to the difference between garply and (garply). The program: var biggles var fang : more_silly_manipulation 10 biggles ! 24 fang ! biggles @ fang @ + ; will return the value 34 on top of the stack. The program: var biggles var fang : more_silly_manipulation 10 biggles ! 24 fang ! biggles fang + ; is *wrong*. For reasons I won't go into now, since this guide was written at the last moment and at great expense, the above word will return the value 7 on top of the stack. In MUF, there are two variables which are predefined and available for use at all times. These variables are "me" and "loc", where "me" holds the player's database reference, and loc holds the player's location's database reference. (Database references were mentioned before as the third type of constant, then sort of ignored till now. For the sake of completeness, I will introduce the word dbref (i -- d) Where i is an integer and d is a database reference, dbref converts between the two types. The line 2032 dbref will return item #2032 in the Muck database. This is useful since there are lots of functions that operate on database references that won't work on integers. [If you want to declare something in one of your programs as being a dbref instead of an integer, you should just put a # in front. For example, 69 means the integer 69, while #69 means object number 69. You could say '69 dbref' instead of '#69', but it would be a little slower and a little harder to read.] Me @ will return the player's item reference, while loc @ will return the room they are in. Trigger @ returns the item that triggered the current program, whether it is a player, exit, room, whatever. A useful word to know is: name (d -- s) Where d is a db reference and s is a string, name returns the name of item x. Now that you know about me @, another Muck function becomes useful. Its synopsis is: notify (d s --) When d is a player, notify prints string s out to user d. The program : warn me @ "There is someone behind the next column waiting to jump you." notify ; would print said message on the user's screen. Before you can really start writing neat stuff in Muck, there are two more things you should know about. One is = and the other is the "if/then" setup. = (i1 i2 -- i) Returns 1 if integer i1 is equal to integer i2, otherwise returns 0. : nonequals 2 3 = ; returns 0. If/then could be written up with a synopsis, but it would be sort of complicated and probably a lie also. The way it works is this: If pulls an item off the stack. If the item is 0, it skips over the program after the IF and resumes execution at the THEN. If the item is not 0, the program will execute everything in between. The naming of this construction as if/then can be somewhat confusing. It certainly doesn't work quite like the if/then of normal languages, and the THEN actually being called THEN is sort of confusing. As nearly as I can tell, if/then is a sort of forth-creators' joke. It does not mean "IF the previous is true THEN do this." like it does in most languages. Rather, it means "IF the previous is true do this; THEN go on with the rest of the program." Remarkably silly. The word: : word 2 3 = if me @ "Your computer is broken!" notify then me @ "Done executing this word." notify ; will always print "Done executing this word." to the user, and will print "Your computer is broken!" if something is really screwy with the math and it actually thinks 2 = 3. Getting a bit more sophisticated, one can write something like: : word_up "Your computer works fine." 2 3 = if pop "Your computer is broken. Sorry. Truth hurts." then me @ swap notify ; When word_up is called, "Your computer works fine." gets put on the stack. If your computer actually works, 2 is *not* equal to 3, so that right after the = the stack looks like: ("Your computer works fine." 0) The IF reads the 0 and skips all the way down to the THEN. The SWAP in the last line is used since the NOTIFY word wants its parameters in the opposite order of where they would be. If your computer is broken, right after the =, the stack looks like: ("Your computer works fine." 1) The IF reads this 1 and decides to keep executing. It then gets to the POP which gets rid of the filthy lie about well-working computers and replaces it with the painful truth. *SAMPLE PROGRAM* Ok, so you've been reading this whole thing so far, and you really want to use this stuff to do something interesting. The following program does something interesting, and uses the function strcat (s1 s2 -- s) Concatenate strings s1 and s2, returning the result. it also uses location (d -- d') Takes db reference d and returns d', the db reference for its location. and dup (x -- x x) Duplicate the top of the stack. and dbcmp (d1 d2 -- ) Works just like =, except operates on db references instead of integers. : far_vision #2032 (2032 is Celia's object number. ) dup (Make 2 copies; we're about to use 1. ) name (Celia might change her name in the future, so) (instead of using "Celia" here we just look up) (her name. ) " is currently in " strcat (Attach name to sentence so far ) swap (Flip the sentence back so we can get at) (Celia's dbref again. ) (Celia's dbref is now at top of stack. ) location (Where is Celia? ) name (What is the name of the place she is in?) "." strcat strcat me @ swap notify (Tell the player where Celia is.) #2055 (Celia's hardsuit is #2055. ) location #2032 (Celia again ) dbcmp (Has she got her hardsuit with her?) if me @ "Watch out-- she's wearing her hardsuit!" notify then ; Note that this program uses no variables (except for the universally defined ME variable.) In Muck, this program would be attached to, say, a homing device or a magic staff. Now, if Boomer ever wants to find Celia, he can, and he'll even know if she's defenseless or she's got her armor. Without the comments and spaced out like you might see normally, this program looks like: : far_vision #2032 dup name " is currently in " strcat swap location name "." strcat strcat (Now we know where she is.) me @ swap notify #2055 location #2032 dbcmp if me @ "Watch out-- she's wearing her hardsuit!" notify then ; Words can also be called by other words; to do this, you treat your other words just like library functions when you use them. When you have more than one word in the same program, the word which is listed *last* is the one executed, and all the ones listed before it are subroutines. The above program could be rewritten: : celia-identity #2032 ; : far_vision celia-identity dup name " is currently in " strcat swap location name "." strcat strcat (Now we know where she is.) me @ swap notify #2055 location celia-identity dbcmp (Using celia-identity and spacing the ) (commands like this makes this bit a ) (little easier to understand. ) if me @ "Watch out-- she's wearing her hardsuit!" notify then ; Oodles and oodles of other neat MUF library routines are available, too numerous to be detailed in an introduction such as this. A complete list, as well as sample code, is available from such spiffy ftp sites as prince.white.toronto.edu and belch.berkeley.edu. If you're interested in seeing more sample code, write to me for program listings for the Pan Galactic Gargle Blaster, walkie-talkies, and several useful library routines. Stinglai "Two Sheds" Ka'abi Mail to: blojo@ocf.berkeley.edu - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "We are too proud to fight." --Woodrow Wilson 1856-1924 "Violence never settles anything." --Genghis Khan 1162-1227 "The mice voted to bell the cat." --Aesop c. 620-c. 560 B.C. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Coming next week: "Life, the Universe, and INTERCAL:" A most excellent introduction to that programming language. riables are "me" and "loc", where "me" holds the player's database reference, and loc holds the player's location's database reference. (Database references were mentioned before as the third type of constant, then sort of ignored till now. For the sake of completeness, I will introduce the word dbref (i -- d) Where i is an integer and d is a database reference, dbref converts between the two types. The line 2032 dbref will return item #2032 in the Muck database. This is useful s Before you can really start writing neat stuff in Muck, there are two more things you should know about. One is = and the other is the "if/then" setup. = (i1 i2 -- i) Returns 1 if integer i1 is equal to integer i2, otherwise returns 0. : nonequals 2 3 = ; returns 0. If/then could be written up with a synopsis, but it would be sort of complicated and probably a lie also. The way it works is this: If pulls an item off the stack. If the item is 0, it skips over the program after the IF and resumes execution at the THEN. If the item is not 0, the program will execute everything in between. The naming of this construction as if/then can be somewhat confusing. It certainly doesn't work quite like the if/then of normal languages, and the THEN actually being called THEN is sort of confusing. As nearly as I can tell, if/then is a sort of forth-creators' joke. It does not mean "IF the previous is true THEN do this." like it does in most languages. Rather, it means "IF the previous is true do this; THEN go on with the rest of the program." Remarkably silly. The word: : word 2 3 = if me @ "Your computer is broken!" notify then me @ "Done executing this word." notify ; will always print "Done executing this word." to the user, and will print "Your computer is broken!" if something is really screwy with the math and it actually thinks 2 = 3. Getting a bit more sophisticated, one can write something like: : word_up "Your computer works fine." 2 3 = if pop "Your computer is broken. Sorry. Truth hurts." then me @ swap notify ; When word_up is called, "Your computer works fine." gets put on the stack. If your computer actually works, 2 is *not* equal to 3, so that right after the = the stack looks like: ("Your computer works fine." 0) The IF reads the 0 and skips all the way down to the THEN. The SWAP in the last line is used since the NOTIFY word wants its parameters in the opposite order of where they would be. If your computer is broken, right after the =, the stack looks like: ("Your computer works fine." 1) The IF reads this 1 and decides to keep executing. It then gets to the POP which gets rid of the filthy lie about well-working computers and replaces it with the painful truth. *SAMPLE PROGRAM* Ok, so you've been reading this whole thing so far, and you really want to use this stuff to do something interesting. The following program does something interesting, and uses the function strcat (s1 s2 -- s) Concatenate strings s1 and s2, returning the result. it also uses location (d -- d') Takes db reference d and returns d', the db reference for its location. and dup (x -- x x) Duplicate the top of the stack. and dbcmp (d1 d2 -- ) Works just like =, except operates on db references instead of integers. : far_vision #2032 (2032 is Celia's object number. ) dup (Make 2 copies; we're about to use 1. ) name (Celia might change her name in the future, so) (instead of using "Celia" here we just look up) (her name. ) " is currently in " strcat (Attach name to sentence so far ) swap (Flip the sentence back so we can get at) (Celia's dbref again. ) (Celia's dbref is now at top of stack. ) location (Where is Celia? ) name (What is the name of the place she is in?) "." strcat strcat me @ swap notify (Tell the player where Celia is.) #2055 (Celia's hardsuit is #2055. ) location #2032 (Celia again ) dbcmp (Has she got her hardsuit with her?) if me @ "Watch out-- she's wearing her hardsuit!" notify then ; Note that this program uses no variables (except for the universally defined ME variable.) In Muck, this program would be attached to, say, a homing device or a magic staff. Now, if Boomer ever wants to find Celia, he can, and he'll even know if she's defenseless or she's got her armor. Without the comments and spaced out like you might see normally, this program looks like: : far_vision #2032 dup name " is currently in " strcat swap location name "." strcat strcat (Now we know where she is.) me @ swap notify #2055 location #2032 dbcmp if me @ "Watch out-- she's wearing her hardsuit!" notify then ; Words can also be called by other words; to do this, you treat your other words just like library functions when you use them. When you have more than one word in the same program, the word which is listed *last* is the one executed, and all the ones listed before it are subroutines. The above program could be rewritten: : celia-identity #2032 ; : far_vision celia-identity dup name " is currently in " strcat swap location name "." strcat strcat (Now we know where she is.) me @ swap notify #2055 location celia-identity dbcmp (Using celia-identity and spacing the ) (commands like this makes this bit a ) (little easier to understand. ) if me @ "Watch out-- she's wearing her hardsuit!" notify then ; Oodles and oodles of other neat MUF library routines are available, too numerous to be detailed in an introduction such as this. A complete list, as well as sample code, is available from such spiffy ftp sites as prince.white.toronto.edu and belch.berkeley.edu. If you're interested in seeing more sample code, write to me for program listings for the Pan Galactic Gargle Blaster, walkie-talkies, and several useful library routines. Stinglai "Two Sheds" Ka'abi Mail to: blojo@ocf.berkeley.edu - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "We are too proud to fight." --Woodrow Wilson 1856-1924 "Violence never settles anything." --Genghis Khan 1162-1227 "The mice voted to bell the cat." --Aesop c. 620-c. 560 B.C. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Coming next week: "Life, the Universe, and INTERCAL:" A most excellent introduction to that programming language. riables are "me" and "loc", where "me" holds the player's database reference, and loc holds the player's location's database reference. (Database references were mentioned before as the third type of constant, then sort of ignored till now. For the sake of completeness, I will introduce the word dbref (i -- d) Where i is an integer and d is a database reference, dbref converts between the two types. The line 2032 dbref will return item #2032 in the Muck database. This is useful s