Skip to main content

LPmud A Programmable Multi-User Domain by Lars Pensj| [ Edited from TeX into Ascii by Adam Beeman ] 1 General 1.1 Idea of the game LPmud is a multi user adventure game. That means that several players can be playing the game at the same time, using the same object database. It also means that the players will meet each other, and affect the game for other players. 1.2 History of LPmud In the beginning, I played a lot of Abermud and some Tinymud, and wanted to do something better, combining the two systems. I made the first version of LPmud as some kind of argument, to show that my ideas were possible. Luckily, I didn't know at that time how that would impact my near future. 1.3 Objects, files and programs The programs defining the behaviour of objects are stored in files. Every object has exactly one file defining the program, but every file may be used for more than one object. When an object that is not loaded is referenced, it will automatically be compiled and loaded. More than one instance of an object can be created using the function clone_object(). [See clone_object in the LPC reference manual]. clone_object() should not be used if only one instance of an object is wanted. Cloned objects may be configured differently after creation, hence enabling different behaviour. Chapter 2: Installation and Setup This chapter describes how to get LPmud running from scratch. It works for SUN SparcStation running SunOS 4.1.1. If you are using any other platform you may have some trouble getting the game up. We don't have time or equipment needed for porting the game to other systems. 2.1 Getting LPmud Sources [ Editor's note: Currently, the source for a full 3.0 mudlib is not available. You can choose one of two options: get the old 2.4.5 mudlib and run in compatibility mode, or begin from scratch with the mudlib.n. You could also just wait until someone decides to release a functional 3.0 mudlib. This may be a while. ] LPmud can be retrieved with anonymous FTP from host alcazar.cd.chalmers.se, IP-number 129.16.48.100. Log on as ftp, and give your email address as password. The archive holding the source can be found in `/pub/lpmud/3.0', and is called `3.0.50.tar.Z'. It is a binary file, which means that you have to set FTP in binary mode. This is how a ftp session might look: % ftp alcazar.cd.chalmers.se Connected to alcazar. 220 alcazar FTP server (Version 5.53 Sun May 27 01:43:44 MET DST 1990) ready. Name (alcazar.cd.chalmers.se:arne): ftp 331 Guest login ok, send ident as password. Password: arne@cd.stanford.edu 230 Guest login ok, access restrictions apply. ftp> cd pub/lpmud 250 CWD command successful. ftp> bin 200 Type set to I. ftp> get 3.0.50.tar.Z 200 PORT command successful. 150 Opening BINARY mode data connection for 3.0.50.tar.Z (510193 bytes). 226 Transfer complete. local: 3.0.50.tar.Z remote: 3.0.50.tar.Z 510193 bytes received in 1e-06 seconds (1.4e+06 Kbytes/s) ftp> bye 221 Goodbye. % 2.2 Contents of the Archive The archive contains all you need to set up an LPmud on your host. However you need a mudlib. You can write one yourself or get one by ftp. The software you got in this archive contains the preprocessor, communication stuff, efuns and lots of other functions needed in the game. The other major part is what we call `mudlib'. Everything accessible from within the game is in `mudlib', such as save files, log files and LPC source code. The LPC source code is the code defining what your LPmud will be like. It is the game itself, while the `game driver' is a tool for running the game. There are also some other things included in the archive, among them documentation and some useful utilities. This is what the directory structure in the archive looks like: mud | ---------------------------------------------------------- | | | | | | README bin doc lib src swap | util [ Editor's note: this is what it WILL look like, one day. Currently the source code just spills out into the current directory, making the util directory. So when you unpack 3.0.50.tar.Z, be sure to move the file into a directory called 'src' before unpacking it. The structure I use looks more like this: mud ________|__________ / | | \ mudlib bin src swap | | several subdirs util including doc You have to make these directories yourself... the main differences are the position of the doc directory, which tends to be needed from inside the mudlib. You could just use symbolic links, of course. ] This is a description of what some of the direcories are. [See File Hierarchy for information on the contents of the `lib' directory.] README A file describing where to find the documentation. bin Directory that will contain all the executables after installation. doc All the documentation as a text file, a texinfo file and a PostScript file. lib The `mudlib' directory. src The source code for the `game driver'. util Source code for some utility programs and shell scripts. swap When the game is running it creates a swap file here. 2.3 Unpacking the Source Archive When you unpack the source archive, a directory called `mud' will be created in your current directory. All the files in the archive will be put in the `mud' directory. Before unpacking the archive you should decide where in the filesystem you want to have the game and change directory to that location. [ Editor's note: As of 11/26/91, this was not true. You must create the 'mud' directory and the 'src' directory. Then, change into the 'src' directory before unpacking the source. ] The archive is a compressed tar archive. To unpack it you need one of the commands uncompress or zcat and the program tar. Here is an example of how the archive can be unpacked: [ edited for accuracy ] % cd /usr/src/games % mkdir mud % cd mud % mkdir src % mkdir bin % mkdir swap % cd src % zcat 3.0.50.tar.Z | tar xf - 2.4 Compiling the Game Driver The first thing you have to do is to configure LPmud to suit your system. Change directory to `mud/src'. Edit `config.h' and change any defines needed. They are well commented in the file, but those that it is likely that you want to change are explained here. TIME_TO_SWAP Tells how long the game driver should wait before swapping out an unused object. The time should be high if you have much memory, and low if disk space is more abundant than memory. TIME_TO_RESET Sets the intervall between calls to reset() in objects. PORTNO This is the port number that the games uses. Before setting it, you should ask your system manager what number to use. DOMAINS If this is defined you enable domains, i.e. groups of wizards can work together, with a special domain directory for each group. SWAP_FILE Should be a full path to a file used for swapping objects. It is typically set to `mud/swap' as mentioned previously. LOG_SHOUT If LOG_SHOUT is defined all shouting in the game is logged in a file, `mud/syslog/SHOUTS'. MAX_PLAYERS The maximum number of simultaneous players in the game. The more powerful system you have, the higher it should be. Next, you should edit the `Makefile' and make changes suitable for your system. These are some of the parameters that you might want to change. MALLOC There are three different versions of malloc to choose from. The `Makefile' tells the difference between them. CC What C compiler to use. BINDIR Where to put all the executables. Typically set to `mud/bin'. MUD_LIB The path to mudlib. Usually set to `mud/lib'. After editing `config.h' and `Makefile' you are ready to compile the game driver. Type: make If the compilation is completed without errors, an executable file `driver' should have been created. 2.5 Installing the Game After compiling the game driver, several files have to be installed in their proper places. If you have changed the path for MUD_LIB in the `Makefile' to something other than `mud/lib' in the directory where you extracted the software, you have to move the contents of `mud/lib' to the new location. If you have changed BINDIR in the `Makefile' or SWAP_FILE in `config.h' to be other than those that were extracted, you must make those directories in the new location. After doing that, give the command: make install Now the game driver should be installed in BINDIR. We provide a shell script that restarts the game every time it crashes or is shut down. It restarts the game at most 50 times. After that the script has to be rerun. The script is called `restart_mud' and is located in `mud/src/util'. To install it in BINDIR type: make install.restart_mud If you want the game to be restarted every time your computer is rebooted, ask your system manager to run `restart_mud' from `/etc/rc.local'. Here is an example of what to put in `/etc/rc.local'. if [ -f /usr/games/mud/bin/restart_mud ]; then /bin/su arne -c /usr/games/mud/bin/restart_mud 2>&/dev/null echo 'Starting LPmud' fi [ Editor's note: This assumes the game is run by account 'arne'. ] 2.6 Starting the Game The simplest way of starting the game is to issue the command driver that after a successfull installation resides in `bin'. That command will start the game in 3.0 mode, accepting connections on the port configured in `src/config.h'. These are the command line options that are available: -c Print a message to stdout every time a file is compiled. -d Print debug information. -e Start the game without loading any wizard or domain files. [ Editor's note: This command will start the game, but unless you redirect the output of it, it will also send error messages to the tty that the game was booted from, rather than logging the errors. I recommend you either use restart_mud, or issue the command in this form: driver >& ../mudlib/log/lpmud.log & This will send the output of the game driver (run time errors, etc.) to a log file you can check from inside the game, and background the process. ] Chapter 3: Commands Tied to Functions in Objects All commands except a very few special cases are defined by the objects. All commands have a simple basic way to be recognized. The first word of the sentence is supposed to be the verb. Every command defined is tied to a special function in an object. Commands are defined with the function add_action(), which specifies the verb to be recognised, and the name of the local function to be called [See add_action, in the LPC Reference Manual]. When a living object gives a command which matches a verb with a command defined by an object, then the corresponding function will be called in the specified object. If this function returns 0, then next command with the same verb is tried. If the function returns 1, then he search is terminated. This enables several objects to define commands with the same verbs, but still behave different if the rest of the sentence differs. For example, there might be two armours. One is named leather jacket, and one is named plate mail. Both objects will have defined a command with the verb wear. If the player now gives the command `wear jacket', then we can't know which defined command is called first. Suppose that the wear function in the plate mail is called first. It will then detect that the argument to wear is jacket, not plate mail. It would then return 0, which would enable the game driver to call the command in the leather jacket that defines the wear verb. This function would accept the command, and execute some appropriate code, followed by a return of 1. Every time an object O comes in contact with a living object L then O will be asked to define commands. 3.1 Call of clean_up() The function clean_up() is automatically called now and then. When an object is loaded, it is checked for existence of a function clean_up(). If found, a flag O_WILL_CLEAN_UP is set. If an object hasn't been used (any function called) for a certain time and O_WILL_CLEAN_UP is set, then clean_up() is called. If this function returns a non-zero value, then O_WILL_CLEAN_UP is set again (which means that clean_up() can be called again). The idea of clean_up() is that objects can self-destruct, which is much more space effective than being swapped out. It will also work for cloned objects. It can be a good idea to define a default clean_up() in the much used room.c, which will destruct the room when it is empty. If a wizard wants to save important rooms, (s)he will have to redefine clean_up(). It is of course possible to do other types of cleaning than destruction. The administrator has to define time until clean up() is called in config.h. The time should be much longer than the time to reset(). [ Editor's note: I have no idea why this is. I tend to use a fairly short clean_up( time myself, to keep memory use down. ] 4 LPC reference manual The language used to program objects is called LPC. It is syntactically modelled after C. As it is important that objects be loadable "on the fly" in a game, I chose to make it an interpreted language. If it would be compiled for real, there would be big problems of portability when moving to different machines. The security of the program is also very important. Under no circumstances should an LPC programmer crash the game by doing a mistake. That rules out standard C. Several ideas has been borrowed from object oriented languages, like inheritance. However, as performance is very important, I have not hesitated to use "impure" language constructs when needed, which will conflict with the concepts of object oriented languages. An LPC programs consists several building blocks: - inheritance specifications - preprocessor - variables - functions 4.1 Types Declaration Types can be used at four places: 1. Declaring type of global variables. 2. Declaring type of functions. 3. Declaring type of arguments to functions. 4. Declaring type of local variables to functions. Normally, the type information is completely ignored, and can be regarded purely as documentation. However, when the basic type of a function is declared, then a more strict type checking will be enforced. That means that the type of all arguments must be defined. And, the variables can only be used to store values of the declared type. The function call_other is defined to return an unkown type, as the compiler can't know the type. This value must always be casted (when strict type checking is enabled). Casting a type is done by putting the type name inside a pair of parentheses. Note that casting in LPC is not the same as casting in C. It is only used as information for the compiler, and can only be used to cast values of type unknown. This type is only returned from call_other. An example when querying the short description of an object: (string)call_other(ob, "short"); When a function is compiled with strict type testing, it can only call other functions that are defined. If they are not yet defined, prototypes can be defined. string func(int arg); Note the ';' instead of a body to the function. All arguments must be given names, but do not have to have the same names as in the real definition. All types must of course be the same. [ Editor's note: this means you can do: string func(int arg); and then later string func(int x) { /* begin actual function */ be sure to keep the number of arguements and their types consistent. ] There is currently a bug (3.0.36) that recursive calls can not be done if the function is not also defined by a prototype. That is because a function is not really defined until the whole function has been compiled. Don't rely on this behaviour, which will hopefully soon be fixed. A dangerous effect is that it is possible to redefine efun's, and let the new definition call the old before it is replaced. Such code will break sooner or later. If an efun is to be redefined to get some new enhancements, always define the new one with a new name. There are two kinds of types. Basic types, and special types. There can be at most one basic type, but any number of special types. The strict type checking is only used by the compiler, not by the runtime. Hence, it is actually possible to store a number in a string variable even when strict type checking is enabled. Why use strict type checking? It is really recommended, because the compiler will find many errors at compile time, which will save a lot of hard work. It is in general much harder to trace an error occuring at run time. I recommend, that when a wizard is having problem with an object and wants help, that he first must make all functions have declared types. The basic types can be divided in to groups. Those that are referenced by value, and those that are referenced by address. The types int and string are always representing different entities. But the type object is a pointer to an object. If a value of this type is assigned to a variable or passed as argument, they will all point to the same object. The same goes for arrays. That means that if the value of an element in an array is changed, then it can modify all other variables pointing to the same array. Changing the size of the array will always allocate a new one, though. The comparation operator, ==, will compare the actual value for the group of types above. But for arrays and objects, it will simply check if it is the same object (or array). That has the very important implication that the expression `() == ()' will always evaluate to false becaus the array construction operator-pair, ( ) always generates a new array. [ Editor's note: not sure if this bit about arrays is still true. ] 4.1.1 Basic Types int An integer 32 bit number. object Pointer to an object. An object pointer can mainly be used for two things. Either giving as argument to functions, or used for calling functions defined by that object with its specific instance of variables. string An unlimited string of characters. A lot of operators are allowed for strings, like + and [] etc. mixed This type is special, in that it is valid to use in any context. Thus, if everything was declared mixed, then the compiler would never complain. This is of course not the idea. It is really only supposed to be used when a variable really is going to contain different types of values. This should be avoided if possible. It is not good coding practice, to allow a function for example to return different types. void This type is only usable for functions. It means that the function will not return any value. The compiler will complain (when type checking is enabled) if the return value is used. 4.1.2 Arrays Arrays are declared using a '*' with a basic type. For example, declaring an array of numbers: int *arr; Use the type mixed if you want an array of arrays, or a mixed combination of types. 4.1.3 Special Types There are some special types, which can be given before the basic type. These special types can also be combined. When using special type T before an inherit statement, all symbols defined by inheritance will also get the special type T. The only special case is public-defined symbols, which can not be redefined as private in a private inheritance statement. varargs A function of this type can be called with a variable number of arguments. Otherwise, the number of arguments is checked, and can generate an error. private Can be given for both functions and variables. Functions that are private in object A can not be called through call_other from another object. And, they are not accessible to any object that inherits A. static This special type behaves different for variables and functions. It is similar to private for functions, in that they can not be called from other objects. static variables will be neither saved nor restored when calling save_object() or restore_object(). public A function defined as public will always be accessible from other objects, even if private inheritance is used. nomask All symbols defined as nomask can not be redefined by inheritance. They can still be used and accessed as usual. 4.2 Access of data and programs in other objects There is a function call_other(), that can be used to call functions in other objects. All functions can be called except those declared static or private. See Section 4.7 [Predefined Functions] for more information. There is another syntax that will do the same thing: ob->func(args); This will call function func in object ob. It is a much better looking way to do it. There has been a lot of questions why this syntax hasn't been used to allow for accessing variables in other objects. There are some good reasons for that. - It conflicts with the idea of programming in an object-oriented way. - It makes the programming less structured, as there are more dependencies. - If a variable name is changed, code can be broken. - Sometimes, you don't even want to keep the variable at all any longer. 4.3 Statements 4.3.1 If 4.3.2 Block 4.3.3 While 4.3.4 Do - While 4.3.6 Return 4.4 Expressions 4.5 Saving and Restoring Objects 4.6 Inheritance [ As yet, this is undocumented. ] 4.7 Predefined Functions There are two kinds of predefined functions: efun The functions hard coded , which are defined by the game driver. They can be redefined by a local function of the same name, which will then be used instead. lfun Functions that optionally can be defined by the objects. These functions will be called by other lfuns, and sometimes by the game driver. They will control how the object will behave in special situations. An example is get(), which if defined and returning 1, will enable the object to be picked up by players. If returning 0, then the player will get a message that says that the object can't be picked up. 4.7.1 Efuns [ What follows is a listing of most or all of the efuns. I have removed the section numbering on them, because when new functions are added, it is easier for me to put them in if I don't have to redo the numbering. ] ---- add_action void add_action(string fun, string cmd, int flag) Set up a local function fun to be called when user input matches the command cmd. Functions called by a player command will get the arguments as a string. It must then return 0 if it was the wrong command, otherwise 1. If it was the wrong command, the parser will continue searching for another command, until one returns true or give error message to player. For example, there can be a wand and a rod. Both of these objects defines add_verb("wave"). One of them will be randomly called first, and it must look at the argument, and match against "wand" or "rod" respectively. If second argument, cmd, is not given, it must be given by add_verb(). Support of add_verb() is of historical reasons. Always have add_action() called only from an init() routine. The object that defines commands must be present to the player, either being the player, being carried by the player, being the room around the player, or being an object in the same room as the player. If argument flag is 1, then only the leading characters of the command has to match the verb cmd. Never define an action that will call the function exit(), because it is a special function. [ Editor's note: I believe this is called when leaving a room. ] See also: query_verb, add_verb, lfun/init, lfun/exit. ----- add_verb void add_verb(string str) This function is connected to the add_action() function. It will set up the command str to trigger a call to the function set up by the previous call to add_action(). This function is now obsolete as the verb can be given directly with add_action(). add_verb() remains for compatibility. See also: add_action, query_verb. ----- all_inventory object *all_inventory(object ob) Returns an array of the objects contained in the inventory of ob. See also: first_inventory, next_inventory. ----- allocate allocate(int size) Allocate an array of size elements. The number of elements must be >= 0 and not bigger than a system maximum (usually 1000). See also: sizeof. ----- call_other unknown call_other(object ob, string str, mixed arg) Call function in another object with an argument. The return value is returned from the other object. See also: present, find_living. ----- call_out void call_out(string fun, int delay, mixed arg) Set up a call of function fun in this_object(). The call will take place in delay seconds, with the argument arg provided. arg can be of any type. Please note that you can't rely on `write' or `say' in the fun called since this_player() is set to 0. Use tell_object() instead. [ Editor's note: This has now been fixed. "this_player()" now carries through the call_out(). ] See also: remove_call_out, call_out_info. ----- call_out_info mixed *call_out_info() Get information about all pending call outs. An array is returned, where every item in the array consists 4 elements: 1. The object 2. The function 3. The delay to go 4. The optional argument See also: call_out, remove_call_out. ----- capitalize string capitalize(string str) Convert the first character in str to upper case, and return the new string. ----- cat int cat(string path, int start, int num) List the file found at path. It is not legal to have '..' or spaces in the path. This function is normally connected to the `cat' command that wizards have. It is also used by the `help' command. The optional arguments start and num makes is start line number, and number of lines. If they are not given, the whole file is printed from the beginning. The total number lines will not exceed a system limit, which normally is 40 lines. cat() returns number of lines read and printed if success, 0 if no such file or no lines to read. See also: ls, file_size. ----- catch mixed catch(string expr) Evaluate expr. If there is no error, 0 is returned. If there is a standard error, a string (with a leading '*') will be returned. The function throw(value) can also be used to immediately return any value, except 0. The catch() is somewhat costly, and should not be used anywhere. Rather, use it at places where an error would destroy consistency. ----- clear_bit string clear_bit(string str, int n) Return the new string where bit n is cleared in string str. Note that the old string str is not modified. See also: set_bit, test_bit. ----- clone_object object clone_object(string name) Load a new object from definition name, and give it a new unique name. Return the new object. The original used for cloning, should not be used in the game, only used for cloning. [ Editor's note: if the original copy has a locatio, you will get an error, *cloning bad object. ] See also: destruct, move_object. ----- command int command(string str) Execute str as a command given directly by the player. Any effects of the command will apply to the current object. There was a second argument, which is not supported any longer. Return value is 1 or 0, for success or failure. Return value is 0 for failure. Otherwise, a numeric value is returned, which tells the evaluation cost. Bigger number means higher cost. The evaluation cost is approximately the number of of machine code instructions executed. See also: enable_commands. ----- create_wizard string create_wizard(string name) string create_wizard(string name, string domain) In the first form, with only name given as argument, create_wizard() makes a directory for the wizard with the name name. It also creates the files `castle.c' and `workroom.c' in the new directory. The new directory is called `PLAYER_DIR/name', where PLAYER_DIR is a define in the game driver and name is the name of the wizard. The second form is used for adding a wizard to a domain, and expects the argument domain to contain the name of the domain that the wizard name is joining. The difference from the first form is that the directory is placed in `DOMAIN_DIR/domain/name', where DOMAIN_DIR is a define in the game driver, domain is the name of the domain and name is the name of the wizard. Also, a symbolic link is created in PLAYER_DIR pointing at the new directory. It returns the name of the new castle. In case of error, false is returned. ----- creator string creator(object ob) Return as a string the name of the wizard that created object ob. If the object was not created by a wizard, 0 is returned. This function is no longer supported (except in -o mode). ----- crypt string crypt(string str, string seed); Crypt the string str using two characters from seed as a seed. If seed is 0, then random seed is used. The result has the first two characters as the seed. ----- ctime string ctime(int clock) Give a nice string with current date and time, with the argument clock that is the number of seconds since 1970. See also: time. ----- destruct void destruct(object ob) Completely destroy and remove object ob. The argument can also be a string. After the call to destruct(), no global variables will exist any longer, only local, and arguments. If an object self-destructs, it will immediately terminate execution and return 0. There is one exception: If the destruct-statement is followed by a `return 1;' immediately after, then this return statement will be executed. This should NOT be used on normal objects in the game, instead use the lfun remove() in the object you want removed: `ob->remove();'. This will ensure correct update of weights, volumes etc. See also: clone_object. ----- ed void ed(string file); void ed(string file, string func); This is a funny function. It will start a local editor on an optional file. This editor is almost ed compatible. If a second argument is given, then a function with that name will be called when the user exits the editor. ----- enable_commands void enable_commands(); Enable this object to use commands normally accessible to players. This also marks the current object as living. Commands defined by `player.c' will not be accessible, of course. This function must be called if the object is supposed to interact with other players. Avoid calling this function from other places then reset(), because the command_giver will be set to the this_object(). See also: command, living. ----- environment object environment(object obj) Return the surrounding object to obj. If no argument is giving, it returns the surrounding to the current object. The object will dissapear silently without any sign. See also: find_first_inventory, this_player, this_object. ----- explode string *explode(string str, string del) Return an array of strings, created when the string str is splitted into substrings as divided by del. The str must end with del if the last part is wanted too. Example: explode(str, " ") will split the string str into an array of words as separated by spaces in the original string. The array is returned. See also: sscanf, extract. ----- export_uid int export_uid(object ob) Set the uid of object ob to this_object's effective uid. It is only possible when object ob has an effective uid of 0. See also: seteuid, getuid. ----- extract string extract(string str, int from, int to) Extract a substring from a string. Character 0 is first character. `extract(str, n)' will return a substring from characer number n to the end. `extract(str, i, j)' will return a string from character i to character j. See also: sscanf, explode. ----- file_name string file_name(object ob) Get the file name of an object. If the object is a cloned object, then it will not have any corresponding file name, but rather a new name based on the original file name. Example: `find_object(file_name(ob)) == ob' is guaranteed to be true for all objects ob. [ Editor's note: the new name, when it is a cloned object, will be the file name of the object, a #, and the object number... so, a player might be "/obj/player#38". ] ----- file_size int file_size(string file) Give the size of a file. Size -1 indicates that the file either does not exist, or that it is not readable by you. Size -2 indicates that it is a directory. See also: save_object, load_object, write_file, cat. ----- filter_objects mixed *filter_objects(mixed *arr, string fun, object ob, mixed extra) Returns an array holding the items of arr filtered through `ob->fun()'. The function fun in ob is called for each element in arr with that element as parameter. A second parameter extra is sent in each call if given. If `ob->fun(arr[.index.], extra)' returns 1 the element is included in the returned array. If arr is not an array, then 0 will be returned. ----- find_call_out int find_call_out(string func) Find the first call out due to be executed for function func, and return the time left. If it is not found, then return -1. See also: efun/call_out, efun/remove_call_out. ----- find_living object find_living(string str) Find first `living' object that answers to the id str (by calling local id()). A living object is an object that has done enable_commands(). The object must have set a name with set_living_name(). There is a special hash table that speeds up the search for living objects. See also: find_player, enable_commands, set_living_name. [ Editor's note: it seems actually to find the name set with set_living_name() rather than the id. These are usually set to the same string though. ] ----- find_object object find_object(string str) Find an object with the file name str. If the file isn't loaded, it will not be found. ----- find_player object find_player(string str) Find a player with the name str. The string must be lowercase. Players are found even if they are invisible or link dead. Monsters are not found. This function uses the name that was set by set_living_name(). This is done automatically in the player object. See also: find_living, set_living_name. ----- first_inventory object first_inventory(mixed ob) Get the first object in the inventory of ob, where ob is either an object or the file name of an object. See also: next_inventory, all_inventory. ----- function_exists string function_exists(string str, object ob) Return the file name of the object that defines the function str in object ob. The returned value can be other than `file_name(ob)' if the function is defined by an inherited object. 0 is returned if the function was not defined. ----- getuid string getuid(object ob) Get the name of the wizard that is set to the user of this object. That name is also the name used in the wizlist. See also: geteuid, seteuid, and export_euid. ----- geteuid string geteuid(object ob) Get the effective user identification of the object ob. The effective user id is often used to determine permissions. See also: getuid, seteuid, and export_euid. ----- implode string implode(mixed *arr, string del) Concatenate all strings found in array arr, with the string del between each element. Only strings are used from the array. See also: explode. ----- input_to void input_to(string fun, int flag) Enable next line of user input to be sent to the local function fun as an argument. The input line will not be parsed. Note that fun is not called immediately. It will not be called until the current execution has terminated, and the player has given a new command. If input_to() is called more than once in the same execution, only the first call has any effect. If optional argument flag is non-zero, the line given by the player will not be echoed, and is not seen if snooped. See also: call_other, sscanf. ----- interactive int interactive(object ob) Return non-zero if ob is an interactive player. 0 will be returned if he is link dead. See also: query_ip_number, query_ip_name. ----- intp int intp(mixed arg) Return 1 if arg is an integer number. See also: stringp, pointerp, objectp. ----- living int living(object ob) Return true if ob is a living object (that is, enable_commands() has been called by ob). ----- log_file void log_file(string file, string message) Append a message to a log file. All log files are in the directory `lib/log'. `/log' is automatically prepended to the file name. See also: write_file. ----- lower_case string lower_case(string str) Convert the all characters in str to lower case, and return the new string. See also: capitalize. ----- ls void ls(string path) List files in an optional path. It is not allowed to use '.' or space in the path. This function is normally connected to the `ls' command. This function is also obsolete in native mode. See also: cat, get_dir. ----- map_array mixed *map_array(mixed *arr, string fun, object ob, mixed extra) Returns an array holding the items of arr mapped through `ob->fun()'. The function fun in ob is called for each element in arr with that element as parameter. A second parameter extra is sent in each call if given. Principal function: `foreach (index) arr[index] = ob->fun(arr[index],extra);' The value returned by `ob->fun(arr[.index.], extra)' replaces the existing element in the array. If arr is not an array, then 0 will be returned. ----- member_array int member_array(mixed item, mixed *arr) Returns the index of the first occurence of item in array arr. If not found, then -1 is returned. ----- mkdir int mkdir(string path) Make a directory named path. Return 1 for success and 0 for failure. See also: rmdir, rm ----- move_object void move_object(mixed item, mixed dest) Move the object item to the object dest. Currently, both arguments can be strings. Usually, transfer() should be used instead of move_object(). In native mode, move_object() can only be called from the object being moved. See also: transfer, first_inventory, this_object, this_player. ----- next_inventory object next_inventory(object ob) Get next object in the same inventory as ob. Warning: If the object ob is moved by move_object(), then next_inventory() will return an object from the new inventory. See also: first_inventory, all_inventory. ----- notify_fail void notify_fail(string str) Store str as the error message given instead of the default message `What ?'. If notify_fail() is called more than once, only the last call of will be used. The idea of this function is to give better error messages instead of simply `What ?'. ----- objectp int objectp(mixed arg) Return 1 if arg is an object. See also: intp, stringp, pointerp. ----- parse_command int parse_command(string str, object source, string pattern, var1, var2 ...) Parses commands given in str against the pattern in pattern and returns 1 if it matches. source is either an object or an array of objects. This is essentially a 'hotted' sscanf and it has a similar syntax, although parse_command works on word basis where sscanf works on character basis. str Given command. source source is either an object or an array of objects. array array holding the accessible objects object object from which to recurse and create the list of accessible objects, normally ob = environment(this_player()) pattern Parse pattern as list of words and formats: word obligatory text (One word) [word] optional text (One word) / Alternative marker %o Single item, object %l Single living object %s Any text (multiple words) %w Any word %p Preposition %i Any items %d Number 0- or tx(0-99) Example string: " 'get' / 'take' %i " Items as in %o and %i be can on many forms. Some examples: apple, two apples, twentyfirst apple apples, all apples, all green apples, all green ones varN This is the list of result variables as in sscanf. One variable is needed for each %_ The return types of different %_ are: %o Returns an object %l Returns an object %s Returns a string of words %w Returns a string of one word %p Can on entry hold a list of word in array or an empty variable Returns: if empty variable: a string if array: array[0]=matched word %i Returns a special array on the form: [0] = (int) given numeric prefix =0: all or a pluralform given >0: numeral given: two, three, four... <0: order given: second, third ... [1..n] (object) Objectpointers A list of the POSSIBLE objects that can match the given %i. No choosing of third or such. %d Returns a number Example: a=parse_command("take apple",environment(this_player()), " 'get' / 'take' %i ", items); [ Editor's note: That example didn't help much, did it? ] ----- people void people() A function that will list all interactive players, and some info about them. This function is normally connected to the people command, that wizards have. THIS FUNCTION IS OBSOLETE. LOOK AT users() INSTEAD. ----- pointerp int pointerp(mixed arg) Return 1 if arg is a string. See also: intp, stringp, objectp. ----- present object present(mixed str, object ob) If an object that identifies to the name str is present, then return it. str can also be an object, in which case the test is much faster and easier. The object is searched for in the inventory of the current object, and in the inventory of the environment of the current object. A second optional argument ob is the enviroment where the search for the str is done. Normally this_player() is a good environment. See also: move_object, environment. ----- previous_object object previous_object() Returns an object pointer to the object that did a call_other() to the current object, if any. There is one exception, and that is doing call_other() to this_object(), which will not change the value of previous_object(). See also: call_other. ----- query_idle int query_idle(object ob) Query how many seconds idle a player object has been. This will generate an error if called on a non-interactive object. ----- query_ip_name string query_ip_name(object ob) Give the ip-name for player ob. An asynchronous process `hname' is used to find out this name in parallell. If there are any failures to find the ip-name, then the ip-number is returned instead. See also: query_ip_number. ----- query_ip_number string query_ip_number(object ob) Give the ip-number for player ob. See also: query_ip_name. ----- query_verb string query_verb() Give the name of the current command, or 0 if not executing from a command. This enables add_action() of several commands to the same function. See also: add_action. ----- random int random(int n) Return a number in the random range [0 .. n-1]. ----- regexp string *regexp(string *list, string pattern); Match the pattern pattern against all strings in list, and return a new array with all strings that matched. ----- remove_call_out int remove_call_out(string fun) Remove next pending call out for function fun in this object. The time left is returned. -1 is returned if there were no call out pending to this function. See also: call_out, call_out_info. ----- rename int rename(string from, string to) The efun rename will move `from' to the new name `to'. If `from' is a file, then `to' may be either a file or a directory. If `from' is a directory, then `to' has to be a directory. If `to' exists and is a directory, then `from' will be placed in that directory and keep its original name. It is only possible to change name of a directory within a directory on machines running System V, i.e it is not possible to move it to another directory. It is not possible to move a directory across filesystems on any system. On successful completion rename will return 0. If any error occurs 1 is returned. ----- restore_object int restore_object(string name) Restore values of variables for current object from file name. It is illegal to have '.' or spaces in the name. Return true if success. Variables that has the type modifer `static' will not be saved. Example: `static int xxx;'. If inheritance is used, then it might be possible that a variable will exist with the same name in more than one place. When restoring, only one of these variables will be restored if encountered in the save file. A good practice is to have verbose and unique names on non-static variables, which also will make it easier to read or patch the save file manually. See also: save_object. ----- rm int rm(string file) Remove file file. Returns 0 for failure and 1 for success. See also: mkdir, rmdir. ----- rmdir void rmdir(string dir) Remove directory dir. See also: rm, mkdir. ----- save_object void save_object(string name) Save values of variables of this object in the file name. It is illegal to have '.' or space in the field name. Wizards that call this function can only save to files in their own directories. Object pointers are stored as the number '0'. Variables that has the type modifier 'static' will not be saved. Example: `static int xxx;'. See also: restore_object. ----- say void say(string str) void say(string str, object obj) Send a message str to all players in the same object (room). This function is also used by the `say' command. If the message depends on the reciever an array of two messages or a message containing words intended for 'value by function call' can be used. If a second argument obj is specified, messages is sent to all except obj. If obj is not an object, but an array of objects, all those objects are excluded, they do not get the message. This commands behaves differently if called from a heart_beat(), or otherwise. When called from a heart_beat(), the message will reach all players in the same environment of the object that calls say(). See also: write, shout, tell. ----- set_bit string set_bit(string str, int n) Return the new string where bit n is set in string str. Note that the old string str is not modified. The max value of n is limited. Ask the administrator if you want to know the maximum value. The new string will automatically be extended if needed. Bits are packed 6 per byte in printable strings. See also: clear_bit, test_bit. ----- set_heart_beat int set_heart_beat(int flag) Enable or disable heart beat. If the heart beat is not needed for the moment, then done disable it. This will reduce system overhead. Return true for success, and false for failure. Specifically, it will fail if the heart beat function has been disabled, which it will be if there is a run time error in it. See also: lfun/heart_beat. ----- set_light int set_light(int n) An object is by default dark. It can be set to not dark by calling `set_light(1)'. The environment will the also get this light. The returned value is the total number of lights in this room. Note that the value of the argument is added to the light of the current argument! ----- set_living_name void set_living_name(string name) Set a living name on an object that must be living. When this is done, the object can be found with find_living(). An object can only have one name that can be searched for with find_living(). See also: find_living, find_player. ----- seteuid int seteuid(string str) Set effective uid to str. It is not possible to set it to any string. It can always be set to getuid(), the creator of the file for this object or 0. When this value is 0, then current objects uid can be changed by export_uid(), and only then. But, when the value is 0, no objects can be loaded or cloned by this object. See also: export_uid, getuid. ----- shout void shout(string str) Send a string str to all players. This function is also used by the sampshout command. [ Editor's note: This function is not to be used lightly, as many find it highly annoying. ] See also: write, tell_object, say. ----- sizeof int sizeof(mixed arr) Return the number of arguments of an array arr. If arr is not an array, then '0' is returned. See also: allocate. ----- slice_array mixed *slice_array(mixed *arr, int from, int to) Returns an array that is a slice of the array arr from the index from to the index to. Indexes are numbered beginning with 0. If arr is not an array or indexes are outside the limits of arr, then 0 will be returned. Note also that you can use the operator `+' on arrays. THIS IS NOW OBSOLETE. YOU CAN NOW RETURN RANGES OF AN ARRAY. ----- sscanf int sscanf(string str, string fmt, mixed var1, mixed var2 ...) Parse a string str using the format fmt. fmt can contain strings separated by "%d" and "%s". Every "%d" and "%s" corresponds to one of var1, var2... "%d" will give a number, and "%s" will give a string. The number of matched "%d" and "%s" is returned. See also: extract, explode. ----- stringp int stringp(mixed arg) Return 1 if arg is a string. See also: intp, pointerp, objectp. ----- tell_object void tell_object(object ob, string str) Send a message str to object ob. If it is an interactive object (a player), then the message will go to him, otherwise it will go to the local function catch_tell(). See also: write, shout, say. ----- tell_room void tell_room(mixed ob, string str) Send a message str to object all objects in the room ob. ob can also be the name of the room (string). If the message depends on the reciever an array of two messages or a message containing words intended for 'value by function call' can be used. See also: write, shout, say, tell_object. ----- test_bit int test_bit(string str, int n) Return 0 or 1 of bit n was set in string str. See also: set_bit, clear_bit. ----- this_object object this_object() Return the object pointer of this object. This is not to be confused with the internal name of an object, which is used by the id() function. See also: this_player. ----- this_player object this_player() Return the object representing the current player. See also: this_object. ----- time int time() Return number of seconds since 1970. See also: ctime. ----- trace int trace(int traceflags) Sets the trace flags and returns the old trace flags. When tracing is on a lot of information is printed during execution. The trace bits are: 1 Trace all function calls to lfuns. 2 Trace all calls to call_other. 4 Trace all function returns. 8 Print arguments at function calls and return values. 16 Print all executed stack machine instructions (produces a lot of output!). 32 Enable trace in heart beat functions. 64 Trace calls to apply. 128 Show object name in tracing. ----- traceprefix string traceprefix(string prefix) If the the traceprefix is set (i.e. not 0) tracing will only occur in objects having a name with the set prefix. ----- unique_array mixed unique_array(object *obarr, string separator) Groups objects together for which the separator function returns the same value. obarr should be an array of objects, other types are ignored. The separator function is called only once in each object in obarr. The return value is an array of arrays of objects on the form: ({ (-Same1:1, Same1:2, Same1:3, .... Same1:N "), (-Same2:1, Same2:2, Same2:3, .... Same2:N "), (-Same3:1, Same3:2, Same3:3, .... Same3:N "), .... .... (-SameM:1, SameM:2, SameM:3, .... SameM:N "), }) ----- users object *users() Return an array of objects, containing all interactive players. ----- write void write(mixed str) Write a message str to current player. str can also be a number, which will be translated to a string. See also: say, tell_object, shout. ----- write_file int write_file(string file, string str) Append the string str into the file file. Returns 0 or 1 for failure or success. See also: file_size, cat, log_file. ----- 4.7.2 Lfuns ----- move int move(object dest) Move the object to the object dest. All kinds of tests are done, and a number is returned specifying the result: 0: Success. 1: To heavy for destination. 2: Can't be dropped. 3: Can't take it out of it's container. 4: The object can't be inserted into bags etc. 5: The destination doesn't allow insertions of objects. 6: The object can't be picked up. If an object is transfered to a newly created object, make sure that the new object first is moved to it's destination. ----- Shadow object shadow(object ob, int flag) If flag is 1, then current object will shadow ob. If flag is 0, then either 0 will be returned, or the object that is the shadow for ob. An object that defines the funtion query_prevent_shadow() to return 1 can't be shadowed, and the shadow() function will return 0 instead of ob. If an object A shadows an object B, then all call_other() to B will be redirected to A. If object A has not defined the function, then the call will be passed on to B. There is only one object that can call functions in B with ncall_other(), and that is A. Not even object B can call_other() itself. All normal (internal) function calls inside B will however remain internal to B. There are two ways to remove the shadow. Either destruct it, or the object that was shadowed. In the latter case, the shadow will also be destructed automatically. The result is that it is possible to hide an object behind another one, but everything can be totally transparent. ----- 4.8 Compilation Errors [ Editors's note: he didn't do anything here. ] ----- 4.9 Simulated efuns There is a mechanism to simulate efuns. All simulated efuns have to be defined in a special file (which can be anywhere). The function 'string get_simul_efun()' has to be defined in master.c to return the name of this file, as well as loading it. If this function returns 0 or is non-existing, then no automatic simulation of efuns will take place. When compiling an object and a function call is found that has not been defined locally, then it is either an efun or an undefined function. If this function is defined in the file of simulated efuns, then there will be a call_other set up to this function. That means that the function will behave as if it was an efun. The type result of the call_other does not have to be casted, but will automatically be set by the compiler. This file of simulated efuns are examined by the game driver at startup of the game. All functions and the types of them are stored then to speed up later references. This means that it is possible to modify this file and reload it. But, changing the number of functions or the type definitions of them will not affect the compiler. The idea of these simulated efuns are several. One is that it is now possible to do major changes (and even removals) of efuns, to be replaced by a simulated efun. A function declared as static will never be called automatically. Chapter 5: The LPC Implementation The language is defined by two files. `lex.c' defines the lexical elemements and takes care of preprocessor directives. `lang.y' defines the grammar. [ note: unfinised. ] 5.1 The Virtual Stack Machine [ note: also unfinished ] 5.2 How to Add Your Own Functions All predefined functions callable by the object must return exactly one result on the stack, even if they are defined as void functions. The compiler assumes that there always is one resulting value. The functions that returns the void value, might as well return anything, as it won't be used (or at least is undefined). That means that I usually return the first argument, which speeds things up as I don't have to pop and push unnecessarily. Many 'stack instructions' exists only to be called by the compiler. Like 'pop', which obviously must not return a value on the stack. But, all those instructions are only generated explicitely by the compiler, which knows what it does. If you want to add a new function of you own, you will have to change: - lang.y: Define a new name 'F_XXX'. Add it last in the list of '%token', because the Makefile has not been instructed to recompile every file depending on the order of the F_ definitions. - lex.c: Add a line to 'predefs', with information about the instruction. Functions that only allow a constant number of arguments are best, as the compiler always knows how many arguments there is, and won't generated code information about that. - interpret.c: Add a case statement in eval_instruction(). If the types of the arguments were specified, and only one type allowed, then you will not have to check the types, but can assume they are correct. If different types are allowed, then they will have to be checked. Also, if the number of arguments are constant, then you can assume they are correct. Otherwise, the variable num_var will tell you the actual number of arguments. [ Well, that's all for today, kids... I realize that there's still a lot to be done as far as writing documentation here... I can only hope that more will be written and shared. If you should write anything that fills in the empty spaces, please send me a copy, at adam@dogstar.colorado.edu --Adam / Buddha ]