PDIRT DOCUMENTATION Compiled by Marty ------------------------------------------------------------------------------ TABLE OF CONTENTS Chapter 0: Introduction Chapter 1: MUD Driver Overview Chapter 2: Special Events Driver Chapter 3: The input Parser Chapter 4: The Automated Transport system. Chapter 5: Zones. Chapter 6: Pdirt Installation. Chapter 7: Configuring Daemon. Chapter 8: The Generator APPENDICES Appendix A: Maintaining the MUD. Appendix B: pDirt scripts. Appendix C: Coding Styles. Appendix D: Global Variables. CHAPTER 0: INTRODUCTION ------------------------------ I have compiled this document out of already exsisting documentation (most written by me), because the original Aber code had no documentation whatsoever. I hope I will set a good example for all the other coders out there who like to supply code without telling how it works... I hope this document will help other users of the pdirt system understand what it is, and how it works, so they can start producing great new worlds for players to explore. Because I think that abers look alike because only a handful of Gods out there know the code the way it should be known. I probably ain't one of them, but at least I'm trying... CHAPTER 1: MUD DRIVER OVERVIEW ------------------------------ This is an attempt of me (Marty) to make this code more documentated. Because almost everyone agrees that it should be more documentated, but no one does something about it. So this is a futile attempt of me to give some explenation on how the system works (a little). I didnt wrote the code so I could be mistaken here and there.. just so you know. WHERE YOU CAN FIND STUFF Type definitions: mudtypes.h types.h and some other header files Daemon setup routines: main.c Socket Setup routines: s_socket.c Login routines: mud.c Command parser: parse.c Message sending: sendsys.c, communicate.c and bprintf.c Time code: timing.c Player database: uaf.c (User Access File?) (For an almost complete list of files in the pdirt distribution see Appendix A (table A.1)) GLOBAL FUNCTIONING The driver handles all players that log in to the game. Unlike the old versions of abers which started a seperate process for every player. The players data are held in two structures. There is the U_BLOCK struct and the PLAYER_REC. The driver waits for a message on its main socket (6700) and the searches a free slot in the PLAYER_REC. If none is found the player will get a message and then be disconnected. If there is a slot it will start the login procedure. It will check the host, the name etc. Once the player has typed in his name it will check the player database for if that name exsisted. If so it will load that data, otherwise it will create a new player. Every player gets a seperate socket which you can see as a file from which you can or cant read (if you can, it means the player typed a command) Every command the player types is handled by a command input handler. For every step in the login procedure there is a different input handler, there is one input handler that handles in-game commands, and some others for various things (example: pager). The one that handles in-game commands is called gamecom(). Once it receives a message it will set up some global variables. First and most important of all is the 'mynum' variable. It will be set to the index in the PLAYER_REC array. Then also the 'cur_player' variable will be set to that slot in the array. the input string will be copied to 'strbuf' (stp is a number which indicates where brkword() has stopped working). When the player is in the game and types a command, it will be handled by gamecom. This will do several things for you. It will set up some variables: pl1,pl2,ob1,ob2. It will parse the command (if valid and call a function that handles that command). Lets take an example and see how it works: ->give foo foobar. In this example pl1 will be set to the number of foo, and ob2 will be set to the number of foobar (these numbers are directly or indirectly a number in the array of objects and players/mobiles). If we however type this: ->give foobar to foo It will set pl1 to -1 and ob1 to foobar (pl2 is foo and ob2 = -1). You can also do this yourself by using the brkword() routine (which gets the next word in the string) and fpbns and fobn (Find Player By Name String, Find Object By Name). It will search up give in an array of game commands, and will call the function that will handle that function. (See parse.c for some more info on this). The sockets are continuously checked, so whenever a command gets in, it will be handled. Besides the continuous check, the mud also has to move mobiles, send fight messages etc. This is done by using an alarm which goes of every 2 seconds. When the alarm goes off, the driver will call the function on_timer. This will work the in game clock, move mobiles, check open and closing times, send fight messages and some other stuff (see timing.c). Well thats what is done in a nutshell. I hope it will help you understand the code a little. See also Appendix D for more info on global variables. CHAPTER 2: SPECIAL EVENTS DRIVER -------------------------------- The file src/special.c includes almost all special events code of the world. This is done so the actual driver and the world code are seperated from eachother. This has the following advantages. - The driver code remains seperate, and is not affected by additions to the world. - Regenerating the world will not result in a remake of the whole driver. - The events work in a standardised way, making it easier to add things. - Less checks are needed on an average command. HOW DOES IT WORK In the old dyrt code, from which this code originates, all special events where coded into the driver. I moved those to seperate files and made a small routine which checks if something needs to be done. Because of this routine, only the objects/rooms that are involved with that command are checked, which results in more direct checks: Instead of checking all objects which have a special event, it now only check the object that is being handled. Lets take a look at a simple example. Lets say you want to 'get pick'. The driver will jump to the getcom, which will then check if the object (pick) has some special event. If it does, it will call the function which handles the events for that object with a unique number (E_ONGET here). HOW TO MAKE AN EVENT FOR AN OBJECT/ROOM/MOBILE All event handlers have the same prototype. It is defined as this: (void)spec_case(int); So a special event handler for an object will look something like this: void obj_fooland_foo(int event) { switch (event) { E_ONINIT: setoloc(param_s.ob,LOC_FOO_INTOWN,IN_ROOM); break; E_ONTIMER: sendf(param_s.plx,"Hello"); break; E_ONGET: destroy(param_s.ob); break; E_ONMISC: if (param_s.misc == VERB_WAVE) { bprintf("Foo waves as well\n"); } break; default: break; } } The first line is the function definition. You can also use the following define: EVENT_HANDLER(), which will fill in the right function definition. Example: 'EVENT_HANDLER(foo_bar)' equals 'void foo_bar(int event)' The integer parameter is needed to specify which event is being called. Besides the int parameter I use an global struct which holds some data on the call. The struct is called param_s and has the following fields. plx : Current player (same as mynum most of the time, but NOT ALWAYS) ob : object that is being handled/manipulated pl : Second char in the event (example: give .. to fooman, pl will point to fooman) misc : Misc values. Used by E_ONMISC, to specify which special event of E_ONMISC is called. ret : return value, if 1 then the function that called the event will continue (default), otherwise it will fail and return. buf : (type = char *). A pointer to a string. This one is almost only used for E_ONCOMM, where it stores the message the player is trying to tell someone. If we look at the example you will see what a typical event handler looks like. On initialisation it will set the location of the object to somewhere in fooland. When someone gets the object it will be destroyed. Once every 2 seconds it will print an hello message and when someone waves to the foo, it will wave back. To see what events are known look at include/special.h. Also you can read the special_event.doc for more info on events. Beta2 Update: Since switching over to Beta, all the special events code for mobiles and objects should be placed in the zone file. The generate will automatically created the code files and the object/mobile table. Only thing you have to do is add the file in the includemobs.h or includeobjects.h. There are two ways for adding code to a mobile or object. 1) Declare code for that object. This is done with the symbols StartCode and EndCode. The code in consists of the function body, so no header. So only the case code goes in there. See some of the other zone files for examples. 2) Let the object/mobile use an function of another mobile/object in the same zone. This can be done using the Extern symbol. Work in progress: - Moving remaining code out of the driver and into special events NOTE: Because of this special event driver, the mud has become slightly less stable, so it is recommended that you remake the MUD after a succesful generate, and only reboot into the new driver. CHAPTER 3: THE INPUT PARSER --------------------------- The original aber parser worked something like this: First it looked up the verb number by checking the command you gave with a list of possible commands. If it was in there, it would return the number of that verb. Then the parser would search the right function to call by examining a large switch statement. In the Alpha & up to Beta 2, I used another type of parser, which used hashing. Although it worked okay, it wasn't prefect. Since Beta 3 I switched to another parser. This chapter will tell you how it works, and why I choose to do it like this. If you look at the old parser, you will recognise what you could describe like two tables which had to be searched before a command would be executed. So I got thinking and thought it might be done more efficient. This is what I came up with. Instead of making a large switch statement with functions, I placed the functions in the same table as the verbs and verbnumbers. To do this I had to rewrite some functions so they would fit in the table. Now when someone types in a command, it will search that table and when it finds a match, it will have the function that should be called as well. The hashparser did the same thing except it stored the verbs a little differently. But here is the thing that makes this parser better than the hash parser. Together with the verb, verbnumber and the function, I also placed a mode field in it. So if a verb is meant for Wizard+ only, it can't be executed by mortals. This makes it possible to prevent a function from being called when it is bound to fail. Since the execution of the command is checked before the call, I can also make some intelligent deciscion not to call that command, but to look for a command that perhaps will work. Let me give an example of what I mean. Let us look at the verb frob and frost. In verbs.src they are standing alphabetically, so first frob then frost. Now someone (a God) types fro, meaning frob. The parser will look in the table and will find the frob command, and execute it. No problem here. Now another player (a mortal) types fro and hopes to get frost. So the parser again will look in the table and find the first match with the verb frob. Now normally this command would be executed, which would basically mean that he would get an error. But because the parser checks the mode of the command frob, it sees that this command would fail for that player (mortals dont have the frob command). So it will look further in the table for another verb, if any, that matches 'fro'. Then it finds frost and will execute that one, cause that one will succeed (hence everyone has the frost command). And this second lookup is the power of this parser, which is not found in the old parser nor in the hashparser. HOW TO ADD A COMMAND First you program a function that will handle that command. I made the A_COMMAND() macro, which will give your function the right type format. Once you finished writing it, add the verb name to the verbs.src file. Then open parse.c and place the following line in the Set_Commands function, together with the other commands. placecommand(VERB_YOURVERB,yourhandler,THEMODE); A more concrete example: You have made a command seethrough, which allows you to see through doors. the command that you add in verbs.src will be seethrough. You probably have made a function A_COMMAND(seethroughcom). Now only thing you need to do is link those two things together in parse.c like this: placecommand(VERB_SEETHROUGH,seethroughcom,M_ALL); The first two parameters you will probably understand (the first is the number of the verb, the second is the functionname). Now the mode field remains. I have specified the following modes: M_ALL : command is available to all players M_WIZONLY : command is available to wizards and up only M_AWIZONLY : command is available to awizards and up. M_DGODONLY : command is available to demi-gods and higher levels. M_GODONLY : command is only available to gods and masters M_NOTFORCED: a player can not be forced to do this command (ie quit) M_NOTINMAIL: a player can't execute this command when writing a mail. (ie quit). As you can see your command seethrough is available for all players. If it was meant as a wizard and up command, you should have set M_WIZONLY instead of M_ALL. If you make a command that could be lethal to the player, or could cause errors in the code, you might want to add the M_NOTFORCED, or M_NOTINMAIL flags. This is done by OR-ing them like this. M_WIZONLY|M_NOTFORCED|M_NOTINMAIL This command would be wiz+ only, can not be forced and can't be executed while in a mailer. After you added the command, and edited the parse.c file, you should do a make to compile the new code, before rebooting. CHAPTER 4: THE AUTOMATED TRANSPORT SYSTEM ----------------------------------------- Lets first define Automated Transport. Automated Transport is a loaction in the game, that moves between two or more other locations, and need a specified time to do this. Examples of Automated Transports (AT's) are: ferries, elevators, public transport etc. This is a system that is designed to handle multiple Automated Transports that move between a given number of ports/jetty's. The amount of At's you can handle is determined by the amount of memory you have and by the machine speed. It uses a linked list to administrate all the data needed to work the AT's. All data is contained in a single struct which can be found by using the function find_AT(). How to make a Automated Transport: 1) Make a location which is the interior of the AT. 2) Make 2 or more locations which will serve as 'ports'. 3) Give the AT a function which is called at E_ONINIT. Use this function to registrate the AT to the AT-system, by calling register_AT (only at startup) 4) Remove the ferry by using the remove_AT() function. An AT can be manipulated with the following functions: - replace_ports(): Make it possible to change the locations it attaches to. Note: If the next port in the list is the same as the one the AT currently is, it will stop moving. - activate_AT(): Starts an AT, so you can make a button that activates an AT. - stop_AT(): Stop an AT. - set_AT_messages(): Specify messages used. Allows you to use non-default travel messages. REQUIREMENTS: I'm not a perfect coder, so there are some requirements. - The size of the ports array should equal the size of the portnames array, and should not be 0. - The last location in the ports should be -1 (terminator) - The start location should be in the ports array - The size of the ports array should not be 0 - The AT name should exsist. - the traveltime should be in 2 second ticks. CHAPTER 5: ZONES ---------------- In this chapter I will explain to you how you can add new zones to the pDirt distribution. This is the same as on any other AberMUD IV type MUD (Dyrt, Dirt 3.1, iDirt). If you want to know how to write zones, I would like to refer to the excelent manual about this subject by Valentin Popescu (zone_writing.primer). To add a the zone to the world, copy the zone file to the directory pdirt/data/WORLD. In that same directory you will find a file called 'files'. It holds all names of zones that should be included. Add your zone to the list, but without extention. So if your file is called 'foo.zone', you add 'foo' to the list in 'files'. After you have added the file in there, go to the source directory and run the script 'gen'. If your zone doesn't contain errors, you can reboot the MUD, otherwise fix the errors, and keep on running 'gen' untill it is without errors. If you change one of the zone files or add a new one, you should always consider making a new daemon, since you might have changed the number representation of a mobile, object or room, causing the mud to do strange things. Therefore it is wise to add new zones at the end of the list, so you don't disturb the previous numeric sequence (and wont have to remake the MUD daemon after every addition to the zone). New symbols introduced in pDirt: StartCode = <name> Start of an special event function named <name>. EndCode = <name> End of a special event code block. Extern = <name> Function uses the function <name> that was declared at another mobile or object. CHAPTER 6: PDIRT INSTALLATION ----------------------------- I have been quite busy with the code, and changed quite a bit of code. I have no idea if it works on anything else than a Linux machine. I have kept the port files which came with the Dyrt distribution, which is still the core engine of this system, but I don't know if they work. All the options for different machines can be found in the Makefile in the source directory. So configure it so it matches your system. It should work with little or no modifications. Here is some steps you should take if you are installing on Linux. 1) Add your MUD-name to the list in data/prived 2) Replace the MASTERUSER name with your MUD-name 3) Make up your own UNVEIL password. 4) Edit the Makefile 5) Run make fresh. 6) Run aberd (use -f param if you dont want it to go to the background) NOTE: pDirt uses the gdbm-library. If your system does not have this library installed you will need to compile it yourself. You can get it from sunsite.unc.edu or prep.ai.mit.edu. NOTE2: The Beta works with a different Makefile. All the Flags and options have been moved to the Makefile in the source directory. So edit that one, and see how far it gets. CHAPTER 7: CONFIGURING DAEMON ----------------------------- The daemon (driver) can be configured in several ways. In this chapter I shall provide a small guide to the config.h file, and how to create opening hours for your MUD. Let us start with the the file include/config.h which includes almost all options needed to set the configurations that are compiled into the daemon. CONFIGURATION FILE Lets take an example config file, and see what everything does (I have stripped some comments to leave only the defines). ---- BEGIN CONFIG.H ---- 1 ] #ifndef _CONFIG_H_ 2 ] #define _CONFIG_H_ 3 ] 4 ] #define MASTERUSER "Marty" 5 ] #define UNVEILPASSWD "unveil" 6 ] 7 ] #define MUDNAME "Wasteland" 8 ] #define COL_MUDNAME "&+LW&+wa&+Wstela&+wn&+Ld" 9 ] 10] #define PORT 6715 11] #define MAX_USERS 15 12] 13] #define GLOBAL_MAX_MOBS 1500 14] #define GLOBAL_MAX_LOCS 3000 15] #define GLOBAL_MAX_OBJS 2000 16] 17] #undef HANDLER 18] #define REBOOT 19] #define TCP_ANNOUNCE 20] #undef CHECK_IDLE 21] #undef UAF_BACKUP 22] #define GROUP 23] #define RESET_TIME 45*60 24] #define RESET_IDLE 10*60 25] #define LINES 24 26] #define MAX_IDLE 30*60 27] #define FIND_SECOND 28] #undef ALLOW_PL_STEAL 29] 30] #define LOG_RESURRECT 31] #undef LOG_STORE 32] #undef LOG_LOAD 33] #undef LOG_CLONE 34] #define LOG_ALIAS 35] #define LOG_TOUT 36] #undef LOG_STEAL 37] #define LOG_SNOOP 38] #define LOG_HEAL 39] #define LOG_ZAP 40] #define LOG_SLAIN 41] #define LOG_EXORCISE 42] #define LOG_RESET 43] #undef LOG_WAR 44] #define LOG_SET 45] #undef LOG_PAGEERROR 46] #define LOG_EVENTS 47] 48] #define DYRT 49] 50] #ifdef NEED_RANDOM 51] #define SYS_NO_RANDOM 52] #endif 53] 54] #ifdef NO_VARARGS 55] #undef VARGS 56] #else 57] #define VARGS 58] #endif 59] 60] #endif /* Do not enter anything below this line !*/ ---- END CONFIG.H ---- The first 2 lines are and the last line (line 60) are needed for compiling. The real configurable part starts at line 4. This is directly the most important line in the whole configuration file. The name specified here as MASTERUSER is the person who always is granted God-priviledges. This should be set to the name of the player who owns the MUD. In line 5 you will find the Unveil Password. This is used for players beside the MASTERUSER, who also should have God priviledges. They can use the unveil command from within the mud to get these priviledges. In here you specify which password should be used by players that use unveil. Line 7 and 8 are used to make it easy to change the name of the MUD. The first one is the one most commonly used. The second one also has the colorcodes in it, and is almost never used, but is in here in case you wish to use it. Line 10 is used to set the default port number, ie the port players need to telnet to, to get a connection with your MUD. The default port for Aber IV Muds is 6715, but you can set it to any number between 2000 and 8000 or so. The MAX_USERS define is to set a default amount of players that are allowed to play simultaniously. Both line 10 and 11 can be overruled by using parameters at startup (-p and -n) Lines 13 to 15 are used to limit the amount of cloning that is allowed. If the amount of objects/mobiles/locations is exceeding this number, the clone will not succeed. If set to small, it may fail at bootstrap (generated files exceeds the numbers specified here). Line 17 is used to install a Crash handler, it only works on Sun's or so i believe. (Not used anymore) The REBOOT define is here in case the reboot code will not work on your machine. If it doesn't, undefine it here, and it will be compiled out of the driver. The TCP_ANNOUNCE define is here so you can install/deinstall the message wizards get to see when a player logs in. CHECK_IDLE is in here if you wish to install a idle checker. It will kick off players that are idle for longer than specified line 26. If you define UAF_BACKUP, the MUD will make a copy of your user file every day. This in case your mud screws your users_file. It hasn't happened to me yet, but you never know. In line 22 is the define that will determine if the Party grouping code is compiled into the driver. The RESET_TIME and RESET_IDLE are used for the the reset stone. The reset stone can only be hit every RESET_TIME (in seconds), and players that aren't at the shady clearing, but are idle longer than RESET_IDLE will be ignored and will not hold back a reset. The LINES define is used to set a default pager size. This is standard for a default terminal, so you better leave it at this figure. The define in Line 27 is to switch on the special feature of the parser ( see the parser chapter for further information) The last line is for a 'bug' that was found lately. It seems that players are able to steal from eachother, even in normal (not tournament) mode. I had a discussion about this with a couple of my MUD-friends, and we almost all agreed that this shouldn't be possible. Since we didnt agree 100 %, I added this option so you can switch it on, if you want it. Lines 30-46 are used to specify what should be logged in the syslog file. In the config.h file included in this distribution you will find what they mean. Line 48 is needed for the Party Grouping code, which is also made to work with iDirt. You better not touch it, unless you don't use the Party code. The text in line 48-60 is in here to allow easy porting to other machines. Check the configuration file for you machine in include/machine for more info on this. NOTE: As you might have noticed, some of the options have the experimental status. That means that they are not thoroughly tested and thus may cause the MUD to misbehave. Although it didn't happen when I tested them, you can't be too sure until someone confirms it works for them as well. OPENING TIMES Although opening times are a God's worst nightmare, it is sometimes required, especially on smaller machines where the MUD may take much of the resources. The opening hours are specified in the file data/hours, which is read at startup/reboot. Here is how you can specify opening times, There may be shortcuts, but since the orginal file explaining this has dissapeared, i had to experiment to find out how it works. The hours file is read one line at the time, and the format of the line should be something like this: <day> hh:mm to/till <day> hh:mm So you can specify another opening time for every day of the week. To clarify this format here is a configuration file for a MUD that is closed during the day from monday to friday, and open all weekend. ---- BEGIN HOURS ---- 1] monday 18:00 till tuesday 10:00 2] tuesday 18:00 till wednesday 10:00 3] wednesday 18:00 till thursday 10:00 4] thursday 18:00 till friday 10:00 5] friday 18:00 till monday 10:00 ---- END HOURS ---- The masteruser always has access to the MUD, even in closed hours. Once the MUD has been loaded, there is no way to alter the opening hours from within the MUD. The only way to change them, is to change the hours file and reboot the MUD. CONFIGURING GENERATE The new generator has uses some default values for fields that aren't filled in. These default values are in the utils/gen.h file. You can modify these values, if you wish. I suggest you keep them like this for compatibility reasons. CHAPTER 8: THE GENERATOR ------------------------ Because I like to have done everything once, and because I'm planning to expand the "zone-file language", I rewrote the generate program. It's almost completely new, except for the fact that it produces almost the same output as the old one (which you can still find in /utils/genold). The generator works in 4 steps, which I will explain in this chapter. The first step isn't really done by the program, but by your compiler preprocessor. This program strips the comments from your zonefile, and fills in the defines you used throughout the file (such as IN_ROOM etc). The generate reads the "stripped" zone file through a pipe. The second phase, is what I called the scan phase. In this phase the data in the zone file is read, and stored in internal datatypes. If any syntax errors are found, it will produce them now. After all the data is read, it is time for the parse phase. In this phase the program looks up the id's that correspond with a name. So in this phase the locations of mobiles and objects are checked, as well as the exits of a location. If a location can't be found you will get an error from here stating so. Now that the data is all checked for validity, and all id's are filled in, the program starts to produce the output needed. This output consists of the database files for mobiles, objects and locations (located in the /data/ directory), the include files and the zone table file. In this newer version I added the option of adding the special events code to the zonefile, so that the code files that belong to that zone are automatically created when doing a generate (this ofcourse can be switched of at will). If you wish to add some new fields to the zone files, you probably only need to study the genscan.c and genasm.c. The first file is the scan process, where the actual zone file is read and the other is the file that assembles the output. Lets say you want to add a field for objects, where the creator can specify what the output should be when someone opens a door. Here are a few steps you should follow to make it work. 1) Add a unique name to the objectIDs table (watch out as the table should be in sorted order. 2) Add an identifier on the same location in the ObjSymbols type. 3) Add a new variable for this field to the OBJECT structure 3) Add the Symbol to the switch statement in the function read_zone() 4) Create the code to read out the parameter (which in this case would be something like a readstring(); 5) Modify the way the objects are written. Don't forget that when you modify the way the database files are written you must also change the way the databases are read (which is located in bootstrap.c). But once you succesfully changed the generate, that part will be easy. Because I tried to seperate the layers as much as possible, it is now possible for you to first test the syntax of the new zone file before creating new databases. To see all options you can use generate -h. I will explain the options here as well. GENERATE OPTIONS -c Do NOT produce code files for objects/mobiles and global data -C instead of ../src/ use the specified directory. Make sure you add a space character between the -C option and the directory. example: generate -C ../../otherdirt/src -D use specified datadirectory instead of the DATA_DIR specified in include/files.h -e Use stderr instead of the GenError file. -s Only scan the specified file. Example: generate -s WORLD/newzone.zone You can add options before -s, but not after. -S Do only a scan of all files included in the world. Note: ALL DIRECTORIES ARE RELATIVE TO THE DATA DIRECTORY. So the source dir is ../src/ and the WORLD dir is WORLD/ etc. SOME ERROR MESSAGES: Here are some error messages I frequently encounter while generating a zone. 1) Warning, Object [xxx@yyy] is not ended properly, adjusting or Warning, Mobile [xxx@yyy] is not ended properly, adjusting You will probably encounter this error while generating jbs.zone. It means that the objects or mobiles weren't closed correctly. Every Object/mobile definition starts with the symbol 'name', and should end with the symbol 'end'. When you get this warning, the last one is missing. PS: I have cleaned jbs.zone, but it used to be full of these errors. 2) Warning: no start of line found. This means that the generator expected to find one of these symbols ', " or ^ on the line it is working on, but didn't find it. The rules say that the string must start on the same line as the symbol. So correct string definitions are: Examine = "blabla " or Examine = " blabla" When you get this error, you will probably have something that looks like this (and which is not legal): Examine = "blabla" 3) Warning, unknown zone yyyy Needed for location xxxx@zzzz Well this is pretty obvious. In one of the exits of location xxxx of zone zzzz, you specified an exit in zone yyyy. This warning just states that it didnt find a zone named yyyy, and thus the location is wrong. 4) Linked objects begin states are not the same [xxxx@yyyy] & [zzzz] When creating a door, both objects that make out the door should have the same begin state. If this is not the case, you will get this message. When generate encounters a situation like this, it sets the states of both objects to the state of object xxxx@yyyy. APPENDIX A: Maintaining a MUD (According to a fool) --------------------------------------------------- First of all, if you know how to run a MUD, then don't read this as you probably have better things to do besides wasting your time reading yesterday's news. Once you have compiled the driver, the real work of running a MUD begins: Maintaining and Improving the MUD. In this chapter I will attempt to show you how you can do this without bringing the whole MUD down. Every MUD has bugs and 'hidden features' which need to be fixed to ensure that the mud will run well. These small improvements should not be done without the owner of the MUD knowing about them. Make sure you keep a log file of whatever you do to the code. In this way you ensure that everyone who has access to the code knows what has been done. Maintaining the MUD means keeping the MUD up and make sure you can fix unsuspected errors, like hard-drive crashes (as an extreme). I don't have enough experience to give you a good guideline, so I can only can give you an example how it is with my MUD (EW) at the moment. Because of some faults in the system, our MUD has to be cold rebooted once every 2 week or so. Although this is an extreme case, it wouldnt hurt doing a reboot once every so often. If you bring the MUD down for longer than a few minutes, you should notify your players by placing it in a news file or the message of the day (motd). When you add new zones or change one of the old ones you might encounter some unsuspected errors (doors won't work etc). This is because the driver uses an internal number to notify objects, rooms and locations. Once you change the order in which they appear, you will cause the driver to generate errors. To prevent this, you should make sure you made a new driver, before rebooting the mud. Backups are an important and often ignored part of maintaining a MUD. Always have a backup ready for when the something happens to the original. Make sure you have a backup on some other machine or, better, on floppy/ tape or other backup device. Depending on the time it takes to do a full compile you can choose to make a complete backup (using the maketar script), or a partial backup by first cleaning the object files and all executables and files generated during compile. Keep in mind that using make clean could remove your user data file so, be careful on running that one. I advise making a backup once every month at least. See table A.1 for the meaning of the files in the pdirt distribution. Finaly make sure you have someone available at least a couple of times a week to answer players answers, and to make sure the mud is working properly. If you are unavailable at any time, make sure that people can contact you whenever it is needed. I will not tell you how to make your MUD a well organised place, that is something you must and probably will find out yourself. A.1 Listing of files found in a common dyrt/pdirt distribution. DIRECTORY FILES DESCRIPTION -----------+-----------+--------------------------------------------------- pdirt/bin | | | aberd | The mud driver. This should always be present in | | case of crashes. | aberd.old | The mud driver before the last compile. If the | | new driver crashes you can use this one. | Dump | Makes a screen dump of the player file. | generate | Needed to compile a new world, or verbs file | | (also see data and include directory) | pfilter | Should always be present. It is needed by the | | driver to read the helpfiles. | clean | A script that cleans all non-distributable code, | | should be run from make. Remember that running | | this you will remove ALL files that are generated | | at a complete make, plus ALL files that should | | not be distributed (like the user data file). | mkdep-x | a script needed by make to update the | | dependencies in the Makefile. | maketar | a script to make a complete (full) backup of the | | pdirt directory. | reorg | Latest addition to the pdirt distribution. This | | program will allow you to clear out unused user | | names, their mailbox, and descriptions. | viewman | Script to view the manual pages in the doc dir. | | pdirt/data | actions | Needed by the driver at startup (or reboot). | | Holds all external commands (smile sneeze etc..) | bootstrap | Needed by the driver on startup (or reboot). | | You probably want to leave this one alone. | hours | Needed by the driver on startup (or reboot). It | | holds your opening hours. It can NOT be removed | | if you have no opening hours. It should ALWAYS be | | here (even if it is 0 bytes in size). | illegal | A list of illegal names. | levels | the score needed at which level. | locations | See objects | mobiles | See objects | objects | These files are made by generate data. They are | | needed at startup or reboot. Consider it a | | database of your world. Better not remove them. | mkdata.log| File generated by generate data. Can be removed | | once generate is ready. | verbs.src | Source file for generate verbs. | verbs | Verbs file needed by startup or reboot. | wizlist | needed at startup or reboot. Better not remove. | users_data| (dyrt: uaf_rand). Holds players data. Make sure | | you keep backups in case this one gets screwed. | | Without this file you will have no players ;) | setins | in and out messages of wizards+. If you remove | | it people will have no messages anymore. It is | | automatically created (if it didnt exsists). | syslog | The driver log file. Do not remove it while the | | mud is running, since it will cause the driver to | | crash. | zones | Needed at startup (or reboot). | prived | List of priviledged users, that may become Gods | pflags | Needed at startup (or reboot), holds the masks of | | all wiz levels. pdirt/data/| WORLD | Directory holding the zone files. Needed to | | generate the locations, mobiles and objects file. pdirt/data/| INFO | Directory holding all info files. Needed during | | uptime of the mud. pdirt/data/| HELP | Helpfiles, needed by driver when running. pdirt/data/| TMP | temporary dir where the driver stores commands | | that use the pager. pdirt/data/| MAIL | The directory where the mail for users is stored. pdirt/data/| DESC | The place where your examine descriptions are | | stored. pdirt/data/| MESSAGES | (pdirt only), place where messages needed at | | login, or for some commands are stored. pdirt/include| | Place where all include files are. This directory | | and all files in it are needed to compile the | | mud. pdirt/src | *.c | Source code files for the MUD, needed to compile | | a new MUD driver. | *.o | All files that are compiled. | Makefile | needed to compile the MUD driver (needed by make) | verbgen | script to generate a verbs file. | gen | script to generate the database files (locations, | | mobiles and objects) pdirt/src/ | npc | code for the mobiles in the world. (needed for | | compile of the driver) pdirt/src/ | rooms | code for the rooms in the world. (needed for | | compile of the driver) pdirt/src/ | objects | code for objects in the world. (needed for | | compile of the driver) pdirt/doc | | Various documents on using the mud and UNIX | | utilities. pdirt/utils| *.c | Code files used to make the utilities. pdirt/utils| newtypes.h| file needed by conv.c pdirt/utils| Makefile | File needed to compile the programs. pdirt/utils| genold | Location of the old original generate code. pdirt/utils| xpp | A small C-preprocessor, needed by some machines | | because their original preprocessor won't work. pdirt/gdbm | | the gdbm library source code. In case you do not | | have a working gdbm library on your system. -----------+-----------+-------------------------------------------------- APPENDIX B: pDirt scripts ------------------------- Here is a small table with all scripts in the pDirt distribution, with an explenation what they are for. Filename: Description: pdirt/bin/clean Cleans all non-distributable files from the pdirt directories (all object files, executables etc) pdirt/bin/fixlog Sorts all logs by type, and places them into the directory pdirt/data/LOGS. pdirt/bin/maketar Make a new archive of the whole pdirt directory pdirt/bin/mkdep-x Script file used by make depend. Checks dependancies of files, and updates the makefile. pdirt/src/gen re-generate the zone files. pdirt/src/verbgen re-generate the verbs files. pdirt/src/lockmake A script to ensure you're the only one that is making the driver at that time, and also will prevent any reboots from happening while you're making pdirt/backup/makedist A script used by me to clear the whole package from any files that should not be included into a distribution. pdirt/backup/backup A srcipt to make a backup of the src, utils, data and bin directory. APPENDIX C: Coding styles ------------------------- To make the code clearer to read i have made several defines and macros. First of all I have added defines to all include files and source files, to indicate with which file we are working. Secondly, I'm introducing the defines PUBLIC, PRIVATE and EXTERN. These are used to indicate if the function/Variable may be called from another file. PUBLIC means that the function is available to the whole MUD. PRIVATE means it can only be called from the current module (something like the old static). I am also trying to code as much as possible in one style, which should improve the readability. Here are some rules I try to follow as much as possible. IF-STATEMENT FOR-STATEMENT WHILE- STATEMENT if ( .... ) for (..;..;..) while (...) { { { } } } else <if (.....)> SWITCH DO-STATEMENT switch (..) { do case ..: { ........ } case ..: while (...) ........ default: } Off course every programmer is used to their old style of programming and will use these automatically, but this is just to indicate which style I use. APPENDIX D: Global variables ---------------------------- All Aber derived muds use quite a bit of global parameters. Here are some of the important ones for pDirt in a row. room_data[] : The array of all locations in the MUD (type is Location) objects[] : The array of all objects in the MUD (type is Object) ublock[] : The array that holds all mobile data. The first few entries in this table are also used to store some of the player data. players[] : The table of that holds all player data. Well not all.. Some of the data is held in the ublock array. wordbuf : global string variable that can be used for getreinput(). It is also used by the function brkword(), which breaks up a sentence in words. After brkword(), wordbuf contains a word, if brkword was succesful (return value != -1) item1 : string variable, see item2. item2 : string variable. This variable is assigned a value at parsing time. Example: > foocommand fooword to bleh In this stupid example, item1 will be set to "fooword" and item2 will be set to "bleh". words as to/in/at/on are ignored when parsing. globalbuf : A string variable. Can be used as temporary storage of a sentence. mynum : Integer variable. Indicates current user that is being processed. set to -1 when user can't be found, should never happen. real_mynum : If player is aliased or polymorphed, mynum will point to the index of the mobile, this variable will point to the real player number. (ie real_mynum is always < max_players, mynum not) cur_player : Pointer to entry in players table. Can be used to manipulate data of the current player. cur_ublock : Pointer to current ublock in the player table. max_players : integer value which shows how many players can be logged in at the same time. (is also the size of the players table) pl1,pl2,ob1,ob2: see Global functioning chapter. MIXLINE,DOUBLELINE,DASHLINE: global string variables, can be used to draw pretty lines :) param_s : structure that holds data that may be needed by a special event driver. ############################################################################## Compiled by Marty in 1996 & mostly written by Marty (pardon my english %-) ) email: petere@odie.et.fnt.hvu.nl