MUF REFERENCE 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 + ;