3.0... What changed?                  (last change: april 27th, 1992)
--------------------

Index
-----
        Preface
	Introduction

	The 3.0 mud
	    Some commands
	    Directories under 3.0

	LPC 3.0
	    Types
	    Arrays
	    Mappings

	Objects in 3.0
	    Objects and properties
	    Some examples
		ROOM.C
		OBJECT.C
		CONTAINER.C
		MONSTER.C
		ARMOUR.C
		WEAPON.C

	VBFC
	Skills
        Debugging
	Interesting documents
	Constants for different metals


Preface
-------
I will divide this doc into several chapters, so you can quickly
find the things you are interested in. In this document, when some-
thing is between brackets (<...>), it means that it is required to
fill in the piece between the brackets in your command with something
that makes sense. If something is between braces ([...]) it means
that that part is optional, and can be left out.


Introduction
------------
I wrote this doc, to help people who have absolutely no experience in
programming LPC 3.0, or with the 3.0 mud itself. I hope that you will
be enlightened in the use of 3.0 and that you can make simple 3.0
objects after you have read this doc. Some people think this is the
reference guide for LPC 3.0. Let me assure you that it isn't, and that
such a document would be hard to write. LPC 3.0 is a language on the move,
and I have learned that the best way to learn it is to look in the sources.
However, not everyone will be able or willing to do that, so I hope that
reading this doc will get you on the coding track a bit sooner. If you
want to know the bottom of everything you are using, I suggest you take a
look in all the files you include/inherit.

It could very well be that this document is not very clear to the layman.
The problem is that I have been programming in LPC for a long time now, and
to me everything seems very clear, so I might not even notice that I skip
important explanations that ought to be given. If you find such a spot in
this document, or notice an erroneous remark or erroneous code, do not
refrain from mailing me, your help is greatly appreciated.

                                                   Tricky

The 3.0 mud
-----------

Some commands
-------------
There are a few commands that really are interesting in 3.0, of which the
most important ones are probably:

   allcmd          Shows all your commands.

   localcmd        Shows all commands added by your direct environment.

   help <cmd>      Shows often help on the command <cmd>. In order to keep
                   this document short, I have not explained every following
                   command in full. Should you need more help, use "help".

   sman [-k] [-s] <fun>
                   Searches for help on the function <fun>. If you use the
                   -k flag, the function <fun> will serve as a keyword, all
                   matching functions will be displayed. This is used to
		   search the mudlib sources. If you use the -s flag, you
                   get to see the sourcecode of the function. Note that
                   this works fine when the searchtable is updated regu-
                   larly, but that it could occur that you end up in the
                   wrong spot in the sourcecode. No fear; you probably are
                   near the place where the source really is.

   man [-k] <subject>
                   Searches for help on the function <fun>. If you use the
		   -k flag, the function <fun> will serve as a keyword, all
		   matching functions will be displayed. This command is
		   used to search for information on efuns and general
		   subjects.

  ed <file>        Edit a file. Most of the help on the editor can be
                   obtained within it! Try "h", or "?" in the editor.
                   NOTE: you don't have to do your editing in Ed, if
                   you can ftp, try this: "ftp milou.cs.chalmers.se", use
                   the login "lpmud:<yourname>" and your own mud-password.
                   Then you can use "[m]put" and "[m]get" to transfer
                   files to and from your own directory. That way, you
                   can use all the comforts of your home editor.

   cp <from> <to>  Copy the file <from> to the file <to>. You may even
                   use wildcards like "*" to match files. There is a
                   maximum number of files you may match, though. <To>
                   may also be a path.

   mv <from> <to>  Move (rename) the file <from> to the file <to>. The
                   file <to> doesn't have to be in the same directory
                   as <from>.

   rm <file>       Remove (delete) the file <file>. Use wildcards if you
                   like.

   sanction <flags> <who>  Allow/disallow someone to read/write in your
                   own directory or to snoop you. Try "help sanction" for
                   more info.

   start here      Set your startup-place. I like to start in the privacy
                   of my workroom, instead of in the crowded church.

   title           Set your title.

   adjdesc         Set your adjective description.

   altitle         Set your alignment title.

   busy [flags]    This command sets your busy level. There are too many
                   flags to explain them all here. Let me just say that
                   it is possible to make yourself completely deaf with
                   this command.

Well, those were by far not all commands, but these are the most basic ones.
If you want to know more, use "allcmd" to find out your commands, and then
ask "help" on one of them.


Directories under 3.0
---------------------
The paths under 3.0 have changed radically. I will point out what the
interesting directories are.

   /doc
      This directory contains only subdirectories. As the name suggests,
      those directories are filled with docs.

   /doc/examples
      This directory contains a growing number of examples of various
      objects. If you want to make something, see if there is an example
      of it somewhere in this directory.

   /doc/man/efun
      This directory contains all manuals for the external functions that
      are provided by LPC. If you search for a function that is not specific
      for any object in particular, look in this directory. You can also
      "man <external function>" to look at its description.

   /doc/sman
      This directory contains all manuals for the local functions of most
      objects that are often inherited. There is a lot to be found in here!
      It is probably easier to do "sman <local function>". "sman" stands
      for source manuals; the sources of the functions can be examined by
      doing "sman -s <local function>". If you only know a name partially,
      you can do "sman -k *<partial name>*", that will show all function
      names that match.

   /std
      This directory contains all objectfiles that need to be inherited
      if you make an LPC object. Multiple inheritance is allowed in LPC,
      but usually inheriting one objectfile will suffice. Inherit eg.:

         - armour.c       for amours, like a chainmail
         - board.c        for a bulletin board.
         - coins.c        for money, like some platinum coins
         - container.c    for a container, like a bag
         - creature.c     for a very basic creature, like a snail
         - drink.c        for a drink, like brandy
         - food.c         for food, like bread
         - herbs.c        for herbs, like blackberries
         - monster.c      for a human-like monster, like an orc
         - object.c       for generic objects, like a painting
         - spells.c       for an object that defines spells, like a scroll.
         - weapon.c       for weapons, like a two-handed broadsword.

   /lib
      Here you find inheritable modules that do stuff for you. If you want
      to make a shop, for example, a lot of convenience routines have been
      implemented for you in "/lib/trade.c". Just inherit that module as
      well in your shoproom, and you can use those routines. Here is a list
      of some library modules:

         - guild_support.c     for make guildshadows
         - herb_support.c      for creating herbs more easily
         - skill_raise.c       for making guildrooms where skills are trained
         - store_support.c     for making shops
         - trade.c             for things that use trading with coins

   /sys
      In 3.0 you use a lot of values to access things. In order to keep
      things transparent to the wizards, all values are hidden behind
      logical sounding names. This also enables the shifting of values
      without anyone noticing it in his objects. Therefore you should use
      always defines instead of their real definitions.
      In this directory you will find almost all of the includes that are
      interesting to include, such as:

         - macros.h        handy macros.
         - stdproperties.h standard properties of all kinds of things.
         - wa_types.h      weapon and armour types.
         - ss_types.h      standard skill types.
         - formulas.h      standard conversion formulas.
         - money.h         money definitions

   /secure
      The 3.0 security system is more tight than that of 2.4.5. More and
      more the access to certain functions is checked. The first object
      that is loaded when the GameDriver is rebooted is the security master,
      or master for short. Some functions can only be called via this
      object, e.g.: SECURITY->query_domain_lord("Genesis");. The name
      SECURITY is defined in the file /secure/std.h

   /d
      In this directory all the domain directories are located. As you
      probably have noticed, all domains start with a capital, whereas
      wizardnames start with a lowercase letter. If a wizard has a
      directory, but is not in a domain, he is automatically in the Wiz
      domain.
 
   /d/Wiz
      This directory is the home of the braves. Most of the keepers and
      arches have their directories in this directory. You will probably
      not be able to read any files in them ;-).

   /d/<Your_domain>
      In this directory is your directory located. You have read access
      to all files and directories in this directory.

   /d/<Your_domain>/<your_name>
      Yep, this is your directory. You have read and write access to it.
      This directory can also be accessed as ~. E.g.: ~/workroom.c is
      your workroom, whereas ~mrpr/workroom.c is Mrpr's home office.

   /d/<Your_domain>/common
      This is the common directory of the domain you're in. Every wizard
      in the domain has write-access on it. That can be real handy if
      someone wants to debug your stuff when you are away.

   /d/<Your_domain>/open              and
   /d/<Your_domain>/<your_name>/open
      Everyone (including people outside your domain) has read-access to
      these directories. That is why you don't need to write in the /open
      directory, simply put your open stuff in your own open directory!

   /d/Genesis
      This is the domain that contains all startup-areas of all races,
      the wiz-area, the race-specific souls and much more. All directories
      can be read by you.

These were the most interesting directories. You probably cannot write in
most of them. This rule does not apply to all people. Lords can write in
every directory in their domain, arches and keepers can write everywhere
they please. Note that you can allow other wizzes to read and/or write in
your own directories by doing "sanction [R][W] <name>", or by simply
putting the stuff you want them to examine in your open directory.


So much for the introductory part, let's get down to the serious business:

LPC 3.0
-------
Some fear it, some think it is impossible, others adore it. I don't know.
For those of you who know LPC 2.4.5 (or 2.4.6), it hasn't changed that much.
Ofcourse there are lots of new functions defined by LPC 3.0, but they are
implemented because they make your life easier. All that is written below
is made with the intention to enable you to make simple objects in LPC 3.0.
If you want to make advanced objects, ask someone who knows about it. You'd
better try to make some simple objects at first, and then try to improve
them.

Types
-----
If you look for the first time at official 3.0 code, you will notice one
difference with 2.4.5: the functions and their arguments have types, e.g.
"object *query_team_members(int flag)".

It is possible to use types in your code, however you don't have to.
If you use types, you must use it for all functions, and you must make sure
that functions are put in the right order, i.e. if function a() calls in its
body function b(), function b() must be declared above function a(). This
declaration can be done in two ways: you can put the entire funtion b() above
a(), or you can implement the function b() somewhere below a() and put the
prototype of b() (e.g.: "int b(int arg);") above a(). One good reason to
use types is that the compiler will be able to detect errors in your code 
more easy, and maybe even directly at the compilation and not wait until 
the bugous function is called.

