\input texinfo @c -*-texinfo-*- @comment %**start of header (This is for running Texinfo on a region.) @setfilename cooldocs.txt @settitle COOLMUD Programmer's Manual @smallbook @c Uncomment the following line for two-sided printing. @setchapternewpage odd @paragraphindent 0 @comment %**end of header (This is for running Texinfo on a region.) @ifinfo @format COOLMUD Programmer's Manual For COOLMUD Version 2.0 Septermber 1992 by Rusty Wright (aka Gus) @sp 1 (This document is a heavily modified version of the LambdaMOO manual by Pavel Curtis.) @sp 1 Copyright @copyright{} 1992 by Rusty Wright. @end format Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. @ignore Permission is granted to process this file through TeX and print the results, provided the printed document carries copying permission notice identical to this one except for the removal of this paragraph (this paragraph not being relevant to the printed manual). @end ignore Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the author. @format @sp 1 @end format @end ifinfo @titlepage @title COOLMUD Programmer's Manual @subtitle For COOLMUD Version 2.0 @subtitle September 1992 @author by Rusty Wright (aka ``Gus'') (This document is heavily modified from the LambdaMOO manual by Pavel Curtis.) @page Copyright @copyright{} 1992 by Rusty Wright. @vskip 0pt plus 1filll Copies of the electronic source for this document can be obtained using anonymous FTP on the Internet. At the site @file{ferkel.ucsb.edu} the files are @file{pub/mud/CoolMUD/coolmud.*}; several different file formats are provided, including Texinfo, plain text, and Postscript. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the author. @end titlepage @unnumbered Introduction COOLMUD is a network-accessible, multi-user, programmable, interactive system designed for the construction of text-based adventure games, conferencing systems, and other collaborative software. Participants (usually referred to as @dfn{players}) connect to COOLMUD using @code{telnet} or some other, more specialized, @dfn{client} program. Upon connecting, they are usually presented with a @dfn{welcome message} explaining how to either create a new @dfn{character} or connect to an existing one. Characters are the embodiment of players in the virtual reality that is COOLMUD. Having connected to a character, players then give one-line commands that are parsed and interpreted by COOLMUD as appropriate. Such commands may cause changes in the virtual reality, for example, changing the location of a character, or may simply report something, such as the appearance of some object. The job of interpreting commands is shared between two major components in the COOLMUD system: the @dfn{server} and the @dfn{database}. The server is a program, written in a standard programming language, that manages the network connections, maintains queues of commands and other tasks to be executed, controls all access to the database, and executes other programs written in the COOL programming language. The database contains representations of all objects in the virtual reality, including the COOL programs the server executes to give objects their specific behaviors. Almost every command is parsed by the server into a call on a COOL @dfn{method} that actually does the work. Thus, programming in the COOL language is a central part of making non-trivial extensions to the database and thus, the virtual reality. In the next chapter we'll go over the structure and contents of a COOLMUD database. The following chapter gives a complete description of how the server performs its primary duty: parsing the commands typed by players. Next, we'll examine the syntax and semantics of the COOL programming language. Finally, we'll cover the database conventions assumed by the server. @quotation @strong{Note:} This manual describes only those aspects of COOLMUD that are entirely independent of the contents of the database. It does not describe, for example, the commands or programming interfaces present in the COOLMUD database. @end quotation @chapter The COOLMUD database In this chapter we'll examine in detail the various kinds of data that can appear in a COOLMUD database and that, therefore, COOL programs can manipulate. In a few places, we'll refer to the @code{boot} database. This is just one particular COOLMUD database. @section Values There are only a few kinds of values that COOL programs can manipulate: @display @itemize @bullet @item @cindex numbers numbers (integers in a specific, large range) @item @cindex strings strings (of characters) @item @cindex objects objects (in the virtual reality) @item @cindex errors errors (arising during program execution) @item @cindex lists lists (of all of the above, including lists) @end itemize @end display @cindex numbers The only @dfn{numbers} that COOL understands are the integers from @minus{}2^31 (that is, negative two to the power of 31) up to 2^31 @minus{} 1 (one less than two to the power of 31); that's from @minus{}2147483648 to 2147483647, enough for most purposes. In COOL programs, numbers are written just as you see them here, an optional minus sign followed by a sequence of decimal digits. In particular, you may not put commas, periods, or spaces in the middle of large numbers, as we sometimes do in natural languages (e.g., `2,147,483,647'). @cindex strings Character @dfn{strings} are arbitrarily-long sequences of normal, ASCII printing characters. When written as values in a program, strings are enclosed in double-quotes, like this: @example "This is a character string." @end example @noindent To include a double-quote in the string, precede it with a backslash (@samp{\}), like this: @example "His name was \"Leroy\", but nobody ever called him that." @end example @noindent Finally, to include a backslash in a string, double it: @example "Some people use backslash ('\\') to mean set difference." @end example @noindent COOL strings may not include special ASCII characters like carriage-return, line-feed, bell, etc. @cindex objects @dfn{Objects} are the backbone of the COOL database and, as such, deserve a great deal of discussion; the next section is devoted to them. Every object has a number, unique to that object. In programs, we write a reference to a object by putting a hash mark (@samp{#}) followed by the object's number, like this: @example #495 @end example @noindent There is one special object number used for an error value; @code{#-1}. @cindex servers COOLMUD allows servers to interconnect, and for objects to move between servers. A @dfn{visitor} object is specified just like a local object and is appended with an ampersand @samp{@@} and the name of the remote server: @example #23@@east #13@@unlucky @end example @cindex errors @dfn{Errors} are, by far, the least frequently used values in COOL. In the normal case, when a program attempts an operation that is erroneous for some reason (for example, trying to add a number to a character string), the server stops running the program and prints an error message. It is possible for a program to stipulate that such errors should not stop execution; instead, the server should just let the value of the operation be an error value. The program can then test for such a result and take appropriate recovery action. In programs, error values are written as words beginning with @samp{E_}. The complete list of error values, along with their associated messages, is as follows: @example E_DIV @r{Division by zero} E_FOR @r{For variable not a list} E_INTERNAL @r{Internal error} E_INVIND @r{Invalid indirection} E_MAXREC @r{Maximum recursion exceeded} E_MESSAGE @r{Message unparseable} E_METHODNF @r{Method not found} E_NONE @r{No error} E_OBJNF @r{Object not found} E_PERM @r{Permission denied} E_RANGE @r{Range error} E_SERVERDN @r{Server down} E_SERVERNF @r{Server not found} E_STACKOVR @r{Stack overflow} E_STACKUND @r{Stack underflow} E_TIMEOUT @r{Timed out} E_TYPE @r{Type mismatch} E_VARNF @r{Variable not found} @end example @ignore @c spacing is screwed up @display @code{E_DIV} Division by zero @code{E_FOR} For variable not a list @code{E_INTERNAL} Internal error @code{E_INVIND} Invalid indirection @code{E_MAXREC} Maximum recursion exceeded @code{E_MESSAGE} Message unparseable @code{E_METHODNF} Method not found @code{E_NONE} No error @code{E_OBJNF} Object not found @code{E_PERM} Permission denied @code{E_RANGE} Range error @code{E_SERVERDN} Server down @code{E_SERVERNF} Server not found @code{E_STACKOVR} Stack overflow @code{E_STACKUND} Stack underflow @code{E_TIMEOUT} Timed out @code{E_TYPE} Type mismatch @code{E_VARNF} Variable not found @end display @c some items are too long and their text is put on the next line @table @code @item E_DIV Division by zero @item E_FOR For variable not a list @item E_INTERNAL Internal error @item E_INVIND Invalid indirection @item E_MAXREC Maximum recursion exceeded @item E_MESSAGE Object not found @item E_PERM Permission denied @item E_RANGE Range error @item E_SERVERDN Server down @item E_SERVERNF Server not found @item E_STACKOVR Stack overflow @item E_STACKUND Stack underflow @item E_TIMEOUT Timed out @item E_TYPE Type mismatch @item E_VARNF Variable not found @end table @end ignore @cindex lists The final kind of value in COOL programs is @dfn{lists}. A list is a sequence of arbitrary COOL values, possibly including other lists. In programs, lists are written with each of the elements in order, separated by commas, the whole enclosed in curly braces (@samp{@{} and @samp{@}}). For example, a list of the names of the days of the week is written: @example @{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"@} @end example @noindent Note that it doesn't matter that we put a line-break in the middle of the list. This is true in general in COOL: anywhere that a space can go, a line-break can go, with the same meaning. The only exception is inside character strings, where line-breaks are not allowed. @section Objects @cindex objects Objects are, in a sense, the whole point of the COOL programming language. They are used to represent objects in the virtual reality; for example, players, rooms, exits, and other concrete things. @findex clone @findex destroy Numbers always exist, in a sense; you have only to write them down in order to operate on them. With objects it is different. The object with number @samp{#958} does not exist just because you write down its number. An explicit operation, the @code{clone()} function described later, is required to bring an object into existence. Symmetrically, once created, an object continues to exist until is explicitly destroyed by the @code{destroy()} function (also described later). The identifying number associated with an object is unique to that object. It is assigned when the object is created and will never be reused, even if the object is destroyed. For example, if we create an object and it is assigned the number @samp{#1076}, the next object created will be assigned @samp{#1077}, even if @samp{#1076} was destroyed in the meantime. @cindex parents @cindex variables @cindex methods Every object is made of four pieces that together define its behavior; its @dfn{parents}, @dfn{variables}, @dfn{methods}, and @dfn{verbs}. @subsection Parents @cindex parents @cindex multiple inheritance @cindex cloning @cindex reparenting @findex chparent Except for the root object (@samp{#1}) all objects have one or more parents. COOLMUD has multiple inheritance, so an object can have more than one ``parallel'' parent. When an object is created, it is cloned from some other object. The child object inherits all of the methods and variables from the parents of the object it was cloned from. The object it was cloned from isn't its parent, but it has the same parents as that object. After an object is cloned it can have its parents changed by either reprogramming the entire object or by calling the built-in @code{chparents()} function. The parent/child hierarchy is used for classifying objects into general classes and then sharing behavior among all members of that class. For example, the @code{boot} database contains an object representing a sort of ``generic'' room. All other rooms are @dfn{descendants} (i.e., children or children's children, or ...) of that one. The generic room defines those pieces of behavior that are common to all rooms; other may rooms specialize that behavior for their own purposes. The notion of classes and specialization is the very essence of what is meant by @dfn{object-oriented} programming. @subsection Object variables @cindex object variables @cindex inheritance @cindex copy-on-write An object @dfn{variable} is a named ``slot'' in an object that can hold an arbitrary COOL value. An object can have any number of variables, and which are declared to be of a certain type. Objects appear to have variables corresponding to every variable in its parents' objects. To use the jargon of object-oriented programming, this is a kind of @dfn{inheritance}. If some parent object has a variable named @code{foo}, then it appears that all of its children and thus its children's children, and so on have that variable. We say it ``appears'' to have all of its parents' variables because you don't have to declare any variables on a child object that are on its parents; when you ask for the value of any of these variables the COOLMUD server finds the variable on the nearest parent object and returns its value. But when an object changes the value of one of these variables, the object then gets its own permanent copy of the variable, which is then changed. This behavior is typically referred to as ``copy-on-write.'' An object may also have a new variable defined only on itself (and its descendants). For example, an object representing a rock might have variables indicating its weight, chemical composition, and/or pointiness, depending upon how the rock is used in the virtual reality. @cindex methods Variables on objects can only be read or modified when there are methods that provide such access to the variables. For example, there are often methods on objects that provide simple ``read'' access for variables: @example method name return name; endmethod @end example @cindex permissions For modifying variables, methods typically implement some permission check to see if the variable can be modified by the @dfn{caller}: @example method set_name if (!(caller in owners)) raise(E_PERM); endif name = args[1]; endmethod /* set_name */ @end example In the above example the check is quite simple. Since methods implement the permission scheme, access is completely controlled by them. It is important to note that the COOLMUD server provides no ``override'' on variable access; even the wizards can be excluded access to a variable, which the above piece of code is an example of. @subsection Methods @cindex methods The other piece making up an object is its @dfn{methods}. A method is a named COOL program that is associated with a particular object. Methods are also used to implement commands that a player might type; for example, in the @code{boot} database, there is a method on all objects representing containers that implements commands of the form `put @var{object} in @var{container}'. COOL methods can also invoke methods defined on objects. Some methods are designed to be used only from within COOL code; they do not correspond to any particular player command at all. Thus, methods in COOL are like the `procedures' or `functions' found in other programming languages. @subsubheading Method variables @cindex method variables @cindex variables Methods can have their own variables. They are untyped and are local to the method; when the method finishes running, its variables cease to exist. Method variables are declared with the @code{var} declaration. @subsection Verbs @cindex verbs In order for an object's method to be used as a command by players, the method must be ``bound'' to a @dfn{verb}. If a method is not bound to a verb it can't be accessed by players, only by COOL code. In a later section we'll go over how to bind a method to a verb. @cindex method arguments When a method is run as a verb, any words following the verb are given to the method as arguments. For example, if object @code{xyz} has a @code{look} verb bound to the @code{look_verb} method, and a player types @samp{look at xyz with glass} the @code{look_verb} method on the @code{xyz} object will be run with the arguments @code{at}, @code{xyz}, @code{with}, and @code{glass}. If there is another object in the room or carried by the player, named @code{glass}, with a a @code{look} verb, it may also be called, and with the same arguments. Since every object in the room or carried by the player with a @code{look} verb may get called, each object must check the arguments to see if they were the one the @code{look} was meant for. When an object's @code{look} verb determines that it's the object that matches, it returns @code{0} as its value to tell the server that no further @code{look} verbs on the other objects need to be called. @findex verb An object's @code{verb} binding can specify different words to invoke the method the verbs are bound to. For example, the words @code{poke} and @code{prod} can both be verbs bound to the @code{poke_verb} method. Then a player could type either @samp{poke xyz} or @samp{prod xyz}. @cindex prepositions Verb bindings can also be set up so that in addition to the verb, another word must be typed as part of the command. Typically the second word is a preposition; for example, @samp{with}, @samp{in}, @samp{to}, @samp{from}, and so on. This allows you to set up commands like @samp{put money in jar} and @samp{rub lamp with rag}. @chapter The COOL programming language The COOL programming language is a relatively small and simple object-oriented language designed to be easy to learn for most non-programmers. Having given you enough context to allow you to understand exactly what COOL code is doing, we'll see what COOL code looks like and what it means. We'll begin with the syntax and semantics of expressions, those pieces of code that have values. After that, we'll go over statements, the next level of structure up from expressions. Next, we'll discuss the concept of a task, the kind of running process initiated by players entering commands, among other causes. Finally, we'll go over the built-in functions available to COOL code and describe what they do. @section Comments You can include bits of text in your COOL program that are ignored by the server. The idea is to allow you to put in notes to yourself and others about what the code is doing. To add a comment you use a character string literal as a statement. For example, the sentence about peanut butter in the following code is essentially ignored during execution but will be maintained in the database: @example for x in (#0.players) "Grendel eats peanut butter!"; player:tell(x.name, " (", x, ")"); endfor @end example @section Expressions @cindex expressions Expressions are those pieces of COOL code that generate values; for example, the COOL code @example 3 + 4 @end example @noindent is an expression that generates (or ``has'' or ``returns'') the value 7. There are many kinds of expressions in COOL, all of them discussed below. @subsection Errors @cindex errors Most kinds of expressions can be used improperly in some way. For example, the expression @example 3 / 0 @end example @noindent @vindex E_DIV @noindent is improper because it tries to divide by zero. In such cases, COOL ``raises'' an error value (@code{E_DIV} in this example), which causes the method's code to be aborted and a message to be printed on the player's screen. @subsection Literals @cindex literals The simplest kind of expression is a literal COOL value, just as described in the section on values at the beginning of this document. For example, the following are all expressions: @example 17 #893 "This is a character string." E_TYPE @{"This", "is", "a", "list", "of", "words"@} @end example Note that the list expression contains other expressions, several character strings in this case. In general, those expressions can be of any kind at all, not necessarily literal values. For example, @example @{3 + 4, 3 - 4, 3 * 4@} @end example @noindent is an expression whose value is the list @samp{@{7, -1, 12@}}. @findex typeof @cindex types @cindex constants COOL also has some constants, which are returned by the @code{typeof()} built-in function: @vindex NUM @vindex LIST @vindex OBJ @vindex ERR @vindex STR @example NUM OBJ STR LIST ERR @end example Their meanings are as follows: @table @code @item NUM @cindex numbers a number, the type code for numbers @item LIST @cindex lists a number, the type code for lists @item STR @cindex strings a number, the type code for strings @item OBJ @cindex objects a number, the type code for objects @item ERR @cindex errors a number, the type code for error values @end table @subsection Variables @cindex variables @cindex variables, local @cindex variables, method @cindex local variables @cindex method variables As discussed earlier, it is possible to store values in variables on objects; the variables will keep those values forever, or until another value is put there. It's often useful to have a place to put a value for just the duration of the execution of a method; COOL provides method (local) variables for this purpose. Method variables are named places to hold values; you can get and set the value in a given method variable as many times as you like. Method variables are temporary, though; they only last while a particular method is running; after it finishes, all of the method variables cease to exist and the values are forgotten. The method variables set in one method are not visible to the code of other methods. When a method begins executing, the method variables are initialized to 0. The name for object and method variables is made up of letters, digits, and the underscore character (@samp{_}) and cannot begin with a digit. The following are all valid variable names: @example foo _foo this2that M68000 two_words This_is_a_very_long_multiword_variable_name @end example Note that, along with almost everything else in COOL, the case of the letters in variable names is insignificant. For example, these are all names for the same variable: @example fubar Fubar FUBAR fUbAr @end example A variable name is itself an expression; it's value is the value of the named variable. @cindex assignment statement To change the value stored in a variable, use an @dfn{assignment} statement: @example @var{variable} = @var{expression} @end example For example, to change the variable named @samp{x} to have the value 17, you would write @samp{x = 17;}. An assignment statement changes the value of of the named variable. COOL also has some predefined pseudo-variables, they are read-only: @cindex variables @cindex variables, pseudo @cindex pseudo-variables @example player this caller args @end example Their values are as follows: @table @code @item player @vindex player an object, the player who typed the command that started the task that involved running this piece of code. @item this @vindex this an object, the object on which the currently-running method was found. @item caller @vindex caller an object, the object on which the method that called the currently-running method was found. For the first method called for a given command, @code{caller} has the same value as @code{player}. @item args @vindex args usually a list, the arguments given to this method. The @code{parse} method on the player object gets the entire command line typed by the player, it hands it off to @code{call_verb}, which splits it into words, which is passed as a list of words to a method bound to the verb. @end table @subsection Arithmetic @cindex arithmetic All of the usual simple operations on numbers are available to COOL programs: @example + - * / % @end example These are, in order, addition, subtraction, multiplication, division, and remainder. In the following table, the expressions on the left have the corresponding values on the right: @example 5 + 2 @result{} 7 5 - 2 @result{} 3 5 * 2 @result{} 10 5 / 2 @result{} 2 5 % 2 @result{} 1 5 % -2 @result{} 1 -5 % 2 @result{} -1 -5 % -2 @result{} -1 -(5 + 2) @result{} -7 @end example Note that division in COOL throws away the remainder and that the result of the remainder operator (@samp{%}) has the same sign as the left-hand operand. Also, note that @samp{-} can be used without a left-hand operand to negate a numeric expression. The @samp{+} operator can also be used to append two strings. The expression @example "foo" + "bar" @end example @noindent has the value @example "foobar" @end example @vindex E_TYPE @vindex E_DIV Unless both operands to an arithmetic operator are numbers (or, for @samp{+}, both strings), the error value @code{E_TYPE} is raised. If the right-hand operand for the division or remainder operators (@samp{/} or @samp{%}) is zero, the error value @code{E_DIV} is raised. @subsection Comparing values @cindex comparing values Any two values can be compared for equality using @samp{==} and @samp{!=}. The first of these returns 1 if the two values are equal and 0 otherwise; the second does the reverse: @example 3 == 4 @result{} 0 3 != 4 @result{} 1 "foo" == "Foo" @result{} 1 #34 != #34 @result{} 0 @{1, #34, "foo"@} == @{1, #34, "FoO"@} @result{} 1 E_DIV == E_TYPE @result{} 0 3 != "foo" @result{} 1 @end example @findex strcmp @noindent Note that comparison of strings is case-insensitive; that is, it does not distinguish between the upper- and lower-case version of letters. To perform a case-sensitive comparison, use the @code{strcmp} function described later. Numbers, object numbers, strings, and error values can also be compared for ordering purposes using the following operators: @example < <= >= > @end example @noindent meaning ``less than,'' ``less than or equal,'' ``greater than or equal,'' and ``greater than,'' respectively. As with the equality operators, these return 1 when their operands are in the appropriate relation and 0 otherwise: @example 3 < 4 @result{} 1 #34 >= #32 @result{} 1 "foo" <= "Boo" @result{} 0 @end example @vindex E_TYPE @noindent Note that, as with the equality operators, strings are compared case-insensitively. If the operands to these four comparison operators are of different types, or if they are lists, then @code{E_TYPE} is raised. @subsection Conditional expressions @cindex conditional expressions There is a notion in COOL of @dfn{true} and @dfn{false} values; every value is one or the other. The true values are as follows: @itemize @bullet @item all numbers other than zero @item all non-empty strings (i.e., other than @samp{""}) @item all non-empty lists (i.e., other than @samp{@{@}}) @item all non-negative object numbers. (Note that a negative object number doesn't necessarily mean that such an object exists.) @end itemize @noindent All other values are false: @itemize @bullet @item zero @item the empty string (@samp{""}) @item the empty list (@samp{@{@}}) @item all positive object numbers @item all error values @end itemize There are four kinds of expressions and two kinds of statements that depend upon this classification of COOL values. In describing them, we sometimes refer to the @dfn{truth value} of a COOL value; this is just @dfn{true} or @dfn{false}, the category into which that COOL value is classified. To negate the truth value of a COOL value, use the @samp{!} operator: @example ! @var{expression} @end example If the value of @var{expression} is true, @samp{!} returns 0; otherwise, it returns 1: @example ! "foo" @result{} 0 ! (3 >= 4) @result{} 1 @end example @noindent The negation operator is usually read as ``not.'' It is frequently useful to test more than one condition to see if some or all of them are true. COOL provides two operators for this: @example @var{expression-1} && @var{expression-2} @var{expression-1} || @var{expression-2} @end example @noindent These operators are usually read as ``and'' and ``or,'' respectively. The @samp{&&} operator first evaluates @var{expression-1}. If it returns a true value, then @var{expression-2} is evaluated and its value becomes the value of the @samp{&&} expression as a whole; otherwise, the value of @var{expression-1} is used as the value of the @samp{&&} expression. Note that @var{expression-2} is only evaluated if @var{expression-1} returns a true value. @refill The @samp{||} operator works similarly, except that @var{expression-2} is evaluated only if @var{expression-1} returns a false value. These two operators behave very much like ``and'' and ``or'' in English: @example 1 && 1 @result{} 1 0 && 1 @result{} 0 0 && 0 @result{} 0 1 || 1 @result{} 1 0 || 1 @result{} 1 0 || 0 @result{} 0 17 <= 23 && 23 <= 27 @result{} 1 @end example @subsection Lists and strings @cindex lists @cindex strings As was mentioned earlier, lists can be constructed by writing a comma-separated sequence of expressions inside curly braces: @example @{@var{expression-1}, @var{expression-2}, @dots{}, @var{expression-N}@} @end example @noindent The resulting list has the value of @var{expression-1} as its first element, that of @var{expression-2} as the second, etc. @example @{3 < 4, 3 <= 4, 3 >= 4, 3 > 4@} @result{} @{1, 1, 0, 0@} @end example Both strings and lists can be seen as ordered sequences of COOL values. In the case of strings, each is a sequence of single-character strings; that is, one can view the string @samp{"bar"} as a sequence of the strings @samp{"b"}, @samp{"a"}, and @samp{"r"}. COOL allows you to refer to the elements of lists and strings by number, the @dfn{index} of that element in the list or string. The first element in a list or string has index 1, the second has index 2, and so on. @subsubheading Extracting an Element from a List or String @cindex list extracting @cindex string extracting The indexing expression in COOL extracts a specified element from a list or string: @example @var{expression-1}[@var{expression-2}] @end example @vindex E_TYPE @vindex E_RANGE First, @var{expression-1} is evaluated; it must return a list or a string (the @dfn{sequence}). Then, @var{expression-2} is evaluated and must return a number (the @dfn{index}). If either of the expressions returns some other type of value, @code{E_TYPE} is raised. The index must be between 1 and the length of the sequence, inclusive; if it is not, then @code{E_RANGE} is raised. The value of the indexing expression is the index'th element in the sequence. @example "fob"[2] @result{} "o" "fob"[1] @result{} "f" @{#12, #23, #34@}[3] @result{} #34 @end example @noindent Note that there are no legal indices for the empty string or list, since there are no numbers between 1 and 0 (the length of the empty string or list). @ignore @subsubsection Replacing an element of a list @cindex list modification It often happens that one wants to change just one particular slot of a list, which is stored in a variable. This can be done conveniently using an @dfn{indexed assignment} having the following form: @example @var{variable}[@var{index-expr}] = @var{result-expr} @end example @vindex E_TYPE @vindex E_INVIND @vindex E_VARNF @noindent This writes into a variable. The usual errors (@code{E_TYPE}, @code{E_INVIND}, and @code{E_VARNF} may be raised. Correspondingly, if @var{variable} does not yet have a value (i.e., it has never been assigned to), @code{E_VARNF} will be raised. @vindex E_RANGE If @var{index-expr} is not a number, or if the value of @var{variable} is not a list, @code{E_TYPE} is raised. Note that indexed assignment does not work for strings. Now suppose @var{index-expr} evaluates to a number @var{k}. If @var{k} is outside the range of the list (i.e. smaller than 1 or greater than the length of the list), @code{E_RANGE} is raised. Otherwise, the actual assignment takes place. The variable is assigned a new list that is identical to the original one except at the @var{k}-th position, where the new list contains the result of @var{result-expr} instead. The assignment expression itself returns the value of @var{result-expr}. For the following examples, assume that @code{l} initially contains the list @samp{@{1, 2, 3@}}: @example l[5] = 3 @error{} E_RANGE l["first"] = 4 @error{} E_TYPE l[2] = l[2] + 3 @result{} 5 l @result{} @{1, 5, 3@} l[2] = "foo" @result{} "foo" l @result{} @{1, "foo", 3@} @end example @noindent Note that, after an indexed assignment, the variable contains a @emph{new} list, a copy of the original list in all but the @var{k}-th place, where it contains a new value. In programming-language jargon, the original list is not mutated, and there is no aliasing. (Indeed, no COOL value is mutable and no aliasing ever occurs.) Indexed assignment can be nested to many levels, to work on nested lists. Assume that @code{l} initially contains the list @example @{@{1, 2, 3@}, @{4, 5, 6@}, "foo"@} @end example @noindent in the following examples: @example l[7] = 4 @error{} E_RANGE l[1][8] = 35 @error{} E_RANGE l[3][2] = "c" @error{} E_TYPE l[1][1][1] = 3 @error{} E_TYPE l[2][2] = -l[2][2] @result{} -5 l @result{} @{@{1, 2, 3@}, @{4, -5, 6@}, "foo"@} l[2] = "bar" @result{} "bar" l @result{} @{@{1, 2, 3@}, "bar", "foo"@} @end example @vindex E_RANGE @vindex E_TYPE @noindent The first two examples raise @code{E_RANGE} because 7 is out of the range of @code{l} and 8 is out of the range of @code{l[1]}. The next two examples raise @code{E_TYPE} because @code{l[3]} and @code{l[1][1]} are not lists. @end ignore @subsubheading Extracting a subsequence of a list or string @cindex list extracting @cindex string extracting The range expression extracts a specified subsequence from a list or string: @example @var{expression-1}[@var{expression-2}..@var{expression-3}] @var{expression-1}[..@var{expression-3}] @var{expression-1}[@var{expression-2}..] @end example @vindex E_TYPE @vindex E_RANGE The three expressions are evaluated in order. @var{Expression-1} must return a list or string (the @dfn{sequence}) and the other two expressions must return numbers (the @dfn{low} and @dfn{high} indices, respectively); otherwise, @code{E_TYPE} is raised. If the low index is greater than the high index, then the empty string or list is returned, depending on whether the sequence is a string or a list. Otherwise, both indices must be between 1 and the length of the sequence; @code{E_RANGE} is raised if they are not. A new list or string is returned that contains just the elements of the sequence with indices between the low and high bounds. As the second and third forms show, you can leave off either the low or high index; you'll automatically get 1 if you leave off the low index, and the value of length of the sequence if you leave off the high index. @example "foobar"[2..6] @result{} "oobar" "foobar"[2..] @result{} "oobar" "foobar"[3..3] @result{} "o" "foobar"[..3] @result{} "foo" "foobar"[17..12] @result{} "" @{"one", "two", "three"@}[1..2] @result{} @{"one", "two"@} @{"one", "two", "three"@}[3..3] @result{} @{"three"@} @{"one", "two", "three"@}[17..12] @result{} @{@} @end example @subsubheading Other operations on lists and strings @findex in The membership expression tests whether or not a given COOL value is an element of a given list, or a substring of a given string and, if so, with what index: @example @var{expression-1} in @var{expression-2} @end example @vindex E_TYPE @var{Expression-2} must return a list or string, otherwise, @code{E_TYPE} is raised. If the value of @var{expression-1} is in that list or string, then the index of its first occurrence in the list or string is returned; otherwise, the @code{in} expression returns 0. @example 2 in @{5, 8, 2, 3@} @result{} 3 7 in @{5, 8, 2, 3@} @result{} 0 "bar" in @{"Foo", "Bar", "Baz"@} @result{} 2 "bit" in "frobitz" @result{} 4 @end example @noindent Note that the membership operator is case-insensitive in comparing strings, just like the comparison operators. Note also that since it returns zero only if the given value is not in the given list or string, the @code{in} expression can be used either as a membership test or as an element or substring locator. @subsection Calling built-in functions and other methods @cindex built-in functions @cindex methods COOL provides a number of functions for performing a variety of operations; a complete list, giving their names, arguments, and semantics, appears in a separate section later. The syntax of a call to a built-in function is as follows: @example @var{name}(@var{expr-1}, @var{expr-2}, @dots{}, @var{expr-N}) @end example @vindex E_TYPE @findex lengthof @noindent where @var{name} is the name of one of the built-in functions. The expressions between the parentheses, called @dfn{arguments}, are each evaluated in turn and then given to the named function. Most functions require that certain of the arguments have certain specified types (e.g., the @code{lengthof()} function requires a list or a string as its argument); @code{E_TYPE} is raised if any argument has the wrong type. Object methods can also call other methods, usually using this syntax: @example @var{expr-0}.@var{name}(@var{expr-1}, @var{expr-2}, @dots{}, @var{expr-N}) @end example @noindent or, if there aren't any arguments you can use either of the following 2 forms: @example @var{expr-0}.@var{name}() @var{expr-0}.@var{name} @end example @vindex E_TYPE @vindex E_OBJNF @vindex E_MAXREC @vindex E_METHODNF @noindent @var{Expr-0} must return an object number; @code{E_TYPE} is raised otherwise; if @var{expr-0} doesn't evaluate to an object value, @code{E_INVIND} is raised. If the object with that number does not exist, @code{E_OBJNF} is raised. If this task is too deeply nested in methods calling methods calling methods, then @code{E_MAXREC} is raised; the limit in COOLMUD at this writing is 50 levels. If neither the object nor any of its ancestors defines a method matching the given name, @code{E_METHODNF} is raised. Otherwise, if none of these things happens, the named method on the given object is called; the various built-in variables have the following initial values in the called method: @table @code @item this @vindex this an object, the value of @var{expr-0} @item args @vindex args a list, the values of @var{expr-1}, @var{expr-2}, etc. @item caller @vindex caller an object, the value of @code{this} in the calling method @item player @vindex player an object, the same value as it had initially in the calling method. @end table Note that these are really pseudo-variables; they're read-only and you can't assign new values to them. We said ``usually'' at the beginning of the previous paragraph because that syntax is used when the @var{name} follows the rules for allowed variable names. There is also a syntax allowing you to compute the name of the method: @example @var{expr-0}.(@var{expr-00})(@var{expr-1}, @var{expr-2}, @dots{}, @var{expr-N}) @end example @vindex E_TYPE @noindent The expression @var{expr-00} must return a string; @code{E_TYPE} is raised otherwise. @subsection Parentheses and operator precedence @cindex parentheses @cindex precedence As shown in a few examples above, COOL allows you to use parentheses to make it clear how you intend for complex expressions to be grouped. For example, the expression @example 3 * (4 + 5) @end example @noindent performs the addition of 4 and 5 before multiplying the result by 3. If you leave out the parentheses, COOL will figure out how to group the expression according to certain rules. The first of these is that some operators have higher @dfn{precedence} than others; operators with higher precedence will bind more tightly to their operands than those with lower precedence. For example, multiplication has higher precedence than addition; thus, if the parentheses had been left out of the expression in the previous paragraph, COOL would have grouped it as follows: @example (3 * 4) + 5 @end example The table below gives the relative precedence of all of the COOL operators; operators on higher lines in the table have higher precedence and those on the same line have identical precedence: @example ! - @r{(without a left operand)} * / % + - == != < <= > >= in && || = @end example @noindent Thus, the horrendous expression @example x = a < b && c > d + e * f ? w in y | - q - r @end example @noindent would be grouped as follows: @example x = (((a < b) && (c > (d + (e * f)))) ? (w in y) | ((- q) - r)) @end example @noindent It is best to keep expressions simpler than this and to use parentheses liberally to make your meaning clear to other humans. @section Statements @cindex statements Statements are COOL constructs that, in contrast to expressions, perform some useful, non-value-producing operation. For example, there are several kinds of statements, called `looping constructs', that repeatedly perform some set of operations. @subsection Simple statements The simplest kind of statement is the @dfn{null} statement, consisting of just a semicolon: @example ; @end example @noindent It doesn't do anything at all. The next simplest statements are also some of the most common, the expression statement and the assignment statement: @example @var{expression}; @var{var} = @var{expression}; @end example @noindent For the expression statement, the given expression is evaluated and the resulting value is ignored. The typical expression for such statements is the method call. Of course, there's no use for such a statement unless the evaluation of @var{expression} has some side-effect, such as printing some text on someone's screen, etc. For the assignment statement, the variable gets the new value. @subsection Conditional execution @cindex conditional execution @findex if The @code{if} statement allows you to decide whether or not to perform some statements based on the value of an expression: @example if (@var{expression}) @var{statements} endif @end example @noindent @var{Expression} is evaluated, if it returns a true value, the statements are executed; otherwise, nothing is done. @findex else Sometimes you'll want to perform one set of statements if some condition is true and some other set of statements otherwise. The optional @code{else} phrase in an @code{if} statement allows you to do this: @example if (@var{expression}) @var{statements-1} else @var{statements-2} endif @end example @noindent This statement is executed just like the previous one, except that @var{statements-1} are executed if @var{expression} returns a true value and @var{statements-2} are executed otherwise. Sometimes, you'll need to test several conditions in a kind of nested fashion: @example if (@var{expression-1}) @var{statements-1} else if (@var{expression-2}) @var{statements-2} else if (@var{expression-3}) @var{statements-3} else @var{statements-4} endif endif endif @end example @noindent Such code can easily become tedious to write and difficult to read. COOL provides a somewhat simpler notation for such cases: @example if (@var{expression-1}) @var{statements-1} elseif (@var{expression-2}) @var{statements-2} elseif (@var{expression-3}) @var{statements-3} else @var{statements-4} endif @end example @findex elseif @noindent Note that @code{elseif} is written as a single word, without any spaces. This simpler version has the very same meaning as the original: evaluate @var{expression-i} for @var{i} equal to 1, 2, and 3, in turn, until one of them returns a true value; then execute the @var{statements-i} associated with that expression. If none of the @var{expression-i} return a true value, then execute @var{statements-4}. Any number of @code{elseif} phrases can appear, each having this form: @example elseif (@var{expression}) @var{statements} @end example The complete syntax of the @code{if} statement is as follows: @example if (@var{expression}) @var{statements} @var{zero-or-more-elseif-phrases} @var{an-optional-else-phrase} endif @end example @subsection Iteration @cindex iteration COOL provides three different kinds of looping statements, allowing you to have a set of statements executed (1) once for each element of a given list, (2) once for each number in a given range, and (3) over and over until a given condition stops being true. To perform some statements once for each element of a given list, you use this syntax: @example for @var{variable} in (@var{expression}) @var{statements} endfor @end example @vindex E_TYPE @noindent The @var{expression} is evaluated and should return a list; if it does not, @code{E_TYPE} is generated. The @var{statements} are then executed once for each element of that list in turn; each time, the given @var{variable} is assigned the value of the element in question. For example, consider the following statements: @example odds = @{1, 3, 5, 7, 9@}; evens = @{@}; for n in (odds) evens = listappend(evens, n + 1); endfor @end example @noindent The value of the variable @code{evens} after executing these statements is the list @example @{2, 4, 6, 8, 10@} @end example The syntax for performing a set of statements once for each number in a given range is as follows: @example for @var{variable} in [@var{expression-1}..@var{expression-2}] @var{statements} endfor @end example @vindex E_TYPE @noindent The two expressions are evaluated and should return numbers; @code{E_TYPE} is raised otherwise. The @var{statements} are then executed, once for each integer greater than or equal to the value of @var{expression-1} and less than or equal to the result of @var{expression-2}, in increasing order. Each time, the given variable is assigned the integer in question. For example, consider the following statements: @example evens = @{@}; for n in [1..5] evens = listappend(evens, 2 * n); endfor @end example @noindent The value of the variable @code{evens} after executing these statements is the same as in the previous example, the list @example @{2, 4, 6, 8, 10@} @end example The final kind of loop in COOL executes a set of statements repeatedly as long as a given condition remains true: @example while (@var{expression}) @var{statements} endwhile @end example @findex while @noindent The @var{expression} is evaluated and, if it returns a true value, the @var{statements} are executed; then, execution of the @code{while} statement begins all over again with the evaluation of the expression. That is, execution alternates between evaluating the expression and executing the statements until the expression returns a false value. The following statements have precisely the same effect as the loop just shown above: @example evens = @{@}; n = 1; while (n <= 5) evens = listappend(evens, 2 * n); n = n + 1; endwhile @end example With each kind of loop, it is possible that the statements in the body of the loop will never be executed at all. For iteration over lists, this happens when the list returned by the expression is empty. For iteration on numbers, it happens when @var{expression-1} returns a larger number than @var{expression-2}. Finally, for the @code{while} loop, it happens if the expression returns a false value the first time it is evaluated. Inside either of the @code{for} or @code{while} iteration loops you can have a @code{break} or @code{continue} statement. The @code{break} statement causes execution of the @code{for} or @code{while} loop to end prematurely; execution continues with the first statement after the @code{endfor} or @code{endwhile}. The @code{continue} statement causes all statements after it in the iteration loop to be skipped and execution continues with the next iteration of the loop. If you have @code{for} or @code{while} statements inside of other @code{for} or @code{while} statements you can specify which iteration loop should be broken out of by following @code{break} with a number specifying the loop level, where 1 means the current loop. Likewise, for the @code{continue} statement you can specify which iteration loop to to skip the rest of by following @code{continue} with a number specifying the loop level. @subsection Returning a value from a method @cindex returning values @findex return The COOL program in a method is just a sequence of statements. Normally, when the method is called, those statements are simply executed in order and then the number 0 is returned as the value of the method-call expression. Using the @code{return} statement, one can change this behavior. The @code{return} statement has one of the following two forms: @example return; @end example @noindent or @example return @var{expression}; @end example @noindent When it is executed, execution of the current method is terminated immediately after evaluating the given @var{expression}, if any. The method-call expression that started the execution of this method then returns either the value of @var{expression} or the number 0, if no @var{expression} was provided. @subsection Executing statements at a later time @cindex delayed execution It is sometimes useful to have some sequence of statements execute at a later time, without human intervention. For example, one might implement an object that, when thrown into the air, eventually falls back to the ground; the @code{throw} verb on that object should arrange to print a message about the object landing on the ground, but the message shouldn't be printed until some number of seconds have passed. @findex at The @code{at} statement is intended for just such situations and has the following syntax: @example at (@var{expression}) @var{statements} endat @end example @noindent The @code{at} statement first executes the expression, which must return a number; call that number @var{n}. It then creates a new COOL @dfn{task} that will, after at least @var{n} seconds, execute the statements. When the new task begins, all variables will have the values they had at the time the @code{at} statement was executed. The task executing the @code{at} statement immediately continues execution. @subsection Errors @cindex errors Statements do not return values, but some kinds of statements can be used improperly and thus generate errors. If such an error is generated in a method that is not ignoring that particular error, then an error message is printed to the current player and the current command (or task, really) is aborted. If the method is ignoring that error then the error is ignored and the statement that generated it is simply skipped; execution proceeds with the next statement. @var{(Need to add stuff about @code{raise} here as well.)} @section Built-in functions @cindex built-in functions There are a number of built-in functions available to COOL programmers. Each one is discussed in detail in this section. The presentation is broken into subsections by grouping functions with similar or related uses. @vindex E_TYPE For most functions, the expected types of the arguments are given; if the arguments are not of these types, @code{E_TYPE} is raised. Some arguments can be of any type; in such cases, no type specification is given for the argument. For most functions, the type of the result of the function is given. Some functions do not return a result; in such cases, the specification @code{void} is used. Some functions can return a result of any type, for them the specificaton @code{value} is used. @vindex E_ARGS Most functions take a fixed number of arguments and, in some cases, one or two optional arguments. If a function is called with too many or too few arguments, @code{E_ARGS} is raised. @subsection Passing execution @cindex passing One of the most important facilities in an object-oriented programming language is ability for a child object to make use of a parent's implementation of some operation, even when the child provides its own definition for that operation. The @code{pass()} function provides this facility in COOL. Often it is useful for a child object to define a method that @emph{augments} the behavior of a method on its parent object. For example, in the @code{boot} database, the @code{DESCRIBED} object (which is an ancestor of most other objects) defines a method called @code{description} that simply returns the value of @code{description}; this method is used by the implementation of the @code{look} command. In many cases, a programmer would like the description of some object to include some non-constant part; for example, a sentence about whether or not the object was `awake' or `sleeping'. This sentence should be added onto the end of the normal description. The programmer would like to have a means of calling the normal @code{description} method and then appending the sentence onto the end of that description. The function @code{pass()} is for such situations. Thus, in the example above, the child-object's @code{description} method might have the following implementation: @example return pass() + " It is " + (this.awake ? "awake." | "sleeping."); @end example @noindent That is, it calls its parent's @code{description} method and then appends to the result a sentence whose content is computed based on the value returned by a method on the object. @deftypefun value pass (@var{arg}, @dots{}) @deftypefunx value pass (@var{arg}, @dots{}) to @var{object} @findex pass @code{pass} calls the method with the same name on the parent of the object who's method is running. The arguments given to @code{pass} are the ones given to the called method and the returned value of the called method is returned from the call to @code{pass}. The initial value of @code{this} in the called method is the same as in the calling method. Since COOL provides for multiple inheritence, the second form of the @code{pass()} call can be used to specify which parent's method to call. @end deftypefun @subsection Type-checking and conversion @cindex type-checking @cindex conversions @deftypefun num typeof (@var{value}) @findex typeof Takes any COOL value and returns a number representing the type of @var{value}. The result is the value of one of these built-in constants: @code{NUM}, @code{STR}, @code{LIST}, @code{OBJ}, or @code{ERR}. Thus, one usually writes code like this: @example if (typeof(x) == LIST) @dots{} @end example @noindent and not like this: @example if (typeof(x) == 3) @dots{} @end example @noindent because the former is more readable than the latter. @end deftypefun @deftypefun str tostr (@var{value}) @findex tostr Converts the given COOL value into a string and returns it. @example tostr(17) @result{} "17" tostr(#17) @result{} "#17" tostr("foo") @result{} "foo" tostr(@{1, 2@}) @result{} "@{1, 2@}" tostr(E_PERM) @result{} "Permission denied" @end example @end deftypefun @deftypefun num tonum (@var{value}) @findex tonum Converts the given COOL value into a number and returns it. Object numbers are converted into the equivalent numbers, strings are parsed as the decimal encoding of a number, and errors are converted into numbers. @code{tonum()} raises @code{E_TYPE} if @var{value} is a list. If @var{value} is a string but the string does not contain a syntactically-correct number, then @code{tonum()} returns 0. @example tonum(#34) @result{} 34 tonum("34") @result{} 34 tonum(" - 34 ") @result{} 34 tonum(E_TYPE) @result{} 1 @end example @end deftypefun @noindent Notice that when parsing digits, spaces are ignored. @deftypefun obj toobj (@var{value}) @findex toobj Converts the given COOL value into an object number and returns it. The conversions are very similar to those for @code{tonum()} except that for strings, the number @emph{may} be preceded by @samp{#}. @example toobj("34") @result{} #34 toobj("#34") @result{} #34 toobj("foo") @result{} #0 toobj(@{1, 2@}) @error{} E_TYPE @end example @end deftypefun @deftypefun err toerr (@var{value}) @findex toerr Converts the given COOL value into an error value and returns that error value. @end deftypefun @subsection Operations on strings @cindex strings @cindex string operations @deftypefun list explode (str @var{string} [, str @var{string}]) @findex explode Break @var{string} into a list of strings. By default, explode breaks on spaces; the optional second argument is the character to break on. @end deftypefun @deftypefun num lengthof (str @var{string}) @findex lengthof Returns the number of characters in @var{string}. It is also permissible to pass a list to @code{lengthof()}; see the description in the next section. @example lengthof("foo") @result{} 3 lengthof("") @result{} 0 @end example @end deftypefun @deftypefun str crypt (str @var{text} [, str @var{salt}]) @findex crypt Encrypts the given @var{text} using the standard UNIX encryption method. If provided, @var{salt} should be a two-character string used for the extra encryption ``salt'' in the algorithm. If @var{salt} is not provided, a random pair of characters is used. The salt used is also returned as the first two characters of the encrypted string. Aside from the possibly-random selection of the salt, the encryption algorithm is deterministic. You can test whether or not a given string is the same as the one used to produced a given piece of encrypted text; extract the first two characters of the encrypted text and pass the candidate string and those two characters to @code{crypt()}. If the result is identical to the given encrypted text, you've got a match. @example crypt("foobar") @result{} "J3fSFQfgkp26w" crypt("foobar", "J3") @result{} "J3fSFQfgkp26w" crypt("mumble", "J3") @result{} "J3D0.dh.jjmWQ" crypt("foobar", "J4") @result{} "J4AcPxOJ4ncq2" @end example @end deftypefun @deftypefun list match (str @var{subject}, str @var{pattern} [, @var{token}]) @deftypefunx list match_full (str @var{subject}, str @var{pattern}, [, @var{token} ]) @findex match Looks for @var{pattern} as a substring of @var{subject}, where @var{pattern} must start on a word boundary. Word are separated by spaces, or by @var{token} if given. Returns 1 if a match was found, 0 if not. @example match("foo bar baz", "foo") @result{} 1 match("foo bar baz", "f") @result{} 1 match("foo bar baz", "o") @result{} 0 match("large green monster", "green") @result{} 1 match("large green monster", "gre") @result{} 1 match("large*green*monster", "monster", "*") @result{} 1 @end example @code{match_full} is the same as @code{match}, except that @var{pattern} must match a full word within @var{subject}. (Useful for TinyMUD-style exit matching.) @example match_full("foo bar baz", "foo") @result{} 1 match_full("foo bar baz", "f") @result{} 0 match_full("out;back;exit;leave", "out", ";") @result{} 1 match_full("out;back;exit;leave", "ou", ";") @result{} 0 @end example @end deftypefun @subsection Operations on lists @cindex lists @cindex list operations @deftypefun num lengthof (list @var{list}) @findex lengthof Returns the number of elements in @var{list}. It is also permissible to pass a string to @code{lengthof()}; see the description in the previous section. @example lengthof(@{1, 2, 3@}) @result{} 3 lengthof(@{@}) @result{} 0 @end example @end deftypefun @deftypefun list listinsert (list @var{list}, @var{value} [, num @var{index}]) @deftypefunx list listappend (list @var{list}, @var{value} [, num @var{index}]) @findex listinsert @findex listappend These functions return a copy of @var{list} with @var{value} added as a new element. @code{listinsert()} and @code{listappend()} add @var{value} before and after (respectively) the existing element with the given @var{index}, if provided. The following three expressions always have the same value: @example listinsert(@var{list}, @var{element}, @var{index}) listappend(@var{list}, @var{element}, @var{index} - 1) @end example If @var{index} is not provided, then @code{listappend()} adds the @var{value} at the end of the list and @code{listinsert()} adds it at the beginning. @example x = @{1, 2, 3@}; listappend(x, 4, 2) @result{} @{1, 2, 4, 3@} listinsert(x, 4, 2) @result{} @{1, 4, 2, 3@} listappend(x, 4) @result{} @{1, 2, 3, 4@} listinsert(x, 4) @result{} @{4, 1, 2, 3@} @end example @end deftypefun @deftypefun list listdelete (list @var{list}, num @var{index}) @findex listdelete Returns a copy of @var{list} with the @var{index}th element removed. If @var{index} is not in the range @samp{[1..length(@var{list})]}, @code{E_RANGE} is raised. @example x = @{"foo", "bar", "baz"@}; listdelete(x, 2) @result{} @{"foo", "baz"@} @end example @end deftypefun @deftypefun list listassign (list @var{list}, @var{value}, num @var{index}) @findex listassign Returns a copy of @var{list} with the @var{index}th element replaced by @var{value}. If @var{index} is not in the range @samp{[1..length(@var{list})]}, @code{E_RANGE} is raised. @example x = @{"foo", "bar", "baz"@}; listassign(x, "mumble", 2) @result{} @{"foo", "mumble", "baz"@} @end example @end deftypefun @deftypefun list setadd (list @var{list}, @var{value}) @deftypefunx list setremove (list @var{list}, @var{value}) @findex setadd @findex setremove Returns a copy of @var{list} with the given @var{value} added or removed, as appropriate; @var{list} is treated as a mathematical set. @code{setadd()} only adds @var{value} if it is not already an element of @var{list}. @var{value} is added at the end of the resulting list, if at all. Similarly, @code{setremove()} returns a list identical to @var{list} if @var{value} is not an element. If @var{value} appears more than once in @var{list}, only the first occurrence is removed in the returned copy. @example setadd(@{1, 2, 3@}, 3) @result{} @{1, 2, 3@} setadd(@{1, 2, 3@}, 4) @result{} @{1, 2, 3, 4@} setremove(@{1, 2, 3@}, 3) @result{} @{1, 2@} setremove(@{1, 2, 3@}, 4) @result{} @{1, 2, 3@} setremove(@{1, 2, 3, 2@}, 2) @result{} @{1, 3, 2@} @end example @end deftypefun @subsection Operations on objects @deftypefun obj clone () @findex clone Clone the current object. A new object is created, whose parent is the current object. Returns the object ID of the new object. If the current object no longer exists (ie., has been destroyed), @samp{#-1} is returned. @end deftypefun @deftypefun void destroy () @findex destroy Destroy the current object. The object itself is responsible for cleaning up any references to itself prior to this call. This might include removing any contained objects, re-parenting or destroying any instances of it, etc. @end deftypefun @deftypefun void chparents (list @var{list}) @findex chparents @end deftypefun @deftypefun void call_verb (str @var{string}) @findex call_verb @code{call_verb} isn't a function, it's a special method; when an object receives the @code{call_verb} message, the server intercepts it and calls the appropriate verb. The argument should be the command string to be parsed, which is then matched against each verb on the object. If a match is found, the associated method is called, with the parsed results in @code{args}. (@code{args[1]} @equiv{} @code{verb}, @code{args[2]} @equiv{} @code{dobj}, @code{args[3]} @equiv{} @code{prep}, @code{args[4]} @equiv{} @code{iobj}). @end deftypefun @deftypefun void lock (str @var{string}) @findex lock This function is used to lock an object, to prevent another execution stream from modifying the object before the current stream is finished with it (see the section on locking). The argument is an arbitrary string, the name of the lock to place on the object. Locks placed by an execution thread remain in effect until a corresponding @code{unlock()} call, or until the thread terminates. @end deftypefun @deftypefun void rm_verb (str @var{verbname}) @findex rm_verb Removes the first verb named @var{verbname} from the current object. The argument may also be a string representing the number indexing the verb to be removed (starting at 0). eg., @samp{rm_verb("3")} would remove the 4th verb. @end deftypefun @deftypefun void rm_method (str @var{methodname}) @findex rm_method Removes the indicated method from the current object. Note that COOLMUD has special provision to allow a method to remove itself and continue executing. It won't be actually destroyed until the method finishes. @end deftypefun @deftypefun void rm_var (str @var{variablename}) @findex rm_var Removes the indicated variable from the current object. @end deftypefun @deftypefun void unlock (str @var{string}) @findex unlock Removes the indicated lock from the current object. If any execution threads are waiting for this lock to be removed, they will execute. @end deftypefun @deftypefun void add_verb (str @var{verbname}, str @var{preposition}, str @var{methodname}) @findex add_verb Adds a verb to the current object. The first argument is the name of the verb. The second argument is the preposition, or @samp{""} for none. The third argument is the name of the method to call in the current object when the verb gets triggered. The verb is added to the end of the object's verb list, unless a verb with the same name and no preposition exists, in which case it is inserted before that verb. This prevents a verb with no preposition masking one with a preposition. @end deftypefun @deftypefun void setvar (str @var{string}, @var{value}) @findex setvar @vindex E_VARNF @vindex E_TYPE Sets a variable, specified in @var{string}, on the current object to @var{value}. @code{E_VARNF} is raised if the variable doesn't exist, and @code{E_TYPE} is raised if there's a type mismatch (either between an existing variable, or an inherited one). @end deftypefun @deftypefun list verbs () @findex verbs Returns a list of verbs on the current object. Each element of the list is a 3-element list, consisting of 3 strings: the verb name, the preposition, and the method to call. @end deftypefun @deftypefun list vars () @findex vars Returns a list of variables on the current object. Each element of the list is a string containing the name of the variable. @end deftypefun @deftypefun value getvar (str @var{variablename}) @findex getvar Gets the value of the indicated variable on the current object. This allows the use of an arbitrary string to get the value of a variable. (eg., @samp{getvar("abc" + "def")}) @end deftypefun @deftypefun list methods () @findex methods Returns a list of methods on the current object. Each element of the list is a string containing the name of the method. @end deftypefun @deftypefun num hasparent (obj @var{object}) @findex hasparent Returns a positive value if the current object has @var{object} as a parent. This function looks recursively on all parents of the current object, so it will return 1 if the object has @var{object} as a parent anywhere in its inheritance tree, and 0 otherwise. @end deftypefun @deftypefun str spew_method (str @var{methodname}) @findex spew_method Returns a string containing the internal stack-machine code for method @var{methodname}. This code is pretty unintelligible unless your brain works in RPN. Even then, some instructions are hard to figure out, and there's not much point. Only for the habitually curious. @end deftypefun @deftypefun str list_method (str @var{methodname} [, num @var{lineno} [, num @var{fullbrackets} [, num @var{indent}]]]) @findex list_method Returns a string containing the decompiled code for method @var{methodname}. This works by turning the stack machine code back into readable form. It does automatic indentation, line numbering, and smart bracketing (ie., it will use the minimum number of brackets when decompiling an expression). The three optional arguments are numeric arguments which control the decompilation: @table @var @item lineno Turns line numbering on and off. @item fullbrackets When on, dumb bracketing will be used in every expression. Default is off, or smart bracketing. @item indent The number of spaces to use in indenting the code. @end table @end deftypefun @deftypefun void echo (str @var{string}) @findex echo Display @var{string} to the current object, a player. @end deftypefun @deftypefun void quit () @findex quit Disconnect the current object, a player. @end deftypefun @deftypefun void program ([obj @var{object}, str @var{methodname}]) @findex program Enter programming mode. This sets a flag on the player's descriptor such that all input from the player is diverted to a temporary file. When the player enters @samp{.}, the file is compiled, and then erased. There can either be no arguments, in which case the server expects a series of objects, or two arguments, which should be the object and method to program. In either case, the server currently uses a built-in set of permissions checks to determine whether the player may reprogram that object: either they must be in the object's @code{owners} list, or in @code{SYS_OBJ.wizards}. @end deftypefun @deftypefun num serverof (obj @var{object}) @findex serverof Returns a number representing the server ID of @var{object}. This ID is used internally by the server, and has no meaning except that ID zero is the local MUD. So the statement @example if (!serverof(obj)) ... endif @end example @noindent would evaluate to true if @var{object} is a local object. @end deftypefun @deftypefun str servername (obj @var{object}) @findex servername Returns a string representing the server name part of @var{object}. @end deftypefun @subsection Miscellaneous operations @cindex miscellaneous operations @deftypefun num random (num @var{n}) @findex random Returns a random value between 1 and @var{n}. @end deftypefun @deftypefun num time () @findex time Returns the current time, represented as the number of seconds that have elapsed since midnight on 1 January 1970, Greenwich Mean Time. @end deftypefun @subsection System functions @deftypefun void shutdown () @findex shutdown Shuts down the MUD. The database is written, remote servers disconnected, and the COOLMUD process terminates. @end deftypefun @deftypefun void dump () @findex dump Syncs the cache to the database so that the database on disk is current. @end deftypefun @deftypefun void writelog (str @var{string}) @findex writelog Writes @var{string} to the logfile, prepended by a timestamp. @end deftypefun @deftypefun num checkmem () @findex checkmem Returns a string showing the amount of memory dynamically allocated, and how many chunks it was allocated in. If the server was not compiled with @code{-DCHECKMEM}, this function will return @samp{"Memory checking disabled."} @end deftypefun @section Syntax for object code @cindex object code syntax The syntax for the code of an object is as follows: @example @code{object} @var{objectname} @var{parent declarations} @var{verb declarations} @var{variable declarations} @var{method declarations} @code{endobject} @end example The syntax for an object name is the same as for variables, given above. @subsection Parent declarations @cindex parents The syntax for the parent declarations is as follows: @example @code{parents} @var{parent-1} @code{,} @dots{} @var{parent-n} @code{;} @end example @subsection Verb declarations @cindex verbs To bind a verb to a method you use the @code{verb} declaration: @example @code{verb} @var{string} @code{=} @var{method} @code{;} @code{verb} @var{string} @code{:} @var{string} @code{=} @var{method} @code{;} @end example @subsection Variable declarations @cindex variables The syntax for the variable declarations is: @example @var{vartype} @var{var-1} @code{,} @dots{} @var{var-N} @code{;} @end example Where @var{vartype} is one of @code{num}, @code{str}, @code{list}, or @code{obj}. You can have several lines of variable declarations, one for each different type, and you don't have to have variables of the same type all declared on the same line; you can have several variable declaration lines for the same type. @subsection Method declarations Method declarations look similar to object code: @example @code{method} @var{methodname} @code{var} @var{local variable declarations} @code{ignore} @var{errors} @code{endmethod} @end example @chapter Differences between COOL and MOO LambdaMOO objects consist of attributes, properties, and verbs. COOLMUD objects consist of variables and methods; there are no attributes. COOLMUD object variables and methods are similar to LambdaMOO properties and verbs. With LambdaMOO, all properties can be accessed by other objects, as long as the permissions allow it, which they generally do except for special properties that need to be hidden. With LambdaMOO properties have an owner. With COOLMUD, object variables can only be accessed if there is a method that provides acces, otherwise the object variable is inaccessible. COOLMUD object variables don't have an owner, just the owners of the object. With COOLMUD the object variables' methods that provide access to them also completely control any permission scheme. COOLMUD methods don't have a ``debug'' bit, methods can @code{ignore} specific errors if they want to. With COOLMUD command parsing is much more controlled by the objects. For the sake of example, let's ignore prepositions. When a palyer types a command, some simple matching is done; all objects that have that ``verb'' defined on them have the method that's bound to that verb called. The method is responsible for checking the arguments to see if they match its object; e.g., @code{args[2]} is typically the object and @code{args[1]} is the verb. The method returns 1 to signify that the arguments didn't match for it and for the parser to continue calling methods on other objects. The method returns 0 to specify that it was the desired object and the parser stops calling methods on the rest of the objects. With COOLMUD, verbs are ``bound'' to methods. Unless a method is bound to a verb, it can't be accessed by a player. With LambdaMOO there is a ``template'' specified for the arguments when creating a verb and the template @samp{this none this} is typically used to specify a verb that isn't to be accessed as a command typed by a player; that is, the verb will be used as a subroutine. With COOLMUD you simply don't bind the method to a verb if you want it only used as a subroutine. COOLMUD treats assignments as statements, not expressions. This means that you can't do looping constructs like @example while ((var = name.method) != someval) @dots{} endwhile @end example @chapter Setting up a new COOLMUD (explain format of .cfg file.) @section Interconnecting COOLMUDs @iftex @unnumbered Function Index @printindex fn @unnumbered Variable Index @printindex vr @unnumbered Concept Index @printindex cp @contents @end iftex @bye Local Variables: makeinfo-options: "+fill-column 70 +no-split" fill-column: 70 End: