The Foundation II LPC Library Foundation II Basics written by Descartes of Borg 950421 This document serves as an introduction to the Foundation II LPC Library. The Foundation II LPC Library is designed to be a sound base from which to develop a highly customized LPC library. There are no preconceptions about what type of MUD you will be building with this library, and, as a result, many things present in traditional libraries such as combat systems, skills, magic, weapons, etc are missing. Since this library is not designed for people to be able immediately to open their own MUD, it does require some LPC skill that others might not. It is imperative that you know all of the subject matter covered in the LPC Basics and Intermediate LPC textbooks. I. The Master Object and Simul Efun Object The MudOS driver requires only two objects to exist in the mudlib: the master object and the simul efun object. The file names do not matter so long as they are specified in the MudOS configuration file. The content of the simul efun object does not matter either, as it can be an empty file. The master object simply needs to have the function connect() defined in it in order to accept connections. For the Foundation II LPC Library, the master object can be found in /secure/daemon/master.c and the simul efun object in /secure/sefun/sefun.c. The driver uses the master object as a sort of interface between the driver and mudlib. By calling functions in the master object, the driver can allow the mudlib to make important decisions about such things as security, sockets, shadows, and so on. The simul efun object, on the other hand, lets the mudlib define its own efuns. Remember that efuns are global functions compiled into the driver. They are written in C, and therefore it is not possible to modify them from the mudlib level. Functions in the simul efun object are treated much like efuns, but you can modify and add to them on the fly since they are part of the mudlib. As a matter of fact, if you have a simul efun which is particularly nasty on the CPU, you can use MudOS' LPC->C feature to compile it to C and make it an efun. An important thing to remember about simul efuns is that the object which called the simul efun is considered the previous_object(). Therefore, another way of looking at a simul efun is as if it were written ob_simul_efun->sefun_call(). In addition, you do not want to make any simul efun calls from the master object so that it can remain independent of the simul efun object in the event you change the simul efun object and make an error. With the Foundation II LPC Library, the simul efun object consists of a header file, /secure/sefun/sefun.h, which has prototype information for all simul efuns. This header file allows you to call simul efuns from simul efuns without a danger of causing the simul efun object not to load. In addition to the header file are a bunch of modular LPC files defining the code to groups of related simul efuns. This allows you to write and test a new simul efun and know that it works before trying to use it in the simul efun object. Finally, the simul efun object itself, /secure/sefun/sefun.c, consists of #include's of all those modular files. The sefun object also has some LPC code in it for something called efun overrides. An efun override is where you redefine the behaviour of a MudOS efun. The Foundation II master object only allows the simul efun object to perform efun overrides. II. Daemons The Foundation II LPC Library distinguishes among three types of objects: daemons, tangiable objects, and shared objects. Tangiable objects are objects creators most often deal with. They are things you clone. They have environment and inventories and can move around. In addition to tangible objects, creators often deal with shared objects. Shared objects are things like rooms and doors which do not move around, are never cloned, and uniquely serve as references which can be viewed from many different points of view. For example, a room may be shared by four other rooms, all of which exit to it. And doors are often shared between two rooms between which it exists. The final object type, daemons, are most often handled at the mudlib level. A daemon has no inventory, no environment, and it never moves around. In fact it is much like a shared object, except in that shared objects represent actual objects in the MUD environment (in other words, a door in fact represents a door). A daemon, however, represents a common data set which may be shared by many objects across the MUD. For example, the Foundation II command daemon keeps a list of all commands and where they are stored so that any object which needs this information can easily grab it. Without that daemon, you would either have to store all of that information in every single object which needed it (nasty waste of RAM) or you have each object that needs that data recalculate it every time it needs it (very nasty on the CPU for something as common as issuing a command). The Foundation II LPC Library stores daemons in /daemon or /secure/daemon depending on what sort of access or protection the daemon requires. Things which need no access, like the command daemon, are kept in /daemon, while things which require high security, like the postal daemons are in /secure/daemon. III. Library Objects The Foundation II LPC Library was designed to make wide and efficient use of object oriented principles in order to take full advantage of the benefits of the object oriented nature of LPC. In addition, things were designed with the thought in mind that users of the mudlib will want to customize it. One reason such plug and play is possible is due to the event driven nature of Foundation II. In traditional combat systems, including the old Foundation system, combat is proceedural. This basically means you call a function to determine what happens in a combat round. In an event driver system, everything which happens is broken down into distinct happenings called events. For example, in the old Nightmare system, it would be very difficult to do something like create a shield of reversal which turns all damage back onto the attacker. What used to happen was simply that a player had a combat round during which the combat proceedures figured out what weapon class was being wielded, what armour class was being worn by the enemy, and what the difference is. Now that is overly simplistic, but it does illustrate how difficult it would be to turn that attack around on the attacker. In an event driven system, a player object is at each step presented with something they are doing or something being done to them. This gives them a chance to respond by to events which happen to them by in turn initiating their own chain of events. In the above example, a player object receives a ReceiveDamage event. Instead of taking the damage, the player object can instead turn around and turn that damage on the agent doing the damage. For more details on each system of events, read the documentation on each system (for example, the Combat document). Foundation II library objects are therefore broken down into several classes of functions: 1. driver applies Functions which get called by the driver for various reasons. 2. command functions Functions which get called by the driver when a command is executed, normally referenced by an add_action() call. 3. modal functions True or false functions which determine if an object is capable of doing something. This allows you to determine if something is possible without actually trying to do it. 4. events functions handling standard Foundation II events. 5. data functions Also known as Set*() and Get*() functions. These allow for data manipluation and retrieval by external objects. All Foundation II objects have header files which contain the prototypes for all functions defined in the object in question. An easy way to search for the existence of a given function is to do a 'grep' through all the header files. III. Inheritance Structre All Foundation II LPC Library objects inherit either directly or indirectly /lib/clean.c. Directly, only /lib/daemon.c and /lib/object.c should ever inherit /lib/clean.c. All other objects should at some point inherit object.c or daemon.c, where object.c is the root object for tangiable objects and daemon.c for daemon objects. Shared objects may end up inheriting either, but should always at some point inherit one or the other. It is beyond the scope of this document to detail the inheritance structure, since IMHO the only useful way to do it is graphically. Towards this end, point your web browser to: http://ie.imaginary.com:7885/libraries/Foundation/inheritance.html II. Commands There are three type of commands in the Foundation II LPC Library which get searched in the following order: 1) cached commands 2) add action commands 3) system commands Cached commands are secure or common commands which get executed directly from the MudOS process_input() driver apply. For example, a password command can be nasty if you allow at any point someone to add action it. Since a nasty cre could write their own password command to trap your password, you would have a security leak. Cached commands cannot be overridden through any other type of commands, and thus avoid this security problem. In addition, commands such as movement commands are the most common commands used on the MUD, and they can be quite intensive CPU-wise. Given that the MudOS switch() construct is very fast, it makes sense to cache the "go" command inside the player object. Add action commands are the most common thing creators deal with. An add action command is one added through the MudOS add_action() efun. These type of commands are rarely dealt with at the mudlib level. As far as customizing the mudlib goes, you should pretty much be dealing exclusively through system commands, which are technically a subset of add action commands. Monsters, players, and creators all inherit an object called /lib/command.c. In that object, an add action command is created which basically intercepts any command issued that has not been executed through a cache command or other add action command. This command looks at what the name of the command you typed was, checks to see if the file /daemon/command.c knows of a command by that name, executes it if it exists, otherwise checks to see if a soul command by that name exists, executing it if it exists, otherwise returning 0. System commands are written inside command daemons. The Foundation II LPC Library keeps command daemons in two set of directories: /cmds and /secure/cmds. A command daemon naturally inherits /lib/daemon (LIB_DAEMON) and consists of at least two functions: mixed cmd(string args); void help(); The function cmd() is the function which gets executed for the command. You put in it whatever code should be executed when a player types the command in question. If that command succeeds, you return 1. Unlike add action commands, however, you do not return 0 on failure. You instead return a string. If you are familiar with the concept of notify_fail(), this is the string you might usually put in the notfy fail is what you return. In other words, the string you return is the error message a player should see if no other command ends up matching the command they issued. The help() function gets called by the help daemon whenever anyone uses the help command to get help on the function. Almost every help() function looks like this: void help() { message("help", "Syntax: <syntax string>\n\n" "Help message here.\n\n" "See also: whatever", this_player()); } V. The World Wide Web There is not a hell of a lot to say here, as most of doing the world wide web stuff involves learning html. It is an easy thing to learn, but others have documented it over and over much better than I could here. The Foundation II LPC Library setup consists of the http daemon in /daemon/http.c, the gateway objects in /www/gateways, and the html files in the /www hierarchy. You need no specific files other than index.html, which is the basic started html file. Descartes of Borg borg@imaginary.com