LPC 3.0 knows these types:
	void		Used for functions that do not return anything
	int		Integers, ranging from -(2^31) to 2^31
	int *		An array of integers, e.g. ({ 1, 2, 3 })
        string          A string of characters and special characters,
			e.g. "\tHi!\n"
	string *	An array of strings, e.g. ({ "foo", "bar" })
	object		An object as you get with clone_object()
	object *	An array of objects
        mapping         A special array, e.g. ([ "foo":"f", "bar":"b" ])
        mixed           Anything of the above.
	mixed *		An array of mixed values.

Several of these types can be checked within your code with the functions
intp(), stringp(), objectp(), mappingp(), which can be useful if you want
to enable people to call your functions with e.g. objects or arrays
of objects.

Type qualifiers
---------------
By adding certain keywords to the basic types you can modify the behaviour
of your objects, functions and variables. They work differently depending
on if they are applied to functions or variables.

Applied to functions:

	static <basic type> 
		The function can only be called by this object. It can't
		be directly accessed with call_other.

	private <basic type>
		This function is only callable from other functions in the
		same compilation unit (the same file and files that include
		or are included by the file). It can't be directly accesessed
		with call_other, and it can't be called from functions in
		other modules in the inheritance chain.

	public <basic type>
		This function is normally callable. It is the same as if you
		didn't put a qualifier at all.

	nomask <basic type>
		A nomask function can't be hidden by an inheriting function.
		Neither can it be shadowed.

	varargs <basic type>
		A note to the compiler that the function may be called with
		a variable number of arguments.

Varargs and nomask can be combined with any of the other modifiers and with
each other... 

Applied to global variables:

	static <basic type>
		This variable will not be saved when the object is saved
		with save_object() or changed by a restore_object().
	 
	private <basic type>
		This variable can only be accessed by functions in the same
		compilation unit.

	public <basic type>
		This is the same as a variable with no modifier.

Arrays
------
Arrays have become very powerful in LPC3.0. There are many new functions that
support the use of arrays. Let me first explain what an array looks like in
LPC: ({ a, b, c }) is an array with 3 elements, a, b and c. these elements
can be of any type: integer, string, object or even array. Arrays can simply
be added like this: ({ "foo" }) + ({ "bar" }) gives ({ "foo", "bar" }).
Arrays are allocated on the fly, i.e. you don't have to allocate or
deallocate anything, the gamedriver does that for you.

Here are a few array functions that are very handy:

   arr[index]
        This will give you the "index"th element of the array arr. Note
        that the elements of an array are numbered from 0 to the length
        of the array minus one (sizeof(arr)-1)).
   
   member_array(elt, arr)
        With this you can check if a given element is a member of the array
        you want to check. If it is a member, the index will be returned.
        Since this means that 0 can be the return value, -1 will be returned
        if the element is not included in the array.

   explode(str1, str2)
	This function returns an array that consists of the loose strings
	that come into existence after the string str1 is divided in parts
	by cutting on every occurence of str2. Eg. if you did
	explode("Humpty Dumpty fell of a wall.", " "), you would get
	({ "Humpty", "Dumpty", "fell", "of", "a", "wall." })

   implode(arr, str)
	This function returns a string that is made of all elements of the
	array arr, with the string str placed between them. E.g.:
	implode(({ "foo","bar","zukini." }), " and ") would return
	"foo and bar and zukini."  

   arr[from..to]
	This notation returns a piece of an array from element from to
	element to. The function slice_array, which did exactly the same,
	is obsolete. E.g.: ({ 1, 2, 3, 4 })[1..2] returns ({ 2, 3 }).

   filter(arr, fun, obj)
         This function returns an array with all elements in it for which the
         function fun in object obj returned 1. The elements for which 0 was
         returned are left out. fun is the function name, enclosed in quotes.

   map(arr, fun, obj)
         This function returns an array in which all elements have been
         replaced by whatever the function fun in the object obj returns
         for each element. fun is the function name, enclosed in quotes.

   sort_array(arr, fun, obj)
         This function returns the sorted version of arr, by using the
         function fun in object obj as less-equal function. Say eg., you
         want your array of strings to be sorted alphabetically. The you
         would make a function str_less_eq() like this:

            str_less_eq(a,b) { return a <= b; }

         And then you would do:

            arr = sort_array(arr, "str_less_eq", this_object());

         Et voila! An alphabetically sorted array.


Mappings
--------
Mappings? Yes. Mappings are arrays that are addressed not with a number as
index, but with a string. Mappings were designed to make certain function a
little bit faster. Since mappings use more memory than normal arrays, you
are asked to use mappings as little as possible, preferably not at all. This
is how a mapping looks: ([ "foo":"bar", "jacuzi":"zukini" ]). The words
before the colon are the indices. Let's call the previous mapping M. In that
case M["foo"] would be "bar" and M["jacuzi"] would give "zukini". The part
after the colon is of the type mixed, so it can be anything, even arrays
or other mappings.
In fact, the indicies of a mapping need not be strings, even if this
is the most common usage.  They can be of any type, e.g., int or object.


Objects in 3.0
--------------
As Commander wrote in his NEW_V3 doc, all objects will inherit something.
The file that is being inherited is called /std/xxxx. The first function
you define in your object, in which you will probably set the name, the
long description and the short description, is called "create_xxxx", where
xxxx is the name of the object you inherited. The function "create_xxxx"
will be called the first time the object is loaded or cloned.

