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