pdirt/data/
pdirt/data/HELP/
pdirt/data/HELP/0/
pdirt/data/HELP/F/
pdirt/data/HELP/G/
pdirt/data/HELP/H/
pdirt/data/HELP/J/
pdirt/data/HELP/K/
pdirt/data/HELP/O/
pdirt/data/HELP/Q/
pdirt/data/HELP/R/
pdirt/data/HELP/U/
pdirt/data/HELP/V/
pdirt/data/HELP/Y/
pdirt/data/HELP/Z/
pdirt/data/MESSAGES/
pdirt/data/POWERINFO/
pdirt/data/WIZ_ZONES/
pdirt/drv/
pdirt/drv/bin/
pdirt/drv/compiler/converter/
pdirt/drv/compiler/libs/
pdirt/drv/compiler/scripts/
pdirt/drv/include/AberChat/
pdirt/drv/include/InterMud/
pdirt/drv/include/machine/
pdirt/drv/src/InterMud/
pdirt/drv/src/Players/
pdirt/drv/utils/UAFPort/
pdirt/drv/utils/dnsresolv/
pdirt/drv/utils/gdbm/
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