Every half hour, the mud will send a reset signal to all its objects. Then,
the function "reset_xxxx" will be called. So, if you want to refresh your
guards periodically in a room, so it will not stay unguarded too long, the
"reset_room" function is a good place to put a check in.

The last interesting function is init(). This function will be called
every time a living creature comes 'in sight' of an object. Eg. if the
object is picked up, if a monster enters the same room, if an object is
taken out of a bag, its init() will be called. Some objects require that
you put a line "::init();" in the init() function. Typically, you will
add commands to a player in the init(). Note that it is not possible to
use the function init() in a monster. Instead, you should use init_living().
The '::' in front of a function means that you try to call the old version
of init(), the one that existed before you decided to redefine it.


Objects and properties
----------------------
Suppose you want to make a lead ball and a big cardboard box. To create
these things, you set their name, and make up a long description. This
is not enough, however. If you only do that, people will be able to carry
about seven of each, whereas in real life two lead balls, because of the
weight, or only one big cardboard box, because of its size, could be
carried by a person.

To make objects more like in real life, objects have properties that their
creator can set. Many standard properties have been invented, and are used
to determine lots of things. They can be found in /sys/stdproperties.h,
which you probably will want to include in your object. The defined names
have a standard form, take for example OBJ_I_WEIGHT. The first part OBJ
means that it is an object property. The second part, I, means that the
property wants a value of the integer type. Other type-descriptors are
S, O and V, and combinations like AI, AS, etc. for arrays of a type.
S means string, O means object and V means 'value by function call'-string.
An M means mixed type = anything :)

Properties can be added by doing "add_prop(<property>, <value>);" in the
object. If the property already existed in the object, the old value will
be replaced by the new value. You can ask the value of a certain property
by calling "query_prop(<property>);" in an object. If a property was not
set, query_prop() will return 0.

Some examples of interesting properties to set:

   #include "/sys/stdproperties.h"

      ...
      add_prop(OBJ_I_WEIGHT, 10000); 	    /* Set weight to 10 Kg    */
      add_prop(OBJ_M_NO_DROP, "@@my_drop"); /* VBFC (explained below) */
      add_prop(OBJ_I_INVIS", 1);	    /* Make invisible	      */
      ...

   int
   my_drop()
   {
       if (this_player()->query_wiz_level() > 0)
           return 0; /* Wizards are allowed to drop this */
       else
           return 1; /* Players are not */
   }

As you can see, the weight is set to 10000 grams, and invisibility is set
to 1, meaning on. The NO_DROP property is used cunningly to detect whether
someone wants to drop this object. If someone tries to drop our object,
query_prop(OBJ_M_NO_DROP) is done, which causes a call to our function
my_drop(). There the wizardlevel of the person is checked, and 1 (meaning
NO_DROP is on) is returned if it was a player who attempted to drop it.


Some examples
-------------
There are a few basic objects that I will explain here. Ofcourse that will
not be all objects, but the most interesting ones. I hope that the examples
have some didactic value.

One thing: if you code an object, please, please, please, pretty please
code with indentation like /doc/man/general/code_standards describes.
There even is a command to help you: "indent <filename>". You don't have
to use exactly that way of indenting, but use one alike. Other peoples code
is unreadable as it is, not properly indented code is really not readable.
Not for you, and not for the person that is trying to figure your code out.


ROOM.C
------
This is probably the most interesting object, since it is the one you will
create most often. This is what the world is made of. Let's make a simple
room.

   inherit "/std/room.c"

   #include "/sys/stdproperties.h"

   void
   create_room()
   {
      set_short("Entrance");   /* This will show up when the player is in */
                               /* "brief" mode.                           */
      /* Set the long description of the room */
      set_long(break_string(
         "There is something very peculiar with this room... It is "
       + "cube-shaped, yet it has no corners! You wonder what sorceror "
       + "would make up such a mind-boggling kind of room... Luckily "
       + "you can escape to the south.\n",70));

      add_exit("/d/Genesis/start/human/church", "south", 0, 1); /* add exit */

      /* Make the corner examinable */
      add_item(({ "corner", "round corner", "edge" }), break_string(
         "You desperately search for a corner, but you cannot locate one. "
       + "How is this possible? You are starting to get a headache.\n", 70));

      add_prop(ROOM_I_INSIDE, 1); /* This is an indoors room */
   }

That was the room... As you can see, I used the break_string("...",70)
technique to make sure that the string is cut into lines of length < 70
characters. The same technique is used with add_item. Note that it is
possible to give either one string, or an array of strings as first
argument to add_item. The given description will be shown every time a
player wants to look at the identifier string.
The add_exit function has four arguments: The filename of the room that is
connected to this room, the command that will get you there and the third
argument is an optional VBFC function (explained below). If that function
returns 1, the exit cannot be taken. If the function returns 0, the exit
can be taken. The last argument indicates how tiring it is to walk that 
direction. 1 is the default value.


OBJECT.C
--------
Let's say you want to make a light-bulb. This is typically an generic object.
This is what the code would look like:

   /* A light bulb */

   inherit "/std/object";

   #include "/sys/stdproperties.h"  /* We want to use standard properties */

   void
   create_object()
   {
      set_name("bulb");           /* The id of this object   */
      set_pname("bulbs");         /* The plural id           */
      set_short("lightbulb");     /* The short description   */
      set_pshort("lightbulbs");   /* Plural short descr.     */
                                  /* Long description        */
      set_long("This lightbulb is now more like a dark bulb.\n");
      add_prop(OBJ_I_WEIGHT,75);  /* Set weight property to 0.075 Kg  */
      add_prop(OBJ_I_VOLUME,200); /* Set volume property to 0.200 Ltr */
   }

That was all! You could leave out the add_prop(...) part, but then the
light bulb would weigh 1 Kg and measure 1 Ltr. This goes for all properties:
if you don't set them specifically, they will take a standard value. You
can also leave out the set_pname and set_pshort part, but then the parser
will try to make its own plural, which you might not like. Eg. when I
cloned another "test version of the pipe of the Shires", I suddenly
carried "two test versions of the pipes of the Shireses"...

Suppose you want the players to be able to light the lightbulb. Then you
would have written the lightbulb something like this:

   /* A little bit more interesting light bulb */

   #include "/sys/macros.h"         /* Some useful macros                 */
   #include "/sys/stdproperties.h"  /* We want to use standard properties */

   inherit "/std/object";

   int lighted; /* Global variable to indicate if the bulb is lighted */

   void
   create_object()
   {
      set_name("bulb");           /* The id of this object   */
      set_pname("bulbs");         /* The plural id           */
      set_short("@@my_short");    /* The short description   */
      set_pshort("@@my_pshort");  /* Plural short descr.     */
      set_long("@@my_long");      /* Long description        */
      add_prop(OBJ_I_WEIGHT,75);  /* Set weight property to 0.075 Kg  */
      add_prop(OBJ_I_VOLUME,200); /* Set volume property to 0.200 Ltr */
      lighted = 0;
   }

   void
   init()
   {
      add_action("do_light", "light"); /* Add the command 'light' */
   }

   string
   my_short()
   {
      if (lighted)
         return "lightbulb (bright)";
      return "lightbulb (dim)";
   }

   string
   my_pshort()
   {
      if (lighted)
         return "lightbulbs (bright)";
      return "lightbulbs (dim)";
   }

   string
   my_long()
   {
      if (lighted)
         return "The lightbulb is currently lit.\n";
      return "The lightbulb is more like a dark bulb. Perhaps you can light "
           + "it.\n";
   }

   int
   do_light(string str)
   {
      if (str != "bulb") /* Did the player type 'light bulb'? */
      {
         notify_fail("Light what?"); /* Set message if everything fails */
         return 0;                   /* 0 means we didn't recognise it  */
      }
      if (lighted)
      {
         notify_fail("The bulb is already lighted.");
         return 0;                   /* 0 means we didn't recognise it  */
      }
      lighted = 1;
      write("You light your lightbulb.\n"); /* Message to the player */
      say(QCTNAME(this_player()) + " lights "
        + this_player()->query_possessive() + " lightbulb.\n");
      return 1; /* We recognised the command */
   }

As you can see, I use for the short, plural short and long description weird
strings, like "@@my_short". This is called Value By Function Call, and is
explained in another part of this document. For the moment it is enough to
know that they return the value of the mentioned function.

To add a command to a player I use the add_action() function in the init().
Each time a player "comes near" the object, the command "light" is added.
If he "leaves" the vicinity of the object, the command is gone again.
Should the player type "light torch", the function do_light() is called with
whatever was typed behind the command "light" as argument. Functions that
are called by add_action() have to return 0 if they do not recognise the
command, or 1 if they handled the command. This allows multiple objects to
define the command "light" in our case. The moment some function returns 1,
the quest for "light"-commands stops. If no function returns 1, the player
will get to see "What?". That is, if no notify_fail() was set. If some string
was set, then the player does not get to see "What?", but the set string.

If the player typed "light bulb" and the bulb was not lighted, then we can
turn the bulb on. First we give a message to the player that she succeeded,
with write(). Write() goes to the player that gave the command, this_player()
to be exact. Then we give a message to everyone in the same room as the
player, but not to the player herself. For this you can use say(). Now a
typical 3.0 thing happens: the macro QCTNAME(). This stands for Query-
CapitalizeTheName, and makes sure that people who know this_player() get to
see her name, but that people who do not know her get to see something like
"The cute happy hobbit" instead. There is a good document that describes the
met-nonmet system exellently, I believe it is called
/doc/man/general/meet_people.

Because we want to say "his lightbulb" for men and "her lightbulb" for
women we ask the possessive article of the player with query_possessive().

After all of this we return 1, because we have recognised and completed
executing the command "light". Perhaps it would be a good exercise to enable
the players to "darken" the lightbulb as well.


CONTAINER.C
-----------
This is a more tricky object, because it does not only have its own volume
and weight, but can also hold a specific volume and weight. Let's say you
want to make a nightstand:

   /* A nightstand */

   inherit "/std/container"

   #include "/sys/stdproperties.h"

   void
   create_container()
   {
      set_name("nightstand");
      set_short("crummy old nightstand");
      set_adj(({"crummy","old"});      /* extra adjectives, the player    */
                                       /* can now do "exa old nightstand" */
      set_long("The crummy old nightstand will probably not last long.\n");
      add_prop(CONT_I_WEIGHT,     20000);   /* It weighs 20 Kg            */
      add_prop(CONT_I_MAX_WEIGHT, 27000);   /* It can contain up to 7 Kg  */
      add_prop(CONT_I_VOLUME,     14000);   /* It measures 14 Ltr         */
      add_prop(CONT_I_MAX_VOLUME, 17000);   /* It can contain 3 Ltr       */
      add_prop(CONT_I_RIGID, 1);            /* It is a rigid object       */
   }

As you notice, the MAX_WEIGHT and MAX_VOLUME are the WEIGHT and the VOLUME
plus what they can contain. The nightstand cannot change shape, so it is
defined RIGID. A bag would typically not be rigid, unless it has been washed
with too much paste ;-).


MONSTER.C
---------
These babies can do a lot. I myself am not quite aware of all their capabili-
ties, but there sure are a lot. I will only show how to make a really simple
talking monster. Let's make an ugly nazgul by the name of Dschik.

   /* Dschik, the ugly nazgul */

   inherit "/std/monster";
   #include "/sys/stdproperties.h"
   #include "/sys/ss_types.h"

   void
   create_monster()
   {
      set_name("dschik");
      set_race_name("nazgul");
      set_adj("ugly");
      set_long("Nazguls are ugly, but this one is one of the uglier types.\n");

               /* STR DEX CON INT WIS DIS */
      set_stats(({ 15, 13, 19,  3,  3, 70 })); /* Set his stats */
      set_hp(1000);           /* Heal him fully */
      
      set_chat_time(10);      /* Set the time between speaking    */
      add_chat("Go away!");   /* Add some lines to say (randomly) */
      add_chat("Who are you?");
      add_chat("Go hither, foul creature!");

      set_cchat_time(4);      /* Set some combat chat lines */
      add_cchat("This is that one, fatal mistake!");
      add_cchat("Prepare to die!");

      set_act_time(7);        /* Set some random actions */
      add_act("growl");
      add_act("grin");
   }

This really is the most basic monster you can possible make. There are much
more intersting features of monsters, such as making them do sequences of
actions, letting them react to the outside world etc., but I won't discuss
them here. Notice that I don't set the WEIGHT and VOLUME properties, so
they will be set to 70 Kg and 70 Ltr.

This monster is not very tough. Novices begin with their stats between 8
and 18. This is what the stats mean:

	- STR	Strength, determines how much one can carry or how hard a
		player can hit.
	- DEX	Dexterity, determines how good someone is in handling
		weapons.
	- CON	Constitution, determines the maximum number of hitpoints.
	- INT	Intelligence, determines the maximum number of mana.
	- WIS	Wisdom
	- DIS	Discipline, determines how quickly someone will wimp out.
		Someone with low DIS is a chicken, high DIS means she's bold.


ARMOUR.C
--------
Ofcourse you don't want your monsters to run around unprotected against the
violent players. Therefore you wish to give them good armours. On the other
hand: too many good armours will devaluate all armours. So, be reluctant in
making good armours. I think the general rule is this: don't make very good
armours, unless you make a very strong monster. Good armours should be tough
to obtain. Here is an example of a blue platemail:

   /* A blue platemail */

   inherit "/std/armour";

   #include "/sys/wa_types.h"       /* Weapon and armour types        */
   #include "/sys/formulas.h"       /* Some handy conversion formulas */
   #include "/sys/stdproperties.h"  /* Standard properties            */

   void
   create_armour()
   {
      set_name("platemail");
      set_short("blue platemail");
      set_long("The blue platemail is heavy and doesn't look magical.\n");

      set_default_armour(
         19,          /* Armour class */
         A_BODY,      /* Armour type  */
         0,           /* Armour/weapon modifier list, it can be use to modify */
		      /* the armour class towards different damage types      */
         0);          /* Object that defines wear and remove */

      add_prop(OBJ_I_WEIGHT, 11000); /* 11 Kg. Well, it is a platemail... */
      add_prop(OBJ_I_VOLUME,  1380); /* An iron platemail (see table)     */
      add_prop(OBJ_I_VALUE, F_VALUE_ARMOUR(19) + random(200) - 100);
                  /* Standard formula to calculate value with given ac */
   }

I think this platemail is selfexplanatory... It is a body armour, when worn
is provides a protection of ac 19, then the value is set to the standard
formula for an armour of ac class 19. The value is randomized a bit, so the
players will not be able to judge an armour by the price it has. With this
construction, it will be max 100 coins more or 100 coins less than it should
be.


WEAPON.C
--------
With these objects you can arm your monsters. The same goes here, as with
the armours: don't make too strong weapons, for it will cause inflation.
If you have a good reason to make a strong weapon, then don't. There are
probably hundreds of other people with similar ideas, and they all have
the same conviction that you have. So, stick to bad/mediocre/fairly good
weapons. Don't forget: there are more ways to make a good weapon other than
making its weapon class high; you could make for example an aluminum sword,
which would be very light.

   /* A copper katana */

   inherit "/std/weapon";

   #include "/sys/wa_types.h"       /* Weapon and armour types        */
   #include "/sys/formulas.h"       /* Some handy conversion formulas */
   #include "/sys/stdproperties.h"  /* Standard properties            */

   void
   create_weapon()
   {
      set_name("katana");
      set_short("copper katana");
      set_long("The copper katana looks like it can slice things easily.\n");

      set_default_weapon(
         19,      /* Weapon hit (see /sys/wa_types for max.)      */
         33,      /* Penetration (see same file for max)          */
         W_SWORD, /* Weapon type                                  */
         W_SLASH | W_IMPALE,  /* Damage type                      */
         W_NONE,  /* A one hand weapon, free to choose which hand */
         0);      /* The object defining the (un)wield functions  */

      add_prop(OBJ_I_WEIGHT, 5000); /* 5.0 Kg   */
      add_prop(OBJ_I_VOLUME,  560); /* 0.56 Ltr */
      add_prop(OBJ_I_VALUE,F_VALUE_WEAPON(19) + random(130) - 65);
                  /* Standard formula to calculate value with given hit */
   }


VBFC
----
This is one of the neatest new possibilities of 3.0. Instead of filling in
what a function needs, you fill in "@@my_func@@", where my_func() returns the
desired value. This means that my_func() can return a value that is dependant
of the status when the function is called. You only need to give the latter
"@@" if you want to imbed the string in another string, like:

      "Hi @@my_name_func@@, how are you?\n"

It is possible to specify arguments that should be passed to the function,
as well as an object in which the function should be called. To be more
exact, one can do: "@@my_func:object_to_call|arg1|arg2...|argN@@". If
you don't provide the object_to_call, this_object() is assumed.

Let's give a simple example; in the previous weapon, I change the set_long
line to this:

      set_long("@@dependant_long");

And I add this function to the code:

   string
   dependant_long()
   {
      /* Check if the environment of the weapon is human */
      if (environment(this_object())->query_race() == "human")
         return "The copper katana has a firm grip in human hands\n";
      else
         return "The copper katana looks like a standard weapon.\n";
   }

Every time someone examines the object, the function dependant_long() will be
called. This function then checks if its carrier (if any) is of the human
race. If so, another long than usual is returned. Virtually all the standard
set_... functions support the usage of VBFC. It is a very powerful feature,
which will often come in handy.

Very important is the difference between these two lines:

    (1)     set_long(dependant_long());
and
    (2)     set_long("@@dependant_long");

If you can explain the difference, you have understood VBFC truly. Let me
give it a try: (1) sets the long description to whatever dependant_long()
returns on the moment that set_long() is done. This will always be "The
copper katana looks like a standard weapon.\n". The long description will
not change after the set_long(), and even if dependant_long() changes, it
will not affect the long description.
(2) however, sets the true long description to the string "@@dependant_long",
which will make the internal function of an object that really returns the
long description evaluate the function dependant_long() each time it is
called. This way the long description will be different under different
circumstances.

Sometimes VBFC contructions do not work, e.g. sometimes if you use

       write(QCTNAME(this_player()) + " smiles.\n");

you will get to see a weird string. In that case, use the function
process_string() to fix things:

       write(process_string(QCTNAME(this_player())) + " smiles.\n");"

The functions write() and tell_object() sends their messages exactly as they
where given, the weird string you get. The function say() on the other hand
handles VBFC nicely. 

The whole VBFC effect is destroyed by using process_string, though. To get
back at our previous examples:

            set_long(dependant_long());
and
            set_long(process_string("@@dependant_long"));

have exactly the same effect. The outcome of the process_string() will
always be "The copper katana looks like a standard weapon.\n" and the
long description will be set to that string.

It is very easy to use VBFC too much. As a rule of thumb one could use that
if the outcome of a function is can be evaluated immediately, one should use
a function. When the evaluation has to take place somewhere in the future,
VBFC can be used.

Note that VBFC is not implemented in the driver, so if you want your
functions also to be able to use VBFC, you will have to make sure that they
can. Let's say you want to make a function that turns on a remote-control.
You would make the code something like this:

        void
	set_remote(string arg)
        {
           global_remote = arg;
        }

        string
	query_remote()
        {
           return check_call(global_remote);
        }

The check_call() function handles the VBFC part, so you don't have to worry
about that yourself.


Skills
------
There are dozens of skills, and you can find all of them in the file
/sys/ss_types.h. This is how you would use skills in your code:

    include "/sys/ss_types.h"

    /* This function returns 1 if the player can climb good enough */
    int
    try_climb(object pl)
    {
       if (pl->query_skill(SS_CLIMB) > 10)
          return 1;
       else
          return 0;
    }

It is not mandatory, but use the skills that players can have as often as
you can. Make object values dependant of the value of SS_TRADING, or make
a dog more aggressive when he encounters someone with SS_ANIMAL_HANDLING low.
If the skills are used often the players will be more interested in raising
them. Another way to use skills is to use tasks. This is more complicated,
but gives you more freedom. To explain tasks adequately would take a lot of
words, but luckily you can do "man tasks" and read all about them in great
detail.


Debugging
---------
If you are new at coding in LPC, you are bound to make errors in your code.
If you are not new at it, you will still make errors. They just slip into
the code. Luckily the gamedriver offers you a way to debug your programs.

When you have edited an object, say "bulb.c", you want to see your result.
To do this, you do "clone bulb". If all goes well, you will find that you
are carrying a bulb on you. Check it, to see if it works fine. I.e. can
you examine it, can you drop it, can you get it, etc. etc.

If you made a mistake in the code, you will get a message like "Error in
line 23: syntax error". Beside that, an error message will be written to
a log file. Which log file, depends on the directory that "bulb.c" is in.
If it is in your directory, you can do "errlog" to see your error logfile.
If the file is in a domain directory, you can do "errlog Domain" to check
that errorlog. The last few errors on the bottom are probably the ones
that made the error occur. In some muds the errors of the gamedriver are
also logged to a file. Those errors tell usually more about the error you
made, but also give a lot of other errors that came with it. So, more
searchwork for you. On Genesis you can examine that file with the command
"tail /lplog".

All errors are of the form:

	<object filename> line <nr>: <error message>

If you look at the errorlog, usually a number of errors are given. It is
wise to solve the highest new one first, because all the lower errors
might exist due to it. For example: if you forget one bracket (")"),
the gamedriver will claim not to know any variables in other functions
below. Also the line number an best be interpreted in a wide sense:
"the error must be around that line number". It is very well possible
that a forgotten semicolon (";") generates an error a few lines lower.

Let's have a few error messages, and see what causes them:

	"d/Genesis/fatty/donut.c line 28:Illegal LHS"

		The LHS stands for Left Hand Statement. Line 28 contains
		an equal-sign ("="), the part on the left is not of the
		same type as the part on the right. So, you may not make
		them equal.


	"d/Genesis/fatty/donut.c line 12:Newline in string"

		On that line, a string was declared, but not closed with
		a doublequote ("). E.g. set_short("donut);


	"d/Genesis/fatty/donut.c line 186:Variable SS_EATING not declared !"

		This one is clear. On line 186 a variable is used that has
		not been declared previously. Don't be misled by the name
		`variable'. It can well be that you forgot to #include some
		file that does define it. Since #defines are usually names
		consisting of only capitals, we probably forgot to #include
		or #define something here.


	"d/Genesis/fatty/donut.c line 20:Return type not matching: "int ""

		At that line you return a value that is not of the same
		type as the function promised to return in its declaration.
		Either adjust the declaration, or return something of the
		correct type.


	"d/Genesis/fatty/donut.c line 27:Wrong number of arguments to eat"

		The function eat() was not declared to get the number of
		arguments given to it on line 27. That might be an error
		of you, but perhaps you want to give not always the same
		number of arguments. In that case you forgot to give the
		function the following declaration: "varargs eat(...)".


	"d/Genesis/fatty/donut.c line 59:Undefined function smear"

		There are two possibilities: you forgot to define the
		function (or mistyped its name), or you did define it,
		but below the function that calls it. If you don't declare
		functions with types, the gamedriver is not picky about
		that last fault, but if you do, you should either move
		the declaration of the function above the call to it, or
		place a prototype (e.g. "int smear();") on top of the file.


	"d/Genesis/fatty/donut.c line 100:syntax error"

		This is a mean one. A syntax error means to say that the
		the syntaxrules of LPC were violated. This could mean that
		you forgot a semicolon, bracket or brace ("}") somewhere.
		It could also mean something completely different, like
		you put to "+"-signs next to each other, without something
		like a number or text between them. Look closely at the lines
		preceding the line of the error.


	"d/Genesis/fatty/donut.c line 85:Illegal to redefine nomask function"

		The name of the function on that line has already been used
		before. Probably in the object it inherits. Whoever wrote
		that object didn't want us to redefine that function, and
		declared it "nomask".


	"d/Genesis/fatty/donut.c line 85:Missing type for argument"

		If the functions are declared with types, their arguments
		should also have types. E.g. "void foo_gnu(object gnat)".


	"d/Genesis/fatty/donut.c line 93:Bad type for argument 1 ( object
								 vs string )

		The function called in line 93 was declared to receive a
		different type of argument then what was given to it.
		E.g. "foo_gnu("bar");", where foo_gnu() was defined as
		above.



Interesting documents:
----------------------
You can do "man <subject>" if you want to, "more /doc/man/general/<subject>"
is also possible.

/doc/man/general/

   LPC             A more exact definition of the language.
   meet_people     Explains the usage of the met/nonmet feature of 3.0.
   experience      Explains how experience works.
   guilds          Rules about building a guild.
   healing         Rules about healing.
   spells          Rules concerning spells.
   tasks           Explains how to use tasks.
   values          How to give values to objects.
   xp_scale        How much experience can one give for a quest?





Constants for different metals
------------------------------
The following table is of course utterly silly, because nobody is really
going to use it. You could use it to get an indication of the weight
differences, though. It is not obliged to make things look extremely real,
but to get a feeling, here are the actual values for the Rho of several
kinds of metal, where Weight = Volume x Rho.

   Metal            Rho            Alloy           Rho
--------------------------      -------------------------
   Aluminum         2.7            Bronze           8.9
   Chrome           7.1            Cast iron        7.3
   Gold            19.3            Brass            8.5
   Lead            11.3            Steel            6.9
   Magnesium        1.7            Stainless steel  7.8
   Copper           8.9
   Platinum        21.4
   Tin              7.3    Example: If you think your gold bar measures
   Iron             7.9             about 1.5 ltr, it will weigh about
   Silver          10.5             1.5*19.3 = 29 Kg.
   Zinc             6.9
