Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/doc/KURS/COMMENTS b/doc/KURS/COMMENTS
new file mode 100644
index 0000000..4ef9ca9
--- /dev/null
+++ b/doc/KURS/COMMENTS
@@ -0,0 +1,75 @@
+ BEMERKUNGEN ZUM THEMA SPIELVERDERBER
+ ------------------------------------
+
+ Eine konsequente Verwendung der Worte Moerder, Verbrecher,
+ o.ae. verkennt den wahren Charakter:
+ Es sind einfach nur Spielverderber, und sollten auch
+ dementsprechend behandelt werden.
+
+ Im Moment wird noch nicht gespielt.
+ Ergo gibt es noch keine Spielverderber.
+
+ Wenn es denn welche gibt, wie geht man mit ihnen um ?
+ - Man spielt nicht mehr mit Ihnen.
+ - Man nimmt ihnen den Spass, sodass sie von selber
+ aufhoeren mitzuspielen, bzw. anderen das Spiel
+ zu verderben.
+
+ Vorschlaege(!) fuer Massnahmen:
+
+ - Belegen mit Fluechen.
+
+ (zB Erkaeltungen, oder zeitweiliger Verlust der Faehigkeit,
+ Waffen zu tragen, Schlechtes Gewissen, dass man immer wieder
+ daran erinnert wird, was man boeses getan hat. etc.)
+ Wer hat weitere Ideen ??
+
+ Vorteile:
+
+ + Die Bestrafung erfolgt innerhalb des Spieles.
+ + Durch die Dauer kann die Strafe fein dosiert
+ werden.
+
+ Nachteil:
+
+ + Magier sind auf diese Weise schwer zu
+ bestrafen.
+
+
+ - Geld oder XP wegnehmen.
+
+ - Herabstufung. Nur im NOTFALL
+
+ - Aussschluss vom Spiel. Nur im AEUSSERSTEN NOTFALL
+
+
+ Wer ein Spielverderber ist, entscheidet im allgemeinen
+ die Gemeinschaft der Spielenden. Deshalb darf es keine
+ fatalen Eingriffe in das Spiel durch die Entscheidung
+ einzelner Spieler geben!
+
+ BEMERKUNGEN ZUM THEMA FLEISS VON MAGIERN
+ ----------------------------------------
+
+ Wenn ein Magier selten im Spiel ist, heisst das nicht,
+ dass er sich, wenn er einmal da ist, um so staerker
+ bemerkbar machen muss.
+
+
+ BEMERKUNGEN ZU GENAUEREN REGELN
+ -------------------------------
+
+ Man sollte sich nicht an irgendwelchen Zahlen (wiz_levels),
+ Verordnungen, Geschaeftsordnugnen etc. festhalten, sondern sich
+ immer vor Augen halten, dass es sich im ein Spiel handelt.
+ Es haben sich Leute zusammengefunden, um miteinander Spass zu
+ haben. Dieses Spiel ist keine so komplexe Gesellschaft wie die
+ reale; deshalb sollte es auch keiner so komplexen Regeln
+ beduerfen.
+
+ Olpp, Sheriff des MorgenGrauens
+ Rumata, MudAdm des MorgenGrauens
+
+ P.S.:
+ Kommentare und weitere Vorschlaege sind herzlich
+ willkommen.
diff --git a/doc/KURS/LPC-KURS/Contents b/doc/KURS/LPC-KURS/Contents
new file mode 100644
index 0000000..0dd4efb
--- /dev/null
+++ b/doc/KURS/LPC-KURS/Contents
@@ -0,0 +1,13 @@
+ LPC Basics
+ Written by Descartes of Borg
+ 23 april 1993
+
+Introduction
+Chapter 1: Introduction to the Coding Environment
+Chapter 2: The LPC Program
+Chapter 3: LPC Data Types
+Chapter 4: Functions
+Chapter 5: The Basics of Inheritance
+Chapter 6: Variable Handling
+Chapter 7: Flow Control
+Chapter 8: The Data Type Object
diff --git a/doc/KURS/LPC-KURS/Introduction b/doc/KURS/LPC-KURS/Introduction
new file mode 100644
index 0000000..2e3c7ff
--- /dev/null
+++ b/doc/KURS/LPC-KURS/Introduction
@@ -0,0 +1,106 @@
+ LPC Basics
+ Written by Descartes of Borg
+ 23 april 1993
+
+
+ INTRODUCTION
+ This manual, how to use it, and its terms
+
+I have seen a lot of requests lately on USENET for LPC manuals. In addition,
+the immortals on my mud have been telling how good the building documentation
+of Nightmare is, but that there was just no adequate explanation of the
+LPC programming language. So I decided to try my hand at writing a manual.
+Some things you should keep in mind.
+LPC is a very easy programming language to learn, and it has real
+value in that place most of us know as the real world. I began playing
+muds in 1991, and in the space of a month created an unimpressive area
+and musician's guild on the original Bates College MUD called Orlith.
+After that, I moved to Los Angeles for a year and had no contact with
+mudding or computers. In June of 1992, I was back on the internet and
+a wizard of Igor. In September of 1992 I began coding the Nightmare
+mudlib for our use, and then later decided to distribute it due to there
+not being any mudlibs for MudOS at the time that a person could just throw
+up a running mud with (now, that of course is not the case :)).
+So, I have been doing serious coding for less than a year. As a
+Philosophy major in a world of Computer Science majors, I just want to
+make clear that it is not at all required that you have ever done anything
+with your computer than log into a mud in order for you to really come
+to understand LPC coding. This manual makes the following assumptions:
+Someone has taught you basic UNIX commands like ls, cd, mkdir, mv, rm, etc.
+You know how to enter your mud's editor and write a file. No other
+assumptions are made. If you know C, you are handicapped in that LPC
+looks a lot like C, but it is not C. Your preconceptions about
+modular programming development will be a hinderence you will have to
+overcome. If you have never heard of the C programming language (like
+me in May of 1991), then you are only missing an understanding of the
+simple constructs of C like the flow of program execution and logical
+operators and such. So a C guru has no real advantage over you, since
+what they know from C which is applicable to LPC is easy to pick up.
+The stuff they know about C which makes them a guru is irrelevant to
+LPC.
+
+The chapters of this manual are meant to be read in order. Starting with
+the introduction, going sequentially through the chapter numbers as
+ordered in the contents file. Each chapter begins with a paragraph or
+two explaining what you should have come to understand by that point
+in your studies. After those introductory paragraphs, the chapter then
+begins to discuss its subject matter in nauseating detail. At the end
+of the chapter is a briefly worded summary of what you should understand
+from that chapter if I have been successful. Following that may or may
+not be some sidenotes relevant to the subject at hand, but not necessary
+to its understanding.
+
+If at any time you get to a chapter intro, and you have read the preceeding
+chapters thoroughly and you do not understand what it says you should
+understand by that point, please mail me! Clearly, I have failed at that
+point and I need to know where it is I have gone wrong so I can revise
+it properly. Similarly, if you do not understand what the chapter summary
+says you should, please mail me. If your mumud is on the MudOS intermud
+system, mail descartes@nightmare. Otherwise mail borg@hebron.connected.com.
+
+Some basic terms this manual uses:
+driver-
+This is the C program which is the game. It accepts incoming sockets
+(links to other computers), interprets LPC code defined by the mudlib,
+keeps mud objects in memory, makes periodic attempts to clean unused
+mud objects from memory, makes periodic calls to objects, and so on.
+
+mudlib-
+LPC code which defines the world in which you are in. The driver of itself
+is not a game. It is just a program which allows the creation of a
+multi-user environment. In some sense, the driver is like an LPC
+compiler, and the mudlib is like a compiler's library (a very loose
+analogy). The mudlib defines basic objects which will likely be used
+over and over again by people creating in the mud world. Examples of
+such objects are /std/room (or /room/room), /std/user.c (or /obj/player.c),
+and so on.
+
+area or castle:
+Specific creator coded objects which often use a feature of LPC called
+inheritance to make use of the properties of basic mudlib objects and
+turn them into specific objects to be used by players in the game
+
+object:
+a room, a weapon, a monster, a player, a bag, etc. More importantly,
+every individual file with a .c extension is an object. Objects are
+used in different ways. Objects like /std/living.c are inherited by
+objects like monster.c and user.c. Others are cloned, which means a
+duplicate of that code is loaded into memory. And still others are
+simply loaded into memory to be referenced by other objects.
+
+native and compat:
+these two terms refer to two popular flavours of drivers. Native mode
+mudlibs make use of on the design of LPMud driver 3.0 and later. You may
+have a 3.0 driver however, but have a 2.4.5 style mudlib. This is what
+is meant by compat mode. Mudlibs which are native mode are any for
+MudOS, CD, and LPMud mudlibs that
+are listed as native. Compat mudlibs are any LPMud mudlib before 3.0 and
+those which are 3.* compat mudlibs. I believe Amylaar's is compat.
+[ Not true, Amylaar supports native and compat mudlibs, MorgenGrauen
+ is native - Boing ]
+
+Good Luck!
+George Reese
+(Descartes of Borg)
+12 july 1993
+borg@hebron.connected.com
diff --git a/doc/KURS/LPC-KURS/chapter1 b/doc/KURS/LPC-KURS/chapter1
new file mode 100644
index 0000000..6f233d0
--- /dev/null
+++ b/doc/KURS/LPC-KURS/chapter1
@@ -0,0 +1,90 @@
+ LPC Basics
+ Written by Descartes of Borg
+ first edition: 23 april 1993
+ second edition: 25 may 1993
+
+CHAPTER 1: Introduction to the Coding Environment
+
+1.1 UNIX file structure
+LPMuds use basic UNIX commands and its file structure. If you know
+UNIX commands already, then note (with a few exceptions) options are
+not available to the commands. Like DOS, UNIX is heirarchical. The
+root directory of which all directories are sub-directories is called
+root(/). And from those sub-directories you may have further
+sub-directories. A directory may be referred to in two different ways:
+1) by its full name, or absolute name, or 2) by its relative name.
+Absolute name refers to the directory's full path starting from / winding
+down the directory tree until you name the directory in question. For
+example:
+
+ /players/descartes/obj/monster
+
+refers to the directory monster which is a sub-directory of obj which
+is a sub-directory of descartes which is a sub-directory of players
+which is a sudirectory of /.
+
+The relative name refers to the name relative to another directory.
+The above example is called monster relative to /players/descartes/obj,
+but it is also called obj/monster relative to /players/descartes,
+descartes/obj/monster relative to /players, and finally
+players/descartes/obj/monster relative to /. You can tell the
+difference between absolute names and relative names because absolute
+names always start with /. In order to know exactly which directory
+is being named by a relative name, you naturally must know what
+directory it is relative to.
+
+A directory contains sub-directories and files. LPMuds only use text files
+inside the mudlib. Like directories, files have both absolute and
+relative names. The most basic relative name is often referred to as the file
+name, with the rest of the absolute name being referred to as the path. So,
+for the file: /players/descartes/castle.c, castle.c is the file name, and
+/players/descartes is the path.
+
+On some muds, a file with a file name beginning with a . (like .plan) is
+not visible when you list files with the regular file listing command.
+
+1.2 UNIX Commands
+Along with the UNIX file structure, LPMuds use many UNIX commands. Typical
+UNIX commands on most muds are:
+pwd, cd, ls, rm, mv, cp, mkdir, rmdir, more, head, cat, ed
+If you have never before seen UNIX commands, you probably are thinking this
+is all nonsense. Well, it is, but you got to use them. Before getting
+into what they mean though, first a discussion of current directory.
+If you know DOS, then you know what a current working directory is.
+At any given point, you are considered to be "in" some directory. This
+means that any relative file or directory names you give in UNIX commands
+are relative to that directory. For example, if my current directory is
+/players/descartes and I type "ed castle.c" (ed is the command to edit),
+then it assumes I mean the file /players/descartes/castle.c
+
+pwd: shows you your current working directory
+cd: changes your current working directory. You may give either relative
+ or absolute path names. With no arguments, it changes to your home
+ directory.
+ls: lists all files in the directory named. If no directory is named,
+ it lists the files of the current working directory
+rm: deletes the file named
+mv: renames the file named
+cp: copies the file named
+mkdir: makes a new directory
+rmdir: deletes a directory. All files must have been first removed.
+more: pages the file named so that the file appears on your screen one
+ page at a time.
+cat: shows the whole file to you at once
+head: shows you the first several lines of a file
+tail: shows you the last several lines of a file
+ed: allows you to edit a file using the mud editor
+
+1.3 Chapter Summary
+UNIX uses a heirarchical file structure with the root of the tree being
+named /. Other directories branch off from that root directory and
+in turn have their own sub-directories. All directories may contain
+directories and files. Directories and files are referred to either
+by their absolute name, which always begins with /, or by their relative
+name which gives the file's name relative to a particular directory.
+In order to get around in the UNIX files structure, you have the
+typical UNIX commands for listing files, your current directory, etc.
+On your mud, all of the above commands should have detailed help commands
+to help you explore exactly what they do. In addition, there should
+be a very detailed file on your mud's editor. If you are unfamiliar
+with ed, you should go over this convoluted file.
diff --git a/doc/KURS/LPC-KURS/chapter2 b/doc/KURS/LPC-KURS/chapter2
new file mode 100644
index 0000000..f9ad566
--- /dev/null
+++ b/doc/KURS/LPC-KURS/chapter2
@@ -0,0 +1,195 @@
+ LPC Basics
+ Written by Descartes of Borg
+ first edition: 23 april 1993
+ second edition: 16 june 1993
+
+CHAPTER 2: The LPC Program
+
+2.1 About programs
+The title of this chapter of the textbook is actually poorly named, since
+one does not write programs in LPC. An LPC coder instead writes *objects*.
+What is the difference? Well, for our purposes now, the difference is
+in the way the file is executed. When you "run" a program, execution
+begins at a definite place in the program. In other words, there
+is a place in all programs that is noted as the beginning where program
+execution starts. In addition, programs have definite end points,
+so that when execution reaches that point, the execution of the program
+terminates. So, in short, execution of a program runs from a definite
+beginning point through to a definite end point. This is not so with
+LPC objects.
+
+With muds, LPC objects are simply distinct parts of the C program which
+is running the game (the driver). In other words, execution of the mud
+program begins and ends in the driver. But the driver in fact does
+very little in the way of creating the world you know when you play
+a mud. Instead, the driver relies heavily on the code created in LPC,
+executing lines of the objects in the mud as needed. LPC objects thus
+have no place that is necessarily the beginning point, nor do they
+have a definite ending point.
+
+Like other programming languages, an LPC "program" may be made up of
+one or more files. For an LPC object to get executed, it simple
+needs to be loaded into the driver's memory. The driver will call lines
+from the object as it needs according to a structure which will be
+defined throughout this textbook. The important thing you need to
+understand at this point is that there is no "beginning" to an LPC
+object in terms of execution, and there is no "end".
+
+2.2 Driver-mudlib interaction
+As I have mentioned earlier, the driver is the C program that runs on
+the host machine. It connects you into the game and processes LPC code.
+Note that this is one theory of mud programming, and not necessarily
+better than others. It could be that the entire game is written in C.
+Such a game would be much faster, but it would be less flexible in
+that wizards could not add things to the game while it was running. This
+is the theory behind DikuMUDs. Instead, LPMUDs run on the theory that
+the driver should in no define the nature of the game, that the nature
+of the game is to be decided by the individuals involved, and that
+you should be able to add to the game *as it is being played*. This
+is why LPMUDs make use of the LPC programming language. It allows
+you to define the nature of the game in LPC for the driver to read and
+execute as needed. It is also a much simpler language to understand
+than C, thus making the process of world creation open to a greater
+number of people.
+
+Once you have written a file in LPC (assuming it is corrent LPC ), it justs
+sits there on the host machine's hard drive until something in the game
+makes reference to it. When something in the game finally does make
+reference to the object, a copy of the file is loaded into memory and
+a special *function* of that object is called in order to initialize
+the values of the variables in the object. Now, do not be concerned
+if that last sentence went right over your head, since someone brand
+new to programming would not know what the hell a function or a variable
+is. The important thing to understand right now is that a copy of the
+object file is taken by the driver from the machine's hard drive and
+stored into memory (since it is a copy, multiple versions of that
+object may exist). You will later understand what a function is, what
+a variable is, and exactly how it is something in the game made reference
+to your object.
+
+2.3 Loading an object into memory
+Although there is no particular place in an object code that must exist
+in order for the driver to begin executing it, there is a place for which
+the driver will search in order to initialize the object. On compat
+drivers, it is the function called reset(). On native muds it is the
+function called create(). [ MorgenGrauen is native - Boing ]
+
+LPC objects are made up of variables (values which can change) and
+functions which are used to manipulate those variables. Functions
+manipulate variables through the use of LPC grammatical structures,
+which include calling other functions, using externally defined
+functions (efuns), and basic LPC expressions and flow control
+mechanisms.
+
+Does that sound convoluted? First lets start with a variable. A
+variable might be something like: level. It can "vary" from sitation
+to situation in value, and different things use the value of the player's
+level to make different things happen. For instance, if you are a
+level 19 player, the value of the variable level will be 19. Now
+if your mud is on the old LPMud 2.4.5 system where levels 1-19 are
+players and 20+ are wizards, things can ask for your level value to
+see if you can perform wizard type actions. Basically, each object
+in LPC is a pile of variables with values which change over time.
+Things happen to these objects based on what values its variables
+hold. Often, then things that happen cause the variables to change.
+
+So, whenever an object in LPC is referenced by another object currently
+in memory, the driver searches to see what places for values the
+object has (but they have no values yet). Once that is done, the driver
+calls a function in the object called reset() or create() (depending
+on your driver) which will set up the starting values for the object's
+variables. It is thus through *calls* to *functions* that variable
+values get manipulated.
+
+But create() or reset() is NOT the starting place of LPC code, although
+it is where most LPC code execution does begin. The fact is, those
+functions need not exist. If your object does just fine with its
+starting values all being NULL pointers (meaning, for our purposes
+here, 0), then you do not need a create() or reset() function. Thus
+the first bit of execution of the object's code may begin somewhere
+completely different.
+
+Now we get to what this chapter is all about. The question: What
+consists a complete LPC object? Well, an LPC object is simply
+one or more functions grouped together manipulating 0 or more
+variables. The order in which functions are placed in an object
+relative to one another is irrelevant. In other words:
+
+-----
+void init() { add_action("smile", "smile"); }
+
+void create() { return; }
+
+int smile(string str) { return 0; }
+-----
+
+is exactly the same as:
+
+-----
+void create() { return; }
+
+int smile(string str) { return 0; }
+
+void init() { add_action("smile", "smile"); }
+_____
+
+Also important to note, the object containing only:
+
+-----
+void nonsense() {}
+-----
+
+is a valid, but trivial object, although it probably would not interact
+properly with other objects on your mud since such an object has no
+weight, is invisible, etc..
+
+2.4 Chapter summary
+LPC code has no beginning point or ending point, since LPC code is used
+to create objects to be used by the driver program rather than create
+individual programs. LPC objects consist of one or more functions whose
+order in the code is irrelevant, as well as of zero or more variables whose
+values are manipulated inside those functions. LPC objects simply sit
+on the host machine's hard driver until referenced by another object in
+the game (in other words, they do not really exist). Once the object
+is referenced, it is loaded into the machine's memory with empty
+values for the variables. The function reset() in compat muds or
+create() in native muds is called in that object if it exists to allow
+the variables to take on initial values. Other functions in the object
+are used by the driver and other objects in the game to allow interaction
+among objects and the manipulation of the LPC variables.
+
+A note on reset() and create():
+create() is only used by muds in native mode (see the textbook Introduction
+for more information on native mode vs. compat mode). It is only used
+to initialize newly referenced objects.
+
+reset() is used by both muds in compat mode and native mode. In compat
+mode, reset() performs two functions. First, it is used to initialize
+newly referenced objects. In addition, however, compat mode muds use
+reset() to "reset" the object. In other words, return it to its initial
+state of affairs. This allows monsters to regenerate in a room and doors
+to start back in the shut position, etc.. Native mode muds use reset()
+to perform the second function (as its name implies).
+
+So there are two important things which happen in LP style muds which
+cause the driver to make calls to functions in objects. The first is
+the creation of the object. At this time, the driver calls a function
+to initalize the values in the object. For compat mode muds, this
+is performed by the function named reset() (with an argument of 0,
+more on this later though). For muds running in native mode, this is
+performed by the function create().
+
+The second is the returning of the room to some base state of affairs.
+This base set of affairs may or may not be different from the initial
+state of affairs, and certainly you would not want to take up time
+doing redundant things (like resetting variables that never change).
+Compat mode muds nevertheless use the same function that was used to
+create the object to reset it, that being reset(). Native mode muds,
+who use create() to create the room, instead use reset() to reset it.
+All is not lost in compat mode though, as there is a way to tell the
+difference between creation and resetting. For reset purposes, the
+driver passes either 1 or the reset number as an argument to reset()
+in compat mode. Now this is meaningless to you now, but just keep in
+mind that you can in fact tell the difference in compat mode. Also
+keep in mind that the argment in the creation use of reset is 0 and
+the argument in the reset use is a nonzero number.
diff --git a/doc/KURS/LPC-KURS/chapter3 b/doc/KURS/LPC-KURS/chapter3
new file mode 100644
index 0000000..f7e89a4
--- /dev/null
+++ b/doc/KURS/LPC-KURS/chapter3
@@ -0,0 +1,185 @@
+ LPC Basics
+ Written by Descartes of Borg
+ first edition: 23 april 1993
+ second edition: 17 june 1993
+
+CHAPTER 3: LPC Data Types
+
+3.1 What you should know by now
+LPC object are made up of zero or more variables manipulated by one or
+more functions. The order in which these functions appear in code is
+irrelevant. The driver uses the LPC code you write by loading copies of
+it into memory whenever it is first referenced and additional copies
+through cloning. When each object is loaded into memory, all the variables
+initially point to no value. The reset() function in compat muds, and
+create() in native muds are used to give initial values to variables in
+objects. The function for creation is called immediately after the object
+is loaded into memory. However, if you are reading this textbook with no
+prior programming experience, you may not know what a function is or how
+it gets called. And even if you have programming experience, you may
+be wondering how the process of functions calling each other gets started
+in newly created objects. Before any of these questions get answered,
+however, you need to know more about what it is the functions are
+manipulating. You therefore should thouroughly come to know the concept
+behind LPC data types. Certainly the most boring subject in this manual,
+yet it is the most crucial, as 90% of all errors (excepting misplaced
+{} and ()) involve the improper usage of LPC data types. So bear through
+this important chapter, because it is my feeling that understanding this
+chapter alone can help you find coding much, much easier.
+
+3.2 Communicating with the computer
+You possibly already know that computers cannot understand the letters
+and numbers used by humans. Instead, the "language" spoken by computers
+consists of an "alphabet" of 0's and 1's. Certainly you know computers
+do not understand natural human languages. But in fact, they do not
+understand the computer languages we write for them either. Computer
+languages like BASIC, C, C++, Pascal, etc. are all intermediate
+languages. They allow you to structure your thoughts more coherently
+for translation into the 0's and 1's of the computer's languages.
+
+There are two methods in which translation is done: compilation and
+interpretation. These simply are differences betweem when the
+programming language is translated into computer language. With
+compiled languages, the programmer writes the code then uses a program
+called a compiler to translate the program into the computer's
+language. This translation occurs before the program is run. With
+interpreted languages however, the process of translation occurs as
+the program is being run. Since the translation of the program is
+occurring during the time of the program's running in interpreted
+languages, interpreted languages make much slower programs than
+compiled languages.
+
+The bottom line is, no matter what language you are writing in, at
+some point this has to be changed into 0's and 1's which can be
+understood by the computer. But the variables which you store in
+memory are not simply 0's and 1's. So you have to have a way in
+your programming languages of telling the computer whether or not
+the 0's and 1's should be treated as decimal numbers or characters or
+strings or anything else. You do this through the use of data types.
+
+For example, say you have a variable which you call 'x' and you give
+it the decimal whole number value 65. In LPC you would do this through
+the statement:
+
+-----
+x = 65;
+-----
+
+You can later do things like:
+
+_____
+write(x+"\n"); /* \n is symbolically represents a carriage return */
+y = x + 5;
+-----
+
+The first line allows you to send 65 and a carriage return to someone's screen.
+The second line lets you set the value of y to 70.
+The problem for the computer is that it does not know what '65' means when
+you tell it x = 65;. What you think of 65, it might think of as:
+00000000000000000000000001000001
+But, also, to the computer, the letter 'A' is represented as:
+00000000000000000000000001000001
+So, whenever you instruct the computer write(x+"\n");, it must have some
+way of knowing that you want to see '65' and not 'A'.
+
+The computer can tell the difference between '65' and 'A' through the use
+of data types. A data types simply says what type of data is being stored
+by the memory location pointed to by a given variable. Thus, each LPC
+variable has a variable type which guides conversions. In the example
+given above, you would have had the following line somewhere in the
+code *before* the lines shown above:
+
+-----
+int x;
+-----
+
+This one line tells the driver that whatever value x points to, it will
+be used as the data type "int", which is short for integer, or whole
+number. So you have a basic introduction into the reason why data types
+exist. They exist so the driver can make sense of the 0's and 1's that
+the computer is storing in memory.
+
+3.3 The data types of LPC
+All LPMud drivers have the following data types:
+
+void, status, int, string, object, int *, string *, object *, mixed *
+
+Many drivers, but not all have the following important data types which
+are important to discuss:
+
+float, mapping, float *, mapping *
+
+And there are a few drivers with the following rarely used data types
+which are not important to discuss:
+
+function, enum, struct, char
+
+3.4 Simple data types
+This introductory textbook will deal with the data types void, status,
+int, float, string, object, mand mixed. You can find out about the
+more complex data types like mappings and arrays in the intermediate
+textbook. This chapter deals with the two simplest data types (from the
+point of view of the LPC coder), int and string.
+
+An int is any whole number. Thus 1, 42, -17, 0, -10000023 are all type int.
+A string is one or more alphanumeric characters. Thus "a", "we are borg",
+"42", "This is a string" are all strings. Note that strings are always
+enclosed in "" to allow the driver to distinguish between the int 42 and
+the string "42" as well as to distinguish between variable names (like x)
+and strings by the same names (like "x").
+
+When you use a variable in code, you must first let the driver know
+what type of data to which that variable points. This process is
+called *declaration*. You do this at the beginning of the function
+or at the beginning of the object code (outside of functions before all
+functions which use it). This is done by placing the name of the data type
+before the name of the variable like in the following example:
+
+-----
+void add_two_and_two() {
+ int x;
+ int y;
+
+ x = 2;
+ y = x + x;
+}
+-----
+
+Now, this is a complete function. The name of the function is
+add_two_and_two(). The function begins with the declaration of an
+int variable named x followed by the declaration of an in variable
+named y. So now, at this point, the driver now has two variables which
+point to NULL values, and it expects what ever values end up there to be
+of type int.
+
+A note about the data types void and status:
+Void is a trivial data type which points to nothing. It is not used
+with respect to variables, but instead with respect to functions. You
+will come to understand this better later. For now, you need only
+understand that it points to no value.
+
+The data type status is a boolean data type. That is, it can only have
+1 or 0 as a value. This is often referred to as being true or false.
+
+3.5 Chapter summary
+For variables, the driver needs to know how the 0's and 1's the computer
+stores in memory get converted into the forms in which you intend them
+to be used. The simplest LPC data types are void, status, int, and string.
+You do not user variables of type void, but the data type does come
+into play with respect to functions. In addition to being used for
+translation from one form to the next, data types are used in determining
+what rules the driver uses for such operations as +, -, etc. For example,
+in the expression 5+5, the driver knows to add the values of 5 and 5
+together to make 10. With strings however, the rules for int addition
+make no sense. So instead, with "a"+"b", it appends "b" to the string "a"
+so that the final string is "ab". Errors can thus result if you mistakenly
+try to add "5"+5. Since int addition makes no sense with strings, the
+driver will convert the second 5 to "5" and use string addition. The final
+result would be "55". If you were looking for 10, you would therefore
+have ended up with erroneous code. Keep in mind, however, that in most
+instances, the driver will not do something so useful as coming up with
+"55". It comes up with "55" cause it has a rule for adding a string
+to an int, namely to treat the int as a string. In most cases, if you
+use a data type for which an operation or function is not defined
+(like if you tried to divide "this is" by "nonsense", "this is"/"nonsense"),
+the driver will barf and report an error to you.
diff --git a/doc/KURS/LPC-KURS/chapter4 b/doc/KURS/LPC-KURS/chapter4
new file mode 100644
index 0000000..4f44cdc
--- /dev/null
+++ b/doc/KURS/LPC-KURS/chapter4
@@ -0,0 +1,225 @@
+ LPC Basics
+ Written by Descartes of Borg
+ first edition: 23 april 1993
+ second edition: 22 june 1993
+
+CHAPTER 4: Functions
+
+4.1 Review
+By this point, you should be aware that LPC objects consist of functions
+which manipulate variables. The functions manipulate variables when they
+are executed, and they get executed through *calls* to those functions.
+The order in which the functions are placed in a file does not matter.
+Inside a function, the variables get manipulated. They are stored in
+computer memory and used by the computer as 0's and 1's which
+get translated to and from useable output and input through a device
+called data typing. String data types tell the driver that the
+data should appear to you and come from you in the form of alphanumeric
+characters. Variables of type int are represented to you as whole
+number values. Type status is represented to you as either 1 or 0.
+And finally type void has no value to you or the machine, and is not
+really used with variable data types.
+
+4.2 What is a function?
+Like math functions, LPC functions take input and return output.
+Languages like Pascal distinguish between the concept of proceedure abd
+the concept of function. LPC does not, however, it is useful to
+understand this distinction. What Pascal calls a proceedure, LPC
+calls a function of type void. In other words, a proceedure, or function
+of type void returns no output. What Pascal calls a function differs
+in that it does return output. In LPC, the most trivial, correct
+function is:
+
+-----
+void do_nothing() { }
+-----
+
+This function accepts no input, performs no instructions, and returns no
+value.
+
+There are three parts to every properly written LPC function:
+1) The declaration
+2) The definition
+3) The call
+
+Like with variables, functions must be declared. This will allow the
+driver to know 1) what type of data the function is returning as output,
+and 2) how many input(s) and of what type those input(s) are. The
+more common word for input is parameters.
+A function declaration therefore consists of:
+type name(parameter1, parameter2, ..., parameterN);
+The declaration of a function called drink_water() which accepts a string as
+input and an int as output would thus look like this:
+
+-----
+int drink_water(string str);
+-----
+
+where str is the name of the input as it will be used inside the function.
+
+The function definition is the code which describes what the function actually
+does with the input sent to it.
+The call is any place in other functions which invokes the execution of the
+function in question. For two functions write_vals() and add(), you thus
+might have the following bit of code:
+
+-----
+/* First, function declarations. They usually appear at the beginning
+ of object code.
+*/
+void write_vals();
+int add(int x, int y);
+
+/* Next, the definition of the function write_vals(). We assume that
+ this function is going to be called from outside the object
+*/
+void write_vals() {
+ int x;
+
+ /*N Now we assign x the value of the output of add() through a call */
+ x = add(2, 2);
+ write(x+"\n");
+}
+
+/* Finally, the definition of add() */
+int add(int x, int y) {
+ return (x + y);
+}
+-----
+
+Remember, it does not matter which function definition appears first in the
+code. This is because functions are not executed consecutively. Instead,
+functions are executed as called. The only requirement is that the
+declaration of a function appear before its definition and before the
+definition of any function which makes a call to it.
+
+4.3 Efuns
+Perhaps you have heard people refer to efuns. They are externally defined
+functions. Namely, they are defined by the mud driver. If you have
+played around at all with coding in LPC, you have probably found some
+expressions you were told to use like this_player(), write(), say(),
+this_object(), etc. look a lot like functions. That is because they are
+efuns. The value of efuns is that they are much faster than LPC functions,
+since they already exist in the binary form the computer understands.
+
+In the function write_vals() above, two functions calls were made. The first was to
+the functions add(), which you declared and defined. The second call, however,
+was to a function called write(), and efun. The driver has already declared
+and defined this function for you. You needs only to make calls to it.
+
+Efuns are created to hanldle common, every day function calls, to handle
+input/output to the internet sockets, and other matters difficult to be
+dealt with in LPC. They are written in C in the game driver and compiled
+along with the driver before the mud comes up, making them much faster
+in execution. But for your purposes, efun calls are just like calls
+made to your functions. Still, it is important to know two things of any
+efun: 1) what return type does it have, and 2) what parameters of what
+types does it take.
+
+Information on efuns such as input parameters and return types is often
+found in a directory called /doc/efun on your mud. I cannot
+detail efuns here, because efuns vary from driver to driver. However,
+you can often access this information using the commands "man" or "help"
+depending on your mudlib. For instance, the command "man write" would
+give you information on the write efun. But if all else fails,
+"more /doc/efun/write" should work.
+
+By looking it up, you will find write is declared as follows:
+
+-----
+void write(string);
+-----
+
+This tells you an appropriate call to write expects no return value and
+passes a single parameter of type string.
+
+4.4 Defining your own functions
+Although ordering your functions within the file does not matter, ordering
+the code which defines a function is most important. Once a function
+has been called, function code is executed in the order it appears
+in the function definition. In write_vals() above, the instruction:
+
+-----
+x = add(2, 2);
+-----
+
+Must come before the write() efun call if you want to see the appropriate
+value of x used in write().
+
+With respect to values returned by function, this is done through the "return"
+instruction followed by a value of the same data type as the function. In
+add() above, the instruction is "return (x+y);", where the value of (x+y)
+is the value returned to write_vals() and assigned to x. On a more
+general level, "return" halts the execution of a function and returns
+code execution to the function which called that function. In addition,
+it returns to the calling function the value of any expression that follows.
+To stop the execution of a function of type void out of order, use
+"return"; without any value following. Once again, remember, the data
+type of the value of any expression returned using "return" MUST be the
+same as the data type of the function itself.
+
+4.5 Chapter Summary
+The files which define LPC objects are made of of functions. Functions, in
+turn, are made up of three parts:
+ 1) The declaration
+ 2) The definition
+ 3) The call
+Function declarations generally appear at the top of the file before any
+defintions, although the requirement is that the declaration must appear
+before the function definition and before the definition of any function
+which calls it.
+Function definitions may appear in the file in any order so long as they
+come after their declaration. In addition, you may not define one function
+inside another function.
+Function calls appear inside the definition of other functions where you
+want the code to begin execution of your function. They may also appear
+within the definition of the function itself, but this is not recommended
+for new coders, as it can easily lead to infinite loops.
+
+The function definition consists of the following in this order:
+ 1) function return type
+ 2) function name
+ 3) opening ( followed by a parameter list and a closing )
+ 4) an opening { instructing the driver that execution begins here
+ 5) declarations of any variables to be used only in that function
+ 6) instructions, expressions, and calls to other functions as needed
+ 7) a closing } stating that the function code ends here and, if no
+ "return" instruction has been given at this point (type void functions
+ only), execution returns to the calling function as if a r"return"
+ instruction was given
+
+The trivial function would thus be:
+
+-----
+void do_nothing() {}
+-----
+
+since this function does not accept any input, perform any instructions, or
+return any output.
+
+Any function which is not of type void MUST return a value of a data type
+matching the function's data type.
+
+Each driver has a set of functions already defined for you called efuns
+These you need neither need to declare nor define since it has already
+been done for you. Furthermore, execution of these functions is faster
+than the execution of your functions since efuns are in the driver.
+In addition, each mudlib has special functions like efuns in that they
+are already defined and declared for you, but different in that they
+are defined in the mudlib and in LPC. They are called simul_efuns, or
+simulated efuns. You can find out all about each of these as they are
+listed in the /doc/efun directory on most muds. In addition many
+muds have a command called "man" or a "help" command which allows you
+simply to call up the info files on them.
+
+Note on style:
+Some drivers may not require you to declare your functions, and some
+may not require you to specify the return type of the function in its
+definition. Regardless of this fact, you should never omit this information
+for the following reasons:
+ 1) It is easier for other people (and you at later dates) to read your
+ code and understand what is meant. This is particularly useful
+ for debugging, where a large portion of errors (outside of misplaced
+ parentheses and brackets) involve problems with data types (Ever
+ gotten "Bad arg 1 to foo() line 32"?).
+ 2) It is simply considered good coding form.
diff --git a/doc/KURS/LPC-KURS/chapter5 b/doc/KURS/LPC-KURS/chapter5
new file mode 100644
index 0000000..29d2a0c
--- /dev/null
+++ b/doc/KURS/LPC-KURS/chapter5
@@ -0,0 +1,161 @@
+ LPC Basics
+ Written by Descartes of Borg
+ first edition: 23 april 1993
+ second edition: 01 july 1993
+
+CHAPTER 5: The Basics of Inheritance
+
+5.1 Review
+You should now understand the basic workings of functions. You should be
+able to declare and call one. In addition, you should be able to recognize
+function definitions, although, if this is your first experience with LPC,
+it is unlikely that you will as yet be able to define your own functions.
+There functions form the basic building blocks of LPC objects. Code
+in them is executed when another function makes a call to them. In making
+a call, input is passed from the calling function into the execution of
+the called one. The called function then executes and returns a value
+of a certain data type to the calling function. Functions which return
+no value are of type void.
+
+After examining your workroom code, it might look something like this
+(depending on the mudlib):
+
+-----
+inherit "/std/room";
+
+void create() {
+ ::create();
+ set_property("light", 2);
+ set_property("indoors", 1);
+ set("short", "Descartes' Workroom");
+ set("long", "This is where Descartes works.\nIt is a cube.\n");
+ set_exits( ({ "/d/standard/square" }), ({ "square" }) );
+}
+-----
+
+If you understand the entire textbook to this point, you should recognize
+of the code the following:
+ 1) create() is the definition of a function (hey! he did not declare it)
+ 2) It makes calls to set_property(), set(), and set_exits(), none
+ of which are declared or defined in the code.
+ 3) There is a line at the top that is no variable or function declaration
+ nor is it a function definition!
+
+This chapter will seek to answer the questions that should be in your head
+at this point:
+ 1) Why is there no declaration of create()?
+ 2) Where are the functions set_property(), set(), and set_exits() declared
+ and defined?
+ 3) What the hell is that line at the top of the file?
+
+5.2 Object oriented programming
+Inheritance is one of the properties which define true object oriented
+programming (OOP). It allows you to create generic code which can be used
+in many different ways by many different programs. What a mudlib does is
+create these generalized files (objects) which you use to make very specific
+objects.
+
+If you had to write the code necessary for you to define the workroom above,
+you would have to write about 1000 lines of code to get all the functionality
+of the room above. Clearly that is a waste of disk space. In addition,
+such code does not interact well with players and other rooms since every
+creator is making up his or her own functions to perform the functionality
+of a room. Thus, what you might use to write out the room's long description,
+query_long(), another wizard might be calling long(). This is the primary
+reason mudlibs are not compatible, since they use different protocols for
+object interaction.
+
+OOP overcomes these problems. In the above workroom, you inherit the
+functions already defined in a file called "/std/room.c". It has all
+the functions which are commonly needed by all rooms defined in it. When
+you get to make a specific room, you are taking the general functionality
+of that room file and making a unique room by adding your own function,
+create().
+
+5.3 How inheritance works
+As you might have guessed by now, the line:
+
+-----
+inherit "/std/room";
+-----
+
+has you inherit the functionality of the room "/std/room.c". By inheriting
+the functionality, it means that you can use the functions which have
+been declared and defined in the file "/std/room.c" In the Nightmare Mudlib,
+"/std/room.c" has, among other functions, set_property(), set(), and
+set_exits() declared and defined. In your function create(), you are
+making calls to those functions in order to set values you want your
+room to start with. These values make your room different from others, yet
+able to interact well with other objects in memory.
+
+In actual practice, each mudlib is different, and thus requires you to use
+a different set of standard functions, often to do the same thing. It is
+therefore beyond the scope of this textbook even to describe what
+functions exist and what they do. If your mudlib is well documented,
+however, then (probably in /doc/build) you will have tutorials on how
+to use the inheritable files to create such objects. These tutorials
+should tell you what functions exist, what input they take, the data
+type of their output, and what they do.
+
+5.4 Chapter summary
+This is far from a complete explanation of the complex subject of inheritance.
+The idea here is for you to be able to understand how to use inheritance in
+creating your objects. A full discussion will follow in a later textbook.
+Right now you should know the following:
+ 1) Each mudlib has a library of generic objects with their own general
+ functions used by creators through inheritance to make coding objects
+ easier and to make interaction between objects smoother.
+ 2) The functions in the inheritable files of a mudlib vary from mudlib
+ to mudlib. There should exist documentation on your mud on how to
+ use each inheritable file. If you are unaware what functions are
+ available, then there is simply no way for you to use them. Always
+ pay special attention to the data types of the input and the data
+ types of ay output.
+ 3) You inherit the functionality of another object through the line:
+
+-----
+inherit "filename";
+-----
+
+ where filename is the name of the file of the object to be inherited.
+ This line goes at the beginning of your code.
+
+Note:
+You may see the syntax ::create() or ::init() or ::reset() in places.
+You do not need fully to understand at this point the full nuances of this,
+but you should have a clue as to what it is. The "::" operator is a way
+to call a function specifically in an inherited object (called the scope
+resolution operator). For instance, most muds' room.c has a function
+called create(). When you inherit room.c and configure it, you are doing
+what is called overriding the create() function in room.c. This means
+that whenever ANYTHING calls create(), it will call *your* version and not
+the one in room.c. However, there may be important stuff in the room.c
+version of create(). The :: operator allows you to call the create() in
+room.c instead of your create().
+An example:
+
+-----
+#1
+
+inherit "/std/room";
+
+void create() { create(); }
+-----
+
+-----
+#2
+
+inherit "/std/room";
+
+void create() { ::create(); }
+-----
+
+Example 1 is a horror. When loaded, the driver calls create(), and then
+create() calls create(), which calls create(), which calls create()...
+In other words, all create() does is keep calling itself until the driver
+detects a too deep recursion and exits.
+
+Example 2 is basically just a waste of RAM, as it is no different from room.c
+functionally. With it, the driver calls its create(), which in turn calls
+::create(), the create() in room.c. Otherwise it is functionally
+exactly the same as room.c.
diff --git a/doc/KURS/LPC-KURS/chapter6 b/doc/KURS/LPC-KURS/chapter6
new file mode 100644
index 0000000..6a64215
--- /dev/null
+++ b/doc/KURS/LPC-KURS/chapter6
@@ -0,0 +1,333 @@
+ LPC Basics
+ Written by Descartes of Borg
+ first edition: 23 april 1993
+ second edition: july 5 1993
+
+CHAPTER 6: Variable Handling
+
+6.1 Review
+By now you should be able to code some simple objects using your muds standard
+object library. Inheritance allows you to use functions defined in those
+objects without having to go and define yourself. In addition,
+you should know how to declare your own functions. This
+chapter will teach you about the basic elements of LPC which will allow you to
+define your own functions using the manipulation of variables.
+
+6.2 Values and objects
+Basically, what makes objects on the mud different are two things:
+1) Some have different functions
+2) All have different values
+
+Now, all player objects have the same functions. They are therefore
+differentiated by the values they hold. For instance, the player
+named "Forlock" is different from "Descartes" *at least* in that they
+have different values for the variable true_name, those being
+"descartes" and "forlock".
+
+Therefore, changes in the game involve changes in the values of the objects
+in the game. Functions are used to name specific process for manipulating
+values. For instance, the create() function is the function whose
+process is specifically to initialize the values of an object.
+Within a function, it is specifically things called instructions which are
+responsible for the direct manipulation of variables.
+
+6.3 Local and global variables
+Like variables in most programming language, LPC variables may be declared
+as variables "local" to a specific function, or "globally" available
+to all functions. Local variables are declared inside the function which
+will use them. No other function knows about their existence, since
+the values are only stored in memory while that function is being executed.
+A global variable is available to any function which comes after its
+declaration in the object code. Since global variables take up RAM for
+the entire existence of the object, you should use them only when
+you need a value stored for the entire existence of the object.
+Have a look at the following 2 bits of code:
+
+-----
+int x;
+
+int query_x() { return x; }
+
+void set_x(int y) { x = y; }
+-----
+
+-----
+void set_x(int y) {
+ int x;
+
+ x = y;
+ write("x is set to x"+x+" and will now be forgotten.\n");
+}
+-----
+
+In the first example, x is declared outside of any functions, and therefore
+will be available to any function declared after it. In that example,
+x is a global variable.
+In the second example, x is declared inside the function set_x(). It
+only exists while the function set_x() is being executed. Afterwards,
+it ceases to exist. In that example, x is a local variable.
+
+6.4 Manipulating the values of variables
+Instructions to the driver are used to manipulate the values of variables.
+An example of an instruction would be:
+
+-----
+x = 5;
+-----
+
+The above instruction is self-explanatory. It assigns to the variable
+x the value 5. However, there are some important concepts in involved
+in that instruction which are involved in instructions in general.
+The first involves the concept of an expression. An expression is
+any series of symbols which have a value. In the above instruction,
+the variable x is assigned the value of the expression 5. Constant
+values are the simplest forms in which expressions can be put. A constant
+is a value that never changes like the int 5 or the string "hello".
+The last concept is the concept of an operator. In the above example,
+the assignment operator = is used.
+
+There are however many more operators in LPC, and expressions can get
+quite complex. If we go up one level of complexity, we get:
+
+-----
+y = 5;
+x = y +2;
+-----
+
+The first instruction uses the assignment operator to assign the value
+of the constant expression 5 to the variable y. The second one
+uses the assignment operator to assign to x the value of the expression
+(y+2) which uses the addition operator to come up with a value which
+is the sum of the value of y and the value of the constant expression 2.
+Sound like a lot of hot air?
+
+In another manner of speaking, operators can be used to form complex
+expressions. In the above example, there are two expressions in the
+one instruction x = y + 2;:
+ 1) the expression y+2
+ 2) the expression x = y + 2
+As stated before, all expressions have a value. The expression
+y+2 has the value of the sum of y and 2 (here, 7);
+The expression x = y + 2 *also* has the value of 7.
+So operators have to important tasks:
+ 1) They *may* act upon input like a function
+ 2) They evaluate as having a value themselves.
+Now, not all operators do what 1 does. The = operators does act upon
+the value of 7 on its right by assigning that value to x. The operator
++ however does nothing. They both, however, have their own values.
+
+6.5 Complex expressions
+As you may have noticed above, the expression x = 5 *itself* has a value
+of 5. In fact, since LPC operators themselves have value as expressions,
+they cal allow you to write some really convoluted looking nonsense like:
+ i = ( (x=sizeof(tmp=users())) ? --x : sizeof(tmp=children("/std/monster"))-1)
+which says basically:
+ assing to tmp the array returned by the efun users(), then assign to x
+ the value equal to the number of elements to that array. If the value
+ of the expression assigning the value to x is true (not 0), then assign
+ x by 1 and assign the value of x-1 to i. If x is false though,
+ then set tmp to the array returned by the efun children(), and then
+ assign to i the value of the number of members in the array tmp -1.
+Would you ever use the above statement? I doubt it. However you might
+see or use expressions similar to it, since the ability to consolidate
+so much information into one single line helps to speed up the execution of
+your code. A more often used version of this property of LPC operators
+would be something like:
+ x = sizeof(tmp = users());
+ while(i--) write((string)tmp[i]->query_name()+"\n");
+instead of writing something like:
+ tmp = users();
+ x = sizeof(tmp);
+ for(i=0; i<x; i++) write((string)tmp[i]->query_name()+"\n");
+Things like for(), while(), arrays and such will be explained later.
+But the first bit of code is more concise and it executed faster.
+
+NOTE: A detailed description of all basic LPC operators follows the chapter
+summary.
+
+
+6.6 Chapter Summary
+You now know how to declare variables and understand the difference between
+declaring and using them globally or locally. Once you become familiar
+with your driver's efuns, you can display those values in many different
+ways. In addition, through the LPC operators, you know how to change
+and evaluate the values contained in variables. This is useful of course
+in that it allows you to do something like count how many apples have
+been picked from a tree, so that once all apples have been picked, no
+players can pick more. Unfortunately, you do not know how to have
+code executed in anything other than a linera fashion. In other words,
+hold off on that apple until the next chapter, cause you do not know
+how to check if the apples picked is equal to the number of apples in the
+tree. You also do not know about the special function init() where you
+give new commands to players. But you are almost ready to code a nice,
+fairly complex area.
+
+6.7 LPC operators
+This section contains a detailed listing of the simpler LPC operators,
+including what they do to the values they use (if anything) and the value
+that they have.
+
+The operators described here are:
+= + - * / % += -= *= /= %=
+-- ++ == != > < >= <= ! && ||
+-> ? :
+
+Those operators are all described in a rather dry manner below, but it is best
+to at least look at each one, since some may not behave *exactly* as
+you think. But it should make a rather good reference guide.
+
+= assignment operator:
+ example: x = 5;
+ value: the value of the variable on the *left* after its function is done
+ explanation: It takes the value of any expression on the *right* and
+ assigns it to the variable on the *left*. Note that you must use
+ a single variable on the left, as you cannot assign values to
+ constants or complex expressions.
+
++ addition operator:
+ example: x + 7
+ value: The sum of the value on the left and the value on the right
+ exaplanation: It takes the value of the expression on the right and
+ adds it to the value of the expression on the left. For values
+ of type int, this means the numerical sum. For strings,
+ it means that the value on the right is stuck onto the value on
+ the left ("ab" is the value of "a"+"b"). This operator does not
+ modify any of the original values (i.e. the variable x from
+ above retains its old value).
+
+- subtraction operator:
+ example: x - 7
+ value: the value of the expression on the left reduced by the right
+ explanation: Same characteristics as addition, except it subtracts.
+ With strings: "a" is the value of "ab" - "b"
+
+* multiplication operator:
+ example: x*7
+ value and explanation: same as with adding and subtracting except
+ this one performs the math of multiplication
+
+/ division operator:
+ example: x/7
+ value and explanation: see above
+
++= additive assignment operator:
+ example: x += 5
+ value: the same as x + 5
+ exaplanation: It takes the value of the variable on the left
+ and the value of the expression on the right, adds them together
+ and assigns the sum to the variable on the left.
+ example: if x = 2... x += 5 assigns the value
+ 7 to the variable x. The whole expression
+ has the value of 7.
+
+-= subtraction assignment operator
+ example: x-=7
+ value: the value of the left value reduced by the right value
+ examplanation: The same as += except for subtraction.
+
+*= multiplicative assignment operator
+ example: x *= 7
+ value: the value of the left value multiplied by the right
+ explanation: Similar to -= and += except for addition.
+
+/= division assignment operator
+ example: x /= 7
+ value: the value of the variable on the left divided by the right value
+ explanation: similar to above, except with division
+
+++ post/pre-increment operators
+ examples: i++ or ++i
+ values:
+ i++ has the value of i
+ ++i has the value of i+1
+ explanation: ++ changes the value of i by increasing it by 1.
+ However, the value of the expression depends on where you
+ place the ++. ++i is the pre-increment operator. This means
+ that it performs the increment *before* giving a value.
+ i++ is the post-ncrement operator. It evalutes before incrementing
+ i. What is the point? Well, it does not much matter to you at
+ this point, but you should recognize what it means.
+
+-- post/pre-decrement operators
+ examples: i-- or --i
+ values:
+ i-- the value of i
+ --i the value of i reduced by 1
+ explanation: like ++ except for subtraction
+
+== equality operator
+ example: x == 5
+ value: true or false (not 0 or 0)
+ explanation: it does nothing to either value, but
+ it returns true if the 2 values are the same.
+ It returns false if they are not equal.
+
+!= inequality operator
+ example: x != 5
+ value: true or false
+ explanation returns true if the left expression is not equal to the right
+ expression. It returns fals if they are equal
+
+> greater than operator
+ example: x > 5
+ value: true or false
+ explanation: true only if x has a value greater than 5
+ false if the value is equal or less
+
+< less than operator
+>= greater than or equal to operator
+<= less than or equal to operator
+ examples: x < y x >= y x <= y
+ values: true or false
+ explanation: similar as to > except
+ < true if left is less than right
+ >= true if left is greater than *or equal to* right
+ <= true if the left is less than *or equal to* the right
+
+&& logical and operator
+|| logical or operator
+ examples: x && y x || y
+ values: true or false
+ explanation: If the right value and left value are non-zero, && is true.
+ If either are false, then && is false.
+ For ||, only one of the values must be true for it to evaluate
+ as true. It is only false if both values indeed
+ are false
+
+! negation operator
+ example: !x
+ value: true or false
+ explanation: If x is true, then !x is false
+ If x is false, !x is true.
+
+A pair of more complicated ones that are here just for the sake of being
+here. Do not worry if they utterly confuse you.
+
+-> the call other operator
+ example: this_player()->query_name()
+ value: The value returned by the function being called
+ explanation: It calls the function which is on the right in the object
+ on the left side of the operator. The left expression *must* be
+ an object, and the right expression *must* be the name of a function.
+ If not such function exists in the object, it will return 0 (or
+ more correctly, undefined).
+
+? : conditional operator
+ example: x ? y : z
+ values: in the above example, if x is try, the value is y
+ if x is false, the value of the expression is z
+ explanation: If the leftmost value is true, it will give the expression as
+ a whole the value of the middle expression. Else, it will give the
+ expression as a whole the value of the rightmost expression.
+
+A note on equality: A very nasty error people make that is VERY difficult
+to debug is the error of placing = where you mean ==. Since
+operators return values, they both make sense when being evaluated.
+In other words, no error occurs. But they have very different values. For example:
+ if(x == 5) if(x = 5)
+The value of x == 5 is true if the value of x is 5, false othewise.
+The value of x = 5 is 5 (and therefore always true).
+The if statement is looking for the expression in () to be either true or false,
+so if you had = and meant ==, you would end up with an expression that is
+always true. And you would pull your hair out trying to figure out
+why things were not happening like they should :)
diff --git a/doc/KURS/LPC-KURS/chapter7 b/doc/KURS/LPC-KURS/chapter7
new file mode 100644
index 0000000..39f311b
--- /dev/null
+++ b/doc/KURS/LPC-KURS/chapter7
@@ -0,0 +1,432 @@
+ LPC Basics
+ Written by Descartes of Borg
+ first edition: 23 april 1993
+ second edition: 10 july 1993
+
+CHAPTER 7: Flow Control
+
+7.1 Review of variables
+Variables may be manipulated by assigning or changing values with the
+expressions =, +=, -=, ++, --. Those expressions may be combined with
+the expressions -, +, *, /, %. However, so far, you have only been
+shown how to use a function to do these in a linear way. For example:
+
+int hello(int x) {
+ x--;
+ write("Hello, x is "+x+".\n");
+ return x;
+}
+
+is a function you should know how to write and understand. But what
+if you wanted to write the value of x only if x = 1? Or what if
+you wanted it to keep writing x over and over until x = 1 before
+returning? LPC uses flow control in exactly the same way as C and C++.
+
+7.2 The LPC flow control statements
+LPC uses the following expressions:
+
+if(expression) instruction;
+
+if(expression) instruction;
+else instruction;
+
+if(expression) instruction;
+else if(expression) instruction;
+else instruction;
+
+while(expression) instruction;
+
+do { instruction; } while(expression);
+
+switch(expression) {
+ case (expression): instruction; break;
+ default: instruction;
+}
+
+Before we discuss these, first something on what is meant by expression and
+instruction. An expression is anything with a value like a variable,
+a comparison (like x>5, where if x is 6 or more, the value is 1, else the
+value is 0), or an assignment(like x += 2). An instruction can be any
+single line of lpc code like a function call, a value assignment or
+modification, etc.
+
+You should know also the operators &&, ||, ==, !=, and !. These are the
+logical operators. They return a nonzero value when true, and 0 when false.
+Make note of the values of the following expressions:
+
+(1 && 1) value: 1 (1 and 1)
+(1 && 0) value: 0 (1 and 0)
+(1 || 0) value: 1 (1 or 0)
+(1 == 1) value: 1 (1 is equal to 1)
+(1 != 1) value: 0 (1 is not equal to 1)
+(!1) value: 0 (not 1)
+(!0) value: 1 (not 0)
+
+In expressions using &&, if the value of the first item being compared
+is 0, the second is never tested even. When using ||, if the first is
+true (1), then the second is not tested.
+
+7.3 if()
+The first expression to look at that alters flow control is if(). Take
+a look at the following example:
+
+1 void reset() {
+2 int x;
+3
+4 ::reset();
+5 x = random(10);
+6 if(x > 50) set_search_func("floorboards", "search_floor");
+7 }
+
+The line numbers are for reference only.
+In line 2, of course we declare a variable of type int called x. Line 3
+is aethetic whitespace to clearly show where the declarations end and the
+function code begins. The variable x is only available to the function
+reset().
+Line 4 makes a call to the room.c version of reset().
+Line 5 uses the driver efun random() to return a random number between
+0 and the parameter minus 1. So here we are looking for a number between
+0 and 99.
+In line 6, we test the value of the expression (x>50) to see if it is true
+or false. If it is true, then it makes a call to the room.c function
+set_search_func(). If it is false, the call to set_search_func() is never
+executed.
+In line 7, the function returns driver control to the calling function
+(the driver itself in this case) without returning any value.
+
+If you had wanted to execute multiple instructions instead of just the one,
+you would have done it in the following manner:
+
+if(x>50) {
+ set_search_func("floorboards", "search_floor");
+ if(!present("beggar", this_object())) make_beggar();
+}
+
+Notice the {} encapsulate the instructions to be executed if the test
+expression is true. In the example, again we call the room.c function
+which sets a function (search_floor()) that you will later define yourself
+to be called when the player types "search floorboards" (NOTE: This is
+highly mudlib dependent. Nightmare mudlibs have this function call.
+Others may have something similar, while others may not have this feature
+under any name). Next, there is another if() expression that tests the
+truth of the expression (!present("beggar",this_object())). The ! in the
+test expression changes the truth of the expression which follows it. In
+this case, it changes the truth of the efun present(), which will return
+the object that is a beggar if it is in the room (this_object()), or it
+will return 0 if there is no beggar in the room. So if there is a beggar
+still living in the room, (present("beggar", this_object())) will have
+a value equal to the beggar object (data type object), otherwise it will
+be 0. The ! will change a 0 to a 1, or any nonzero value (like the
+beggar object) to a 0. Therefore, the expression
+(!present("beggar", this_object())) is true if there is no beggar in the
+room, and false if there is. So, if there is no beggar in the room,
+then it calls the function you define in your room code that makes a
+new beggar and puts it in the room. (If there is a beggar in the room,
+we do not want to add yet another one :))
+
+Of course, if()'s often comes with ands or buts :). In LPC, the formal
+reading of the if() statement is:
+
+if(expression) { set of intructions }
+else if(expression) { set of instructions }
+else { set of instructions }
+
+This means:
+
+If expression is true, then do these instructions.
+Otherise, if this second expression is true, do this second set.
+And if none of those were true, then do this last set.
+
+You can have if() alone:
+
+if(x>5) write("Foo,\n");
+
+with an else if():
+
+if(x > 5) write("X is greater than 5.\n");
+else if(x >2) write("X is less than 6, but greater than 2.\n");
+
+with an else:
+
+if(x>5) write("X is greater than 5.\n");
+else write("X is less than 6.\n");
+
+or the whole lot of them as listed above. You can have any number of
+else if()'s in the expression, but you must have one and only one
+if() and at most one else. Of course, as with the beggar example,
+you may nest if() statements inside if() instructions. (For example,
+ if(x>5) {
+ if(x==7) write("Lucky number!\n");
+ else write("Roll again.\n");
+ }
+ else write("You lose.\n");
+
+7.4 The statements: while() and do {} while()
+Prototype:
+while(expression) { set of instructions }
+do { set of instructions } while(expression);
+
+These allow you to create a set of instructions which continue to
+execute so long as some expression is true. Suppose you wanted to
+set a variable equal to a player's level and keep subtracting random
+amounts of either money or hp from a player until that variable equals
+0 (so that player's of higher levels would lose more). You might do it
+this way:
+
+1 int x;
+2
+3 x = (int)this_player()->query_level(); /* this has yet to be explained */
+4 while(x > 0) {
+5 if(random(2)) this_player()->add_money("silver", -random(50));
+6 else this_player()->add_hp(-(random(10));
+7 x--;
+8 }
+
+The expression this_player()->query_level() calIn line 4, we start a loop that executes so long as x is greater than 0.
+ Another way we could have done this line would be:
+ while(x) {
+ The problem with that would be if we later made a change to the funtion
+y anywhere between 0 and 49 coins.
+In line 6, if instead it returns 0, we call the add_hp() function in the
+ player which reduces the player's hit points anywhere between 0 and 9 hp.
+In line 7, we reduce x by 1.
+At line 8, the execution comes to the end of the while() instructions and
+ goes back up to line 4 to see if x is still greater than 0. This
+ loop will keep executing until x is finally less than 1.
+
+You might, however, want to test an expression *after* you execute some
+instructions. For instance, in the above, if you wanted to execute
+the instructions at least once for everyone, even if their level is
+below the test level:
+
+ int x;
+
+ x = (int)this_player()->query_level();
+ do {
+ if(random(2)) this_player()->add_money("silver", -random(50));
+ else this_player()->add_hp(-random(10));
+ x--;
+ } while(x > 0);
+
+This is a rather bizarre example, being as few muds have level 0 players.
+And even still, you could have done it using the original loop with
+a different test. Nevertheless, it is intended to show how a do{} while()
+works. As you see, instead of initiating the test at the beginning of the
+loop (which would immediately exclude some values of x), it tests after
+the loop has been executed. This assures that the instructions of the loop
+get executed at least one time, no matter what x is.
+
+7.5 for() loops
+Prototype:
+for(initialize values ; test expression ; instruction) { instructions }
+
+initialize values:
+This allows you to set starting values of variables which will be used
+in the loop. This part is optional.
+
+test expression:
+Same as the expression in if() and while(). The loop is executed
+as long as this expression (or expressions) is true. You must have a
+test expression.
+
+instruction:
+An expression (or expressions) which is to be executed at the end of each
+loop. This is optional.
+
+Note:
+for(;expression;) {}
+IS EXACTLY THE SAME AS
+while(expression) {}
+
+Example:
+
+1 int x;
+2
+3 for(x= (int)this_player()->query_level(); x>0; x--) {
+4 if(random(2)) this_player()->add_money("silver", -random(50));
+5 else this_player()->add_hp(-random(10));
+6 }
+
+This for() loop behaves EXACTLY like the while() example.
+Additionally, if you wanted to initialize 2 variables:
+
+for(x=0, y=random(20); x<y; x++) { write(x+"\n"); }
+
+Here, we initialize 2 variables, x and y, and we separate them by a
+comma. You can do the same with any of the 3 parts of the for()
+expression.
+
+7.6 The statement: switch()
+Prototype:
+switch(expression) {
+ case constant: instructions
+ case constant: instructions
+ ...
+ case constant: instructions
+ default: instructions
+}
+
+This is functionally much like if() expressions, and much nicer to the
+CPU, however most rarely used because it looks so damn complicated.
+But it is not.
+
+First off, the expression is not a test. The cases are tests. A English
+sounding way to read:
+
+1 int x;
+2
+3 x = random(5);
+4 switch(x) {
+5 case 1: write("X is 1.\n");
+6 case 2: x++;
+7 default: x--;
+8 }
+9 write(x+"\n");
+
+is:
+
+set variable x to a random number between 0 and 4.
+In case 1 of variable x write its value add 1 to it and subtract 1.
+In case 2 of variable x, add 1 to its value and then subtract 1.
+In other cases subtract 1.
+Write the value of x.
+
+switch(x) basically tells the driver that the variable x is the value
+we are trying to match to a case.
+Once the driver finds a case which matches, that case *and all following
+cases* will be acted upon. You may break out of the switch statement
+as well as any other flow control statement with a break instruction in
+order only to execute a single case. But that will be explained later.
+The default statement is one that will be executed for any value of
+x so long as the switch() flow has not been broken. You may use any
+data type in a switch statement:
+
+string name;
+
+name = (string)this_player()->query_name();
+switch(name) {
+ case "descartes": write("You borg.\n");
+ case "flamme":
+ case "forlock":
+ case "shadowwolf": write("You are a Nightmare head arch.\n");
+ default: write("You exist.\n");
+}
+
+For me, I would see:
+You borg.
+You are a Nightmare head arch.
+You exist.
+
+Flamme, Forlock, or Shadowwolf would see:
+You are a Nightmare head arch.
+You exist.
+
+Everyone else would see:
+You exist.
+
+7.7 Altering the flow of functions and flow control statements
+The following instructions:
+return continue break
+
+alter the natural flow of things as described above.
+First of all,
+return
+no matter where it occurs in a function, will cease the execution of that
+function and return control to the function which called the one the
+return statement is in. If the function is NOT of type void, then a
+value must follow the return statement, and that value must be of a
+type matching the function. An absolute value function would look
+like this:
+
+int absolute_value(int x) {
+ if(x>-1) return x;
+ else return -x;
+}
+
+In the second line, the function ceases execution and returns to the calling
+function because the desired value has been found if x is a positive
+number.
+
+continue is most often used in for() and while statements. It serves
+to stop the execution of the current loop and send the execution back
+to the beginning of the loop. For instance, say you wanted to avoid
+division by 0:
+
+x= 4;
+while( x > -5) {
+ x--
+ if(!x) continue;
+ write((100/x)+"\n");
+}
+write("Done.\n")
+
+You would see the following output:
+33
+50
+100
+-100
+-50
+-33
+-25
+Done.
+To avoid an error, it checks in each loop to make sure x is not 0.
+If x is zero, then it starts back with the test expression without
+finishing its current loop.
+
+In a for() expression
+ for(x=3; x>-5; x--) {
+ if(!x) continue;
+ write((100/x)+"\n");
+ }
+ write("Done.\n");
+It works much the same way. Note this gives exactly the same output
+as before. At x=1, it tests to see if x is zero, it is not, so it
+writes 100/x, then goes back to the top, subtracts one from x, checks to
+see if it is zero again, and it is zero, so it goes back to the top
+and subtracts 1 again.
+
+break
+This one ceases the function of a flow control statement. No matter
+where you are in the statement, the control of the program will go
+to the end of the loop. So, if in the above examples, we had
+used break instead of continue, the output would have looked like this:
+
+33
+50
+100
+Done.
+
+continue is most often used with the for() and while() statements.
+break however is mostly used with switch()
+
+switch(name) {
+ case "descartes": write("You are borg.\n"); break;
+ case "flamme": write("You are flamme.\n"); break;
+ case "forlock": write("You are forlock.\n"); break;
+ case "shadowwolf": write("You are shadowwolf.\n"); break;
+ default: write("You will be assimilated.\n");
+}
+
+This functions just like:
+
+if(name == "descartes") write("You are borg.\n");
+else if(name == "flamme") write("You are flamme.\n");
+else if(name == "forlock") write("You are forlock.\n");
+else if(name == "shadowwolf") write("You are shadowwolf.\n");
+else write("You will be assimilated.\n");
+
+except the switch statement is much better on the CPU.
+If any of these are placed in nested statements, then they alter the
+flow of the most immediate statement.
+
+7.8 Chapter summary
+This chapter covered one hell of a lot, but it was stuff that needed to
+be seen all at once. You should now completely understand if() for()
+while() do{} while() and switch(), as well as how to alter their flow
+using return, continue, and break. Effeciency says if it can be done in
+a natural way using switch() instead of a lot of if() else if()'s, then
+by all means do it. You were also introduced to the idea of calling
+functions in other objects. That however, is a topic to be detailed later.
+You now should be completely at ease writing simple rooms (if you have
+read your mudlib's room building document), simple monsters, and
+other sorts of simple objects.
diff --git a/doc/KURS/LPC-KURS/chapter8 b/doc/KURS/LPC-KURS/chapter8
new file mode 100644
index 0000000..a794713
--- /dev/null
+++ b/doc/KURS/LPC-KURS/chapter8
@@ -0,0 +1,195 @@
+ LPC Basics
+ Written by Descartes of Borg
+ first edition: 23 april 1993
+ second edition: 12 july 1993
+
+CHAPTER 8: The data type "object"
+
+8.1 Review
+You should now be able to do anything so long as you stick to calling
+functions within your own object. You should also know, that at the
+bare minimum you can get the create() (or reset()) function in your object
+called to start just by loading it into memory, and that your reset()
+function will be called every now and then so that you may write the
+code necessary to refresh your room. Note that neither of these
+functions MUST be in your object. The driver checks to see if the
+function exists in your object first. If it does not, then it does not
+bother. You are also acquainted with the data types void, int, and string.
+
+7.2 Objects as data types
+In this chapter you will be acquainted with a more complex data type,
+object. An object variable points to a real object loaded into the
+driver's memory. You declare it in the same manner as other data types:
+ object ob;
+It differs in that you cannot use +, -, +=, -=, *, or / (what would it
+mean to divide a monster by another monster?). And since efuns like
+say() and write() only want strings or ints, you cannot write() or
+say() them (again, what would it mean to say a monster?).
+But you can use them with some other of the most important efuns on any
+LPMud.
+
+8.3 The efun: this_object()
+This is an efun which returns an object in which the function being executed
+exists. In other words, in a file, this_object() refers to the object your
+file is in whether the file gets cloned itself or inherted by another file.
+It is often useful when you are writing a file which is getting inherited
+by another file. Say you are writing your own living.c which gets
+inherited by user.c and monster.c, but never used alone. You want to log
+the function set_level() it is a player's level being set (but you do not
+care if it is a monster.
+You might do this:
+
+void set_level(int x) {
+ if(this_object()->is_player()) log_file("levels", "foo\n");
+ level = x;
+}
+
+Since is_player() is not defined in living.c or anything it inherits,
+just saying if(is_player()) will result in an error since the driver
+does not find that function in your file or anything it inherits.
+this_object() allows you to access functions which may or may not be
+present in any final products because your file is inherited by others
+without resulting in an error.
+
+8.4 Calling functions in other objects
+This of course introduces us to the most important characteristic of
+the object data type. It allows us to access functions in other objects.
+In previous examples you have been able to find out about a player's level,
+reduce the money they have, and how much hp they have.
+Calls to functions in other objects may be done in two ways:
+
+object->function(parameters)
+call_other(object, "function", parameters);
+
+example:
+this_player()->add_money("silver", -5);
+call_other(this_player(), "add_money", "silver", -5);
+
+In some (very loose sense), the game is just a chain reaction of function
+calls initiated by player commands. When a player initiates a chain of
+function calls, that player is the object which is returned by
+the efun this_player(). So, since this_player() can change depending
+on who initiated the sequence of events, you want to be very careful
+as to where you place calls to functions in this_player(). The most common
+place you do this is through the last important lfun (we have mentioned
+create() and reset()) init().
+
+8.5 The lfun: init()
+Any time a living thing encounters an object (enters a new room, or enters
+the same room as a certain other object), init() is called in all of
+the objects the living being newly encounters. It is at this point
+that you can add commands the player can issue in order to act.
+Here is a sample init() function in a flower.
+
+void init() {
+ ::init();
+ add_action("smell_flower", "smell");
+}
+
+Ito smell_flower(). So you should have smell_flower() look like this:
+
+1 int smell_flower(string str); /* action functions are type int */
+2
+3 int smell_flower(string str) {
+4 if(str != "flower") return 0; /* it is not the flower being smelled */
+5 write("You sniff the flower.\n");
+6 say((string)this_player()->query_cap_name()+" smells the flower.\n");
+7 this_player()->add_hp(random(5));
+8 return 1;
+9 }
+
+In line 1, we have our function declared.
+In line 3, smell_flower() begins. str becomes whatever comes after the
+ players command (not including the first white space).
+In line 4, it checks to see if the player had typed "smell flower". If
+ the player had typed "smell cheese", then str would be "cheese". If
+ it is not in fact "flower" which is being smelled, then 0 is returned,
+ letting the driver know that this was not the function which should
+ have been called. If in fact the player had a piece of cheese as well
+ which had a smell command to it, the driver would then call the function
+ for smelling in that object. The driver will keep calling all functions
+ tied to smell commands until one of them returns 1. If they all return
+ 0, then the player sees "What?"
+In line 5, the efun write() is called. write() prints the string which
+ is passed to it to this_player(). So whoever typed the command here
+ sees "You sniff the flower."
+In line 6, the efun say() is called. say() prints the string which is
+ doing the sniffing, we have to call the query_cap_name() function
+ in this_player(). That way if the player is invis, it will say
+ "Someone" (or something like that), and it will also be properly
+ capitalized.
+In line 7, we call the add_hp() function in the this_player() object,
+ since we want to do a little healing for the sniff (Note: do not
+ code this object on your mud, whoever balances your mud will shoot you).
+In line 8, we return control of the game to the driver, returning 1 to
+ let it know that this was in fact the right function to call.
+
+8.6 Adding objects to your rooms
+And now, using the data type object, you can add monsters to your rooms:
+
+void create() {
+ ::create();
+ set_property("light", 3);
+ set("short", "Krasna Square");
+ set("long", "Welcome to the Central Square of the town of Praxis.\n");
+ set_exits( ({ "d/standard/hall" }), ({ "east" }) );
+}
+
+void reset() {
+ object ob;
+
+ ::reset();
+ if(present("guard")) return; /* Do not want to add a guard if */
+ ob = new("/std/monster"); /* one is already here */
+ ob->set_name("guard");
+ ob->set("id", ({ "guard", "town guard" }) );
+ ob->set("short", "Town guard");
+ ob->set("long", "He guards Praxis from nothingness.\n");
+ ob->set_gender("male");
+ ob->set_race("human");
+ ob->set_level(10);
+ ob->set_alignment(200);
+ ob->set_humanoid();
+ ob->set_hp(150);
+ ob->set_wielding_limbs( ({ "right hand", "left hand" }) );
+ ob->move(this_object());
+}
+
+Now, this will be wildly different on most muds. Some, as noted before,
+in that object so you have a uniquely configured monster object. The
+last act in native muds is to call move() in the monster object to move
+it to this room (this_object()). In compat muds, you call the efun
+move_object() which takes two parameters, the object to be moved, and the
+object into which it is being moved.
+
+8.7 Chapter summary
+At this point, you now have enough knowledge to code some really nice
+stuff. Of course, as I have been stressing all along, you really need
+to read the documents on building for your mud, as they detail which
+functions exist in which types of objects for you to call. No matter
+what your knowledge of the mudlib is, you have enough know-how to
+give a player extra things to do like sniffing flowers or glue or whatever.
+At this point you should get busy coding stuff. But the moment things
+even look to become tedious, that means it is time for you to move to
+the next level and do more. Right now code yourself a small area.
+Make extensive use of the special functions coded in your mud's
+room.c (search the docs for obscure ones no one else seems to use).
+Add lots o' neat actions. Create weapons which have magic powers which
+gradually fade away. All of this you should be able to do now. Once
+this becomes routine for you, it will be time to move on to intermediate
+stuff. Note that few people actually get to the intermediate stuff.
+If you have played at all, you notice there are few areas on the mud
+which do what I just told you you should be able to do. It is not
+because it is hard, but because there is a lot of arrogance out there
+on the part of people who have gotten beyond this point, and very little
+communicating of that knowledge. The trick is to push yourself and
+think of something you want to do that is impossible. If you ask someone
+in the know how to do X, and they say that is impossible, find out
+youself how to code it by experimenting.
+
+George Reese
+Descartes of Borg
+12 july 1993
+borg@hebron.connected.com
+Descartes@Nightmare (intermud)
+Descartes@Igor (not intermud)
diff --git a/doc/KURS/LPC-KURS2/Contents b/doc/KURS/LPC-KURS2/Contents
new file mode 100644
index 0000000..ff58a8a
--- /dev/null
+++ b/doc/KURS/LPC-KURS2/Contents
@@ -0,0 +1,15 @@
+Intermediate LPC
+Descartes of Borg
+November 1993
+
+ Contents
+
+1: Introduction
+2: The LPMud Driver
+3: Complex Data Types
+4: The LPC Pre-Compiler
+5: Advanced String Handling
+6: Intermediate Inheritance
+7: Debugging
+
+Copyright (c) George Reese 1993
diff --git a/doc/KURS/LPC-KURS2/Copyright b/doc/KURS/LPC-KURS2/Copyright
new file mode 100644
index 0000000..29a2620
--- /dev/null
+++ b/doc/KURS/LPC-KURS2/Copyright
@@ -0,0 +1,62 @@
+ Intermediate LPC first edition
+
+Copyright (c) 1993 George Reese
+All rights to this text are retained by the author.
+
+
+Permission is granted to distrubute and display the contents of this
+document in full so long as the following conditions are met:
+1) No payment may be received for the redistribution or display of this text,
+except to cover the costs for distribution media and and shipping and/or
+transmission charges.
+2) The textbook must be distributed or displayed in its entirety in its original
+form. Changes may only be made to private, individual copies, except as
+outlined below.
+
+Acceptable changes are defined as the following:
+1) Format changes, such as changing from WordPerfect to Word
+2) Medium changes, such as from electronic copy to paper
+3) Content changes are only acceptable under the following circumstances:
+ a) In electronic media: none of the original text may be ommitted.
+ You may add comments
+ as you feel necessary, so long as comments are enclosed in <* *>
+ and are accompanied by
+ the game name or real name of the author of the comments
+ b) In hard copy: none of the original text may be omitted, but it may
+ be struck out so long
+ as the content of the original text is visible. Comments may be made
+ in any form so long
+ as they are made in handwriting and they are signed by the author.
+ Comments which are typed or printed must be made in accordance with the
+ format for electronic media.
+
+Practically speaking, this is what I mean:
+First, I wrote this mostly for mud admins to put onto their muds for learning
+coders to read as they are learning to build realms. I did not do this for
+someone else to make a buck. So if you charge money for redistributing it
+or allowing someone else to see it, you are in violation of this copyright.
+Unless you are simply charging for what it cost you to print up a copy or
+what the diskettes and postage cost to mail it.
+Second, I wrote this textbook, and I should receive credit/blame for what I
+say, and others should receive credit/blame for what they say. For example,
+if I said something completely wrong, and you simply corrected it, I would
+be getting credit for something I did not do. Yet, if you comment according
+to the outline above, you will be properly credited for your comments.
+More important to me, however, is the practical effect of having hundreds of
+copies of this textbook everywhere. If you change something I had right
+without noting it as a comment, I will be blamed for spreading
+misinformation. This problem is only compunded if the text is redistributed.
+So I prefer my words to remain my own. But, when I make mistakes, or if
+something I say does not fit your driver/mudlib, please comment it so people
+will know. In addition, having the comments side-by-side allows people to
+see other ideas, like how another driver might handle something.
+
+
+I want to please note again, you may display this on your mud (like in /doc).
+You do not need to
+mail me for permission. I would not mind email, since it is nice to know
+people are using it, but that is not required. Also, if you really feel I have
+done such a wonderful job that you should pay money to use this, then give
+$5 to your local ASPCA (or international equivalent).
+
+See the file titled Contents for a full list of textbook chapters.
diff --git a/doc/KURS/LPC-KURS2/chapter1 b/doc/KURS/LPC-KURS2/chapter1
new file mode 100644
index 0000000..6c459cd
--- /dev/null
+++ b/doc/KURS/LPC-KURS2/chapter1
@@ -0,0 +1,143 @@
+Intermediate LPC
+Descartes of Borg
+Novermber 1993
+
+ Chapter 1: Introduction
+
+1.1 LPC Basics
+Anyone reading this textbook should either have read the textbook LPC
+Basics or be familiar enough with mud realm coding such that not only are
+they capable of building rooms and other such objects involved in area
+coding, but they also have a good idea of what is going on when the code
+they write is executing. If you do not feel you are at this point, then go
+back and read LPC Basics before continuing. If you do so, you will find
+that what you read here will be much more meaningful to you.
+
+1.2 Goals of This Textbook
+The introductory textbook was meant to take people new to LPC from
+knowing nothing to being able to code a nice realm on any LPMud. There
+is naturally much more to LPC and to LPMud building, however, than
+building rooms, armours, monsters, and weapons. As you get into more
+complicated concepts like guilds, or desire to do more involved things with
+your realm, you will find the concepts detailed in LPC Basics to be lacking
+in support for these projects. Intermediate LPC is designed to take you
+beyond the simple realm building process into a full knowledge of LPC for
+functioning as a realm builder on an LPMud. The task of mudlib building
+itself is left to a later text. After reading this textbook and working through
+it by experimenting with actual code, the reader should be able to code game
+objects to fit any design or idea they have in mind, so long as I have been
+successful.
+
+1.3 An Overview
+What more is there? Well many of you are quite aware that LPC supports
+mappings and arrays and have been asking me why those were not detailed
+in LPC Basics. I felt that those concepts were beyond the scope of what I
+was trying to do with that textbook and were more fitting to this textbook.
+But new tools are all fine and dandy, what matters, however, is what you
+can do with those tools. The goal of LPC Basics was to get you to building
+quality LPMud realms. Mappings and arrays are not necessary to do that.
+The goal of this book is to allow you to code any idea you might want to
+code in your area. That ability requires the knowledge of mappings and
+arrays.
+
+Any idea you want to code in an LPMud is possible. LPC is a language
+which is amazingly well suited to this task. All that prevents you from
+coding your ideas is your knowledge of LPC or an inadequate mudlib or
+your mudÕs theme or administrative policies. This textbook cannot make
+the mudlib you are working with any better, and it cannot change the mud
+theme or the mudÕs administrative policies. Never once think that LPC is
+incapable of doing what you want to do. If your idea is prevented by
+administrative policies or themes, then it is simply not an idea for your
+current mud. If the mudlib is inadequate, talk to the people in charge of
+your mudlib about what can be done at the mudlib level to facilitate it. You
+would be surprised by what is actually in the mudlib you did not know
+about. More important, after reading this textbook, you should be able to
+read all of the mudlib code in your mudÕs mudlib and understand what is
+going on at each line in the mudlib code. You may not as yet be able to
+reproduce that code on your own, but at least you can understand what is
+going on at the mudlib level.
+
+This textbook starts out with a discussion about what the LPMud driver is
+doing. One nice thing about this textbook, in general it is completely driver
+and mudlib independent (excepting for the Dworkin Game Driver). The
+chapter on the game driver does not get into actual implementation, but
+instead deals with what all game drivers basically do in order to run the
+mud.
+
+Next I discuss those magic topics everyone wants to know more about,
+arrays and mappings. Mappings may be simultaneously the easiest and
+most difficult data type to understand. Since they are sort of complex arrays
+in a loose sense, you really need to understand arrays before discussing
+them. All the same, once you understand them, they are much easier than
+arrays to use in real situations. At any rate, spend most of your time
+working with that chapter, because it is probably the most difficult, yet most
+useful chapter in the book.
+
+After that follows a brief chapter on the LPC pre-compiler, a tool you can
+use for sorting out how your code will look before it gets sent to the
+compiler. Despite my horrid intro to it here, this chapter is perhaps the
+easiest chapter in the textbook. I put it after the mappings and arrays
+chapter for exactly that reason.
+
+Strings are re-introduced next, going into more detail with how you can do
+such things as advanced command handling by breaking up strings. Once
+you understand arrays fairly well, this chapter should be really simple.
+
+The next chapter is the second most important in the book. It may be the
+most important if you ever intend to go beyond the intermediate stage and
+dive into mudlib coding. That chapter involves the complex ideas behind
+LPC inheritance. Since the goal of this textbook is not to teach mudlib
+programming, the chapter is not a detailed discussion on object oriented
+programming. Understanding this chapter, however, will give you some
+good insights into what is involved with object oriented programming, as
+well as allow you to build more complex objects by overriding functions
+and defining your own base classes.
+
+Finally, the textbook ends with a simple discussion of code debugging.
+This is not an essential chapter, but instead it is meant as more of an
+auxiliary supplement to what the knowledge you have accumulated so far.
+
+1.4 Not Appearing in This Textbook
+Perhaps what might appear to some as the most glaring omission of this
+textbook is largely a political omission, shadows. Never have I ever
+encountered an example of where a shadow was either the best or most
+effecient manner of doing anything. It does not follow from that, however,
+that there are no uses for shadows. My reasoning for omitting shadows
+from this textbook is that the learner is best served by learning the concepts
+in this textbook first and having spent time with them before dealing with
+the subject of shadows. In that way, I feel the person learning LPC will be
+better capable of judging the merits of using a shadow down the road. I
+will discuss shadows in a future textbook.
+
+If you are someone who uses shadows some or a lot, please do not take the
+above paragraph as a personal attack. There may be some perfectly valid
+uses for shadows somewhere which I have yet to encounter. Nevertheless,
+they are not the ideal way to accomplish any given task, and therefore they
+are not considered for the purposes of this textbook an intermediate coding
+tool.
+
+I have also omitted discussions of security and object oriented
+programming. Both are quite obviously mudlib issues. Many people,
+however, might take exception with my leaving out a discussion of object
+oriented programming. I chose to leave that for a later text, since most area
+builders code for the creativity, not for the computer science theory. In both
+the intermediate and beginner textbooks, I have chosen only to discuss
+theory where it is directly applicable to practical LPC programming. For
+people who are starting out green in LPC and want to code the next great
+mudlib, perhaps theory would be more useful. But for the purposes of this
+book, a discussion of object oriented programming is simply a snoozer. I
+do plan to get heavy into theory with the next textbook.
+
+1.5 Summary
+LPC is not difficult to learn. It is a language which, although pathetic
+compared to any other language for performing most computer language
+tasks, is incredibly powerful and unequalled for the tasks of building an
+area in MUD type games. For the beginner, it allows you to easily jump in
+and code useful objects without even knowing what you are doing. For the
+intermediate person, it allows you to turn any idea you have into textual
+virtual reality. And for the advanced person, itÕs object oriented features
+can allow you to build one of the most popular games on the internet. What
+you can do is simply limited by how much you know. And learning more
+does not require a computer science degree.
+
+Copyright (c) George Reese 1993
diff --git a/doc/KURS/LPC-KURS2/chapter2 b/doc/KURS/LPC-KURS2/chapter2
new file mode 100644
index 0000000..51a4c3c
--- /dev/null
+++ b/doc/KURS/LPC-KURS2/chapter2
@@ -0,0 +1,223 @@
+Intermediate LPC
+Descartes of Borg
+Novermber 1993
+
+ Chapter 2: The LPMud Driver
+
+2.1 Review of Basic Driver/Mudlib Interaction
+In the LPC Basics textbook, you learned a lot about the way the mudlib
+works, specifically in relation to objects you code in order to build your
+realm. Not much was discussed about the interaction between the
+mudlib and the driver. You should know, however, that the driver
+does the following:
+1) When an object is first loaded into memory, the driver will call
+create() in native muds and reset() in compat muds. A creator
+uses create() or reset() to give initial values to the object.
+2) At an interval setup by the game administrator, the driver calls the
+function reset(). This allows the object to regenerate monsters and
+such. Notice that in a compat mud, the same function is used to set up
+initial values as is used to reset the room.
+3) Any time a living object comes in contact with an object of any sort,
+the driver calls init() in the newly encountered object. This allows
+newly encountered objects to give living objects commands to execute
+through the add_action() efun, as well as perform other actions which
+should happen whenever a living thing encounters a given object.
+4) The driver defines a set of functions known as efuns which are
+available to all objects in the game. Examples of commonly used efuns
+are: this_player(), this_object(), write(), say(), etc.
+
+2.2 The Driver Cycle
+The driver is a C program which runs the game. Its basic functions are
+to accept connections from the outside world so people can login,
+interpret the LPC code which defines LPC objects and how they
+function in the game, and accept user input and call the appropriate LPC
+functions which match the event. In its most simplest essence, it is an
+unending loop.
+
+Once the game has booted up and is properly functioning (the boot up
+process will be discussed in a future, advanced LPC textbook), the
+driver enters a loop which does not terminate until the shutdown() efun
+is legally called or a bug causes the driver program to crash. First off,
+the driver handles any new incoming connections and passes control of
+the connection to a login object. After that, the driver puts together a
+table of commands which have been entered by users since the last cycle
+of the driver. After the command table is assembled, all messages
+scheduled to be sent to the connection from the last driver cycle are sent
+out to the user. At this point, the driver goes through the table of
+commands to be executed and executes each set of commands each
+object has stored there. The driver ends its cycle by calling the function
+heart_beat() in every object with a heart_beat() set and finally
+performing all pending call outs. This chapter will not deal with the
+handling of connections, but instead will focus on how the driver
+handles user commands and heartbeats and call outs.
+
+2.3 User Commands
+As noted in section 1.2, the driver stores a list of commands for each
+user to be executed each cycle. The commands list has the name of the
+living object performing the command, the object which gave the living
+object that command, and the function which is to be executed in order
+to perform the command. The driver refers to the object which typed in
+the command as the command giver. It is the command giver which
+gets returned as this_player() in most cases.
+
+The driver starts at the top of the list of living objects with pending
+commands, and successively performs each command it typed by calling
+the function associated with the command and passing any arguments
+the command giver gave as arguments to the function. As the driver
+starts with the commands issued by a new living object, the command
+giver variable is changed to be equal to the new living object, so that
+during the sequence of functions initiated by that command, the efun
+this_player() returns the object which issued the command.
+
+Let's look at the command buffer for an example player. Since the
+execution of his last command, Bozo has typed "north" and "tell
+descartes when is the next reboot". The command "north" is associated
+with the function "Do_Move()" in the room Bozo is in (the command
+"north" is automatically setup by the set_exits() efun in that room). The
+command "tell" is not specifically listed as a command for the player,
+however, in the player object there is a function called "cmd_hook()"
+which is associated with the command "", which matches any possible
+user input.
+
+Once the driver gets down to Bozo, the command giver variable is set to
+the object which is Bozo. Then, seeing Bozo typed "north" and the
+function "north" is associated with, the driver calls Bozo's_Room-
+>Do_Move(0). An argument of 0 is passed to the function since Bozo
+only typed the command "north" with no arguments. The room
+naturally calls some functions it needs, all the while such that the efun
+this_player() returns the object which is Bozo. Eventually, the room
+object will call move_player() in Bozo, which in turn calls the
+move_object() efun. This efun is responsible for changing an object's
+environment.
+
+When the environment of an object changes, the commands available to
+it from objects in its previous environment as well as from its previous
+environment are removed from the object. Once that is done, the driver
+calls the efun init() in the new environment as well as in each object in
+the new environment. During each of these calls to init(), the object
+Bozo is still the command giver. Thus all add_action() efuns from this
+move will apply to Bozo. Once all those calls are done, control passes
+back from the move_object() efun to the move_player() lfun in Bozo.
+move_player() returns control back to Do_Move() in the old room,
+which returns 1 to signify to the driver that the command action was
+successful. If the Do_Move() function had returned 0 for some reason,
+the driver would have written "What?" (or whatever your driver's
+default bad command message is) to Bozo.
+
+Once the first command returns 1, the driver proceeds on to Bozo's
+second command, following much the same structure. Note that with
+"tell descartes when is the next reboot", the driver passes "descartes
+when is the next reboot" to the function associated with tell. That
+function in turn has to decide what to do with that argument. After that
+command returns either 1 or 0, the driver then proceeds on to the next
+living object with commands pending, and so on until all living objects
+with pending commands have had their commands performed.
+
+2.4 The Efuns set_heart_beat() and call_out()
+Once all commands are performed for objects with commands pending,
+the driver then proceeds to call the heart_beat() function in all objects
+listed with the driver as having heartbeats. Whenever an object calls the
+efun set_heart_beat() with a non-zero argument (depending on your
+driver, what non-zero number may be important, but in most cases you
+call it with the int 1). The efun set_heart_beat() adds the object which
+calls set_heart_beat() to the list of objects with heartbeats. If you call it
+with an argument of 0, then it removes the object from the list of objects
+with heartbeats.
+
+The most common use for heartbeats in the mudlib is to heal players and
+monsters and perform combat. Once the driver has finished dealing with
+the command list, it goes through the heartbeat list calling heart_beat() in
+each object in the list. So for a player, for example, the driver will call
+heart_beat() in the player which will:
+1) age the player
+2) heal the player according to a heal rate
+3) check to see if there are any hunted, hunting, or attacking objects
+around
+4) perform an attack if step 3 returns true.
+5) any other things which need to happen automatically roughly every
+second
+
+Note that the more objects which have heartbeats, the more processing
+which has to happen every cycle the mud is up. Objects with heartbeats
+are thus known as the major hog of CPU time on muds.
+
+The call_out() efun is used to perform timed function calls which do not
+need to happen as often as heartbeats, or which just happen once. Call
+outs let you specify the function in an object you want called. The
+general formula for call outs is:
+call_out(func, time, args);
+The third argument specifying arguments is optional. The first argument
+is a string representing the name of the function to be called. The second
+argument is how many seconds should pass before the function gets
+called.
+
+Practically speaking, when an object calls call_out(), it is added to a list
+of objects with pending call outs with the amount of time of the call out
+and the name of the function to be called. Each cycle of the driver, the
+time is counted down until it becomes time for the function to be called.
+When the time comes, the driver removes the object from the list of
+objects with pending call outs and performs the call to the call out
+function, passing any special args originally specified by the call out
+function.
+
+If you want a to remove a pending call before it occurs, you need to use
+the remove_call_out() efun, passing the name of the function being
+called out. The driver will remove the next pending call out to that
+function. This means you may have some ambiguity if more than one
+call out is pending for the same function.
+
+In order to make a call out cyclical, you must reissue the call_out() efun
+in the function you called out, since the driver automatically removes the
+function from the call out table when a call out is performed. Example:
+
+void foo() { call_out("hello", 10); }
+
+void hello() { call_out("hello", 10); }
+
+will set up hello() to be called every 10 seconds after foo() is first called.
+There are several things to be careful about here. First, you must watch
+to make sure you do not structure your call outs to be recursive in any
+unintended fashion. Second, compare what a set_heart_beat() does
+when compared directly to what call_out() does.
+
+set_heart_beat():
+a) Adds this_object() to a table listing objects with heartbeats.
+b) The function heart_beat() in this_object() gets called every single
+driver cycle.
+
+call_out():
+a) Adds this_object(), the name of a function in this_object(), a time
+delay, and a set of arguments to a table listing functions with pending
+call outs.
+b) The function named is called only once, and that call comes after the
+specified delay.
+
+As you can see, there is a much greater memory overhead associated
+with call outs for part (a), yet that there is a much greater CPU overhead
+associated with heartbeats as shown in part (b), assuming that the delay
+for the call out is greater than a single driver cycle.
+
+Clearly, you do not want to be issuing 1 second call outs, for then you
+get the worst of both worlds. Similarly, you do not want to be having
+heart beats in objects that can perform the same functions with call outs
+of a greater duration than 1 second. I personally have heard much talk
+about at what point you should use a call out over a heartbeat. What I
+have mostly heard is that for single calls or for cycles of a duration
+greater than 10 seconds, it is best to use a call out. For repetitive calls of
+durations less than 10 seconds, you are better off using heartbeats. I do
+not know if this is true, but I do not think following this can do any
+harm.
+
+2.5 Summary
+Basic to a more in depth understanding of LPC is and understanding of
+the way in which the driver interacts with the mudlib. You should now
+understand the order in which the driver performs functions, as well as a
+more detailed knowledge of the efuns this_player(), add_action(), and
+move_object() and the lfun init(). In addition to this building upon
+knowledge you got from the LPC Basics textbook, this chapter has
+introduced call outs and heartbeats and the manner in which the driver
+handles them. You should now have a basic understanding of call outs
+and heartbeats such that you can experiment with them in your realm
+code.
+
+Copyright (c) George Reese 1993
diff --git a/doc/KURS/LPC-KURS2/chapter3 b/doc/KURS/LPC-KURS2/chapter3
new file mode 100644
index 0000000..f986737
--- /dev/null
+++ b/doc/KURS/LPC-KURS2/chapter3
@@ -0,0 +1,481 @@
+Intermediate LPC
+Descartes of Borg
+November 1993
+
+ Chapter 3: Complex Data Types
+
+3.1 Simple Data Types
+In the textbook LPC Basics, you learned about the common, basic LPC
+data types: int, string, object, void. Most important you learned that
+many operations and functions behave differently based on the data type
+of the variables upon which they are operating. Some operators and
+functions will even give errors if you use them with the wrong data
+types. For example, "a"+"b" is handled much differently than 1+1.
+When you ass "a"+"b", you are adding "b" onto the end of "a" to get
+"ab". On the other hand, when you add 1+1, you do not get 11, you get
+2 as you would expect.
+
+I refer to these data types as simple data types, because they atomic in
+that they cannot be broken down into smaller component data types.
+The object data type is a sort of exception, but you really cannot refer
+individually to the components which make it up, so I refer to it as a
+simple data type.
+
+This chapter introduces the concept of the complex data type, a data type
+which is made up of units of simple data types. LPC has two common
+complex data types, both kinds of arrays. First, there is the traditional
+array which stores values in consecutive elements accessed by a number
+representing which element they are stored in. Second is an associative
+array called a mapping. A mapping associates to values together to
+allow a more natural access to data.
+
+3.2 The Values NULL and 0
+Before getting fully into arrays, there first should be a full understanding
+of the concept of NULL versus the concept of 0. In LPC, a null value is
+represented by the integer 0. Although the integer 0 and NULL are often
+freely interchangeable, this interchangeability often leads to some great
+confusion when you get into the realm of complex data types. You may
+have even encountered such confusion while using strings.
+
+0 represents a value which for integers means the value you add to
+another value yet still retain the value added. This for any addition
+operation on any data type, the ZERO value for that data type is the value
+that you can add to any other value and get the original value. Thus: A
+plus ZERO equals A where A is some value of a given data type and
+ZERO is the ZERO value for that data type. This is not any sort of
+official mathematical definition. There exists one, but I am not a
+mathematician, so I have no idea what the term is. Thus for integers, 0
+is the ZERO value since 1 + 0 equals 1.
+
+NULL, on the other hand, is the absence of any value or meaning. The
+LPC driver will interpret NULL as an integer 0 if it can make sense of it
+in that context. In any context besides integer addition, A plus NULL
+causes an error. NULL causes an error because adding valueless fields
+in other data types to those data types makes no sense.
+
+Looking at this from another point of view, we can get the ZERO value
+for strings by knowing what added to "a" will give us "a" as a result.
+The answer is not 0, but instead "". With integers, interchanging NULL
+and 0 was acceptable since 0 represents no value with respect to the
+integer data type. This interchangeability is not true for other data types,
+since their ZERO values do not represent no value. Namely, ""
+represents a string of no length and is very different from 0.
+
+When you first declare any variable of any type, it has no value. Any
+data type except integers therefore must be initialized somehow before
+you perform any operation on it. Generally, initialization is done in the
+create() function for global variables, or at the top of the local function
+for local variables by assigning them some value, often the ZERO value
+for that data type. For example, in the following code I want to build a
+string with random words:
+
+string build_nonsense() {
+ string str;
+ int i;
+
+ str = ""; /* Here str is initialized to the string
+ZERO value */
+ for(i=0; i<6; i++) {
+ switch(random(3)+1) {
+ case 1: str += "bing"; break;
+ case 2: str += "borg"; break;
+ case 3: str += "foo"; break;
+ }
+ if(i==5) str += ".\n";
+ else str += " ";
+ }
+ return capitalize(str);
+}
+
+If we had not initialized the variable str, an error would have resulted
+from trying to add a string to a NULL value. Instead, this code first
+initializes str to the ZERO value for strings, "". After that, it enters a
+loop which makes 6 cycles, each time randomly adding one of three
+possible words to the string. For all words except the last, an additional
+blank character is added. For the last word, a period and a return
+character are added. The function then exits the loop, capitalizes the
+nonsense string, then exits.
+
+3.3 Arrays in LPC
+An array is a powerful complex data type of LPC which allows you to
+access multiple values through a single variable. For instance,
+Nightmare has an indefinite number of currencies in which players may
+do business. Only five of those currencies, however, can be considered
+hard currencies. A hard currency for the sake of this example is a
+currency which is readily exchangeable for any other hard currency,
+whereas a soft currency may only be bought, but not sold. In the bank,
+there is a list of hard currencies to allow bank keepers to know which
+currencies are in fact hard currencies. With simple data types, we would
+have to perform the following nasty operation for every exchange
+transaction:
+
+int exchange(string str) {
+ string from, to;
+ int amt;
+
+ if(!str) return 0;
+ if(sscanf(str, "%d %s for %s", amt, from, to) != 3)
+ return 0;
+ if(from != "platinum" && from != "gold" && from !=
+ "silver" &&
+ from != "electrum" && from != "copper") {
+ notify_fail("We do not buy soft currencies!\n");
+ return 0;
+ }
+ ...
+}
+
+With five hard currencies, we have a rather simple example. After all it
+took only two lines of code to represent the if statement which filtered
+out bad currencies. But what if you had to check against all the names
+which cannot be used to make characters in the game? There might be
+100 of those; would you want to write a 100 part if statement?
+What if you wanted to add a currency to the list of hard currencies? That
+means you would have to change every check in the game for hard
+currencies to add one more part to the if clauses. Arrays allow you
+simple access to groups of related data so that you do not have to deal
+with each individual value every time you want to perform a group
+operation.
+
+As a constant, an array might look like this:
+ ({ "platinum", "gold", "silver", "electrum", "copper" })
+which is an array of type string. Individual data values in arrays are
+called elements, or sometimes members. In code, just as constant
+strings are represented by surrounding them with "", constant arrays are
+represented by being surrounded by ({ }), with individual elements of
+the array being separated by a ,.
+
+You may have arrays of any LPC data type, simple or complex. Arrays
+made up of mixes of values are called arrays of mixed type. In most
+LPC drivers, you declare an array using a throw-back to C language
+syntax for arrays. This syntax is often confusing for LPC coders
+because the syntax has a meaning in C that simply does not translate into
+LPC. Nevertheless, if we wanted an array of type string, we would
+declare it in the following manner:
+
+string *arr;
+
+In other words, the data type of the elements it will contain followed by
+a space and an asterisk. Remember, however, that this newly declared
+string array has a NULL value in it at the time of declaration.
+
+3.4 Using Arrays
+You now should understand how to declare and recognize an array in
+code. In order to understand how they work in code, let's review the
+bank code, this time using arrays:
+
+string *hard_currencies;
+
+int exchange(string str) {
+ string from, to;
+ int amt;
+
+ if(!str) return 0;
+ if(sscanf(str, "%d %s for %s", amt, from, to) != 3)
+return 0;
+ if(member_array(from, hard_currencies) == -1) {
+ notify_fail("We do not buy soft currencies!\n");
+ return 0;
+ }
+ ...
+}
+
+This code assumes hard_currencies is a global variable and is initialized
+in create() as:
+ hard_currencies = ({ "platinum", "gold", "electrum", "silver",
+ "copper" });
+Ideally, you would have hard currencies as a #define in a header file for
+all objects to use, but #define is a topic for a later chapter.
+
+Once you know what the member_array() efun does, this method
+certainly is much easier to read as well as is much more efficient and
+easier to code. In fact, you can probably guess what the
+member_array() efun does: It tells you if a given value is a member of
+the array in question. Specifically here, we want to know if the currency
+the player is trying to sell is an element in the hard_curencies array.
+What might be confusing to you is, not only does member_array() tell us
+if the value is an element in the array, but it in fact tells us which element
+of the array the value is.
+
+How does it tell you which element? It is easier to understand arrays if
+you think of the array variable as holding a number. In the value above,
+for the sake of argument, we will say that hard_currencies holds the
+value 179000. This value tells the driver where to look for the array
+hard_currencies represents. Thus, hard_currencies points to a place
+where the array values may be found. When someone is talking about
+the first element of the array, they want the element located at 179000.
+When the object needs the value of the second element of the array, it
+looks at 179000 + one value, then 179000 plus two values for the third,
+and so on. We can therefore access individual elements of an array by
+their index, which is the number of values beyond the starting point of
+the array we need to look to find the value. For the array
+hard_currencies array:
+"platinum" has an index of 0.
+"gold" has an index of 1.
+"electrum" has an index of 2.
+"silver" has an index of 3.
+"copper" has an index of 4.
+
+The efun member_array() thus returns the index of the element being
+tested if it is in the array, or -1 if it is not in the array. In order to
+reference an individual element in an array, you use its index number in
+the following manner:
+array_name[index_no]
+Example:
+hard_currencies[3]
+where hard_currencies[3] would refer to "silver".
+
+So, you now should now several ways in which arrays appear either as
+a whole or as individual elements. As a whole, you refer to an array
+variable by its name and an array constant by enclosing the array in ({ })
+and separating elements by ,. Individually, you refer to array variables
+by the array name followed by the element's index number enclosed in
+[], and to array constants in the same way you would refer to simple data
+types of the same type as the constant. Examples:
+
+Whole arrays:
+variable: arr
+constant: ({ "platinum", "gold", "electrum", "silver", "copper" })
+
+Individual members of arrays:
+variable: arr[2]
+constant: "electrum"
+
+You can use these means of reference to do all the things you are used to
+doing with other data types. You can assign values, use the values in
+operations, pass the values as parameters to functions, and use the
+values as return types. It is important to remember that when you are
+treating an element alone as an individual, the individual element is not
+itself an array (unless you are dealing with an array of arrays). In the
+example above, the individual elements are strings. So that:
+ str = arr[3] + " and " + arr[1];
+will create str to equal "silver and gold". Although this seems simple
+enough, many people new to arrays start to run into trouble when trying
+to add elements to an array. When you are treating an array as a whole
+and you wish to add a new element to it, you must do it by adding
+another array.
+
+Note the following example:
+string str1, str2;
+string *arr;
+
+str1 = "hi";
+str2 = "bye";
+/* str1 + str2 equals "hibye" */
+arr = ({ str1 }) + ({ str2 });
+/* arr is equal to ({ str1, str2 }) */
+Before going any further, I have to note that this example gives an
+extremely horrible way of building an array. You should set it: arr = ({
+str1, str2 }). The point of the example, however, is that you must add
+like types together. If you try adding an element to an array as the data
+type it is, you will get an error. Instead you have to treat it as an array of
+a single element.
+
+3.5 Mappings
+One of the major advances made in LPMuds since they were created is
+the mapping data type. People alternately refer to them as associative
+arrays. Practically speaking, a mapping allows you freedom from the
+association of a numerical index to a value which arrays require.
+Instead, mappings allow you to associate values with indices which
+actually have meaning to you, much like a relational database.
+
+In an array of 5 elements, you access those values solely by their integer
+indices which cover the range 0 to 4. Imagine going back to the example
+of money again. Players have money of different amounts and different
+types. In the player object, you need a way to store the types of money
+that exist as well as relate them to the amount of that currency type the
+player has. The best way to do this with arrays would have been to
+store an array of strings representing money types and an array of
+integers representing values in the player object. This would result in
+CPU-eating ugly code like this:
+
+int query_money(string type) {
+ int i;
+
+ i = member_array(type, currencies);
+ if(i>-1 && i < sizeof(amounts)) /* sizeof efun
+returns # of elements */
+ return amounts[i];
+ else return 0;
+}
+
+And that is a simple query function. Look at an add function:
+
+void add_money(string type, int amt) {
+ string *tmp1;
+ int * tmp2;
+ int i, x, j, maxj;
+
+ i = member_array(type, currencies);
+ if(i >= sizeof(amounts)) /* corrupt data, we are in
+ a bad way */
+ return;
+ else if(i== -1) {
+ currencies += ({ type });
+ amounts += ({ amt });
+ return;
+ }
+ else {
+ amounts[i] += amt;
+ if(amounts[i] < 1) {
+ tmp1 = allocate(sizeof(currencies)-1);
+ tmp2 = allocate(sizeof(amounts)-1);
+ for(j=0, x =0, maxj=sizeof(tmp1); j < maxj;
+ j++) {
+ if(j==i) x = 1;
+ tmp1[j] = currencies[j+x];
+ tmp2[j] = amounts[j+x];
+ }
+ currencies = tmp1;
+ amounts = tmp2;
+ }
+ }
+}
+
+That is really some nasty code to perform the rather simple concept of
+adding some money. First, we figure out if the player has any of that
+kind of money, and if so, which element of the currencies array it is.
+After that, we have to check to see that the integrity of the currency data
+has been maintained. If the index of the type in the currencies array is
+greater than the highest index of the amounts array, then we have a
+problem since the indices are our only way of relating the two arrays.
+Once we know our data is in tact, if the currency type is not currently
+held by the player, we simply tack on the type as a new element to the
+currencies array and the amount as a new element to the amounts array.
+Finally, if it is a currency the player currently has, we just add the
+amount to the corresponding index in the amounts array. If the money
+gets below 1, meaning having no money of that type, we want to clear
+the currency out of memory.
+
+Subtracting an element from an array is no simple matter. Take, for
+example, the result of the following:
+
+string *arr;
+
+arr = ({ "a", "b", "a" });
+arr -= ({ arr[2] });
+
+What do you think the final value of arr is? Well, it is:
+ ({ "b", "a" })
+Subtracting arr[2] from the original array does not remove the third
+element from the array. Instead, it subtracts the value of the third
+element of the array from the array. And array subtraction removes the
+first instance of the value from the array. Since we do not want to be
+<* NOTE Highlander@MorgenGrauen 11.2.94:
+ WRONG in MorgenGrauen (at least). The result is actually ({ "b" }). Array
+ subtraction removes ALL instances of the subtracted value from the array.
+ This holds true for all Amylaar-driver LPMuds.
+*>
+forced on counting on the elements of the array as being unique, we are
+forced to go through some somersaults to remove the correct element
+from both arrays in order to maintain the correspondence of the indices
+in the two arrays.
+
+Mappings provide a better way. They allow you to directly associate the
+money type with its value. Some people think of mappings as arrays
+where you are not restricted to integers as indices. Truth is, mappings
+are an entirely different concept in storing aggregate information. Arrays
+force you to choose an index which is meaningful to the machine for
+locating the appropriate data. The indices tell the machine how many
+elements beyond the first value the value you desire can be found. With
+mappings, you choose indices which are meaningful to you without
+worrying about how that machine locates and stores it.
+
+You may recognize mappings in the following forms:
+
+constant values:
+whole: ([ index:value, index:value ]) Ex: ([ "gold":10, "silver":20 ])
+element: 10
+
+variable values:
+whole: map (where map is the name of a mapping variable)
+element: map["gold"]
+
+So now my monetary functions would look like:
+
+int query_money(string type) { return money[type]; }
+
+void add_money(string type, int amt) {
+ if(!money[type]) money[type] = amt;
+ else money[type] += amt;
+ if(money[type] < 1)
+ map_delete(money, type); /* this is for
+ MudOS */
+ ...OR...
+ money = m_delete(money, type) /* for some
+ LPMud 3.* varieties */
+ ... OR...
+ m_delete(money, type); /* for other LPMud 3.*
+ varieties */
+}
+
+Please notice first that the efuns for clearing a mapping element from the
+mapping vary from driver to driver. Check with your driver's
+documentation for the exact name an syntax of the relevant efun.
+
+As you can see immediately, you do not need to check the integrity of
+your data since the values which interest you are inextricably bound to
+one another in the mapping. Secondly, getting rid of useless values is a
+simple efun call rather than a tricky, CPU-eating loop. Finally, the
+query function is made up solely of a return instruction.
+
+You must declare and initialize any mapping before using it.
+Declarations look like:
+mapping map;
+Whereas common initializations look like:
+map = ([]);
+map = m_allocate(10) ...OR... map = m_allocate(10);
+map = ([ "gold": 20, "silver": 15 ]);
+
+As with other data types, there are rules defining how they work in
+common operations like addition and subtraction:
+ ([ "gold":20, "silver":30 ]) + ([ "electrum":5 ])
+gives:
+ (["gold":20, "silver":30, "electrum":5])
+Although my demonstration shows a continuity of order, there is in fact
+no guarantee of the order in which elements of mappings will stored.
+Equivalence tests among mappings are therefore not a good thing.
+
+3.6 Summary
+Mappings and arrays can be built as complex as you need them to be.
+You can have an array of mappings of arrays. Such a thing would be
+declared like this:
+
+mapping *map_of_arrs;
+which might look like:
+({ ([ ind1: ({ valA1, valA2}), ind2: ({valB1, valB2}) ]), ([ indX:
+({valX1,valX2}) ]) })
+
+Mappings may use any data type as an index, including objects.
+Mapping indices are often referred to as keys as well, a term from
+databases. Always keep in mind that with any non-integer data type,
+you must first initialize a variable before making use of it in common
+operations such as addition and subtraction. In spite of the ease and
+dynamics added to LPC coding by mappings and arrays, errors caused
+by failing to initialize their values can be the most maddening experience
+for people new to these data types. I would venture that a very high
+percentage of all errors people experimenting with mappings and arrays
+for the first time encounter are one of three error messages:
+ Indexing on illegal type.
+ Illegal index.
+ Bad argument 1 to (+ += - -=) /* insert your favourite operator */
+Error messages 1 and 3 are darn near almost always caused by a failure
+to initialize the array or mapping in question. Error message 2 is caused
+generally when you are trying to use an index in an initialized array
+which does not exist. Also, for arrays, often people new to arrays will
+get error message 3 because they try to add a single element to an array
+by adding the initial array to the single element value instead of adding
+an array of the single element to the initial array. Remember, add only
+arrays to arrays.
+
+At this point, you should feel comfortable enough with mappings and
+arrays to play with them. Expect to encounter the above error messages
+a lot when first playing with these. The key to success with mappings is
+in debugging all of these errors and seeing exactly what causes wholes
+in your programming which allow you to try to work with uninitialized
+mappings and arrays. Finally, go back through the basic room code and
+look at things like the set_exits() (or the equivalent on your mudlib)
+function. Chances are it makes use of mappings. In some instances, it
+will use arrays as well for compatibility with mudlib.n.
+
+Copyright (c) George Reese 1993
diff --git a/doc/KURS/LPC-KURS2/chapter4 b/doc/KURS/LPC-KURS2/chapter4
new file mode 100644
index 0000000..c3e9905
--- /dev/null
+++ b/doc/KURS/LPC-KURS2/chapter4
@@ -0,0 +1,195 @@
+Intermediate LPC
+Descartes of Borg
+November 1993
+
+ Chapter 4: The LPC Pre-Compiler
+
+4.1 Review
+The previous chapter was quite heavy, so now I will slow down a bit so
+you can digest and play with mappings and arrays by taking on the
+rather simple topic of the LPC pre-compiler. By this point, however,
+you should well understand how the driver interacts with the mudlib and
+be able to code objects which use call outs and heart beats. In addition,
+you should be coding simple objects which use mappings and arrays,
+noting how these data types perform in objects. It is also a good idea to
+start looking in detail at the actual mudlib code that makes up your mud.
+See if you understand everything which is going on in your mudlibs
+room and monster codes. For things you do not understand, ask the
+people on your mud designated to answer creator coding questions.
+
+Pre-compiler is actually a bit of a misnomer since LPC code is never
+truly compiled. Although this is changing with prototypes of newer
+LPC drivers, LPC drivers interpret the LPC code written by creators
+rather than compile it into binary format. Nevertheless, the LPC pre-
+compiler functions still perform much like pre-compilers for compiled
+languages in that pre-compiler directives are interpreted before the driver
+even starts to look at object code.
+
+4.2 Pre-compiler Directives
+If you do not know what a pre-compiler is, you really do not need to
+worry. With respect to LPC, it is basically a process which happens
+before the driver begins to interpret LPC code which allows you to
+perform actions upon the entire code found in your file. Since the code
+is not yet interpreted, the pre-compiler process is involved before the file
+exists as an object and before any LPC functions or instructions are ever
+examined. The pre-compiler is thus working at the file level, meaning
+that it does not deal with any code in inherited files.
+
+The pre-compiler searches a file sent to it for pre-compiler directives.
+These are little instructions in the file meant only for the pre-compiler
+and are not really part of the LPC language. A pre-compiler directive is
+any line in a file beginning with a pound (#) sign. Pre-compiler
+directives are generally used to construct what the final code of a file will
+look at. The most common pre-compiler directives are:
+
+#define
+#undefine
+#include
+#ifdef
+#ifndef
+#if
+#elseif
+#else
+#endif
+#pragma
+
+Most realm coders on muds use exclusively the directives #define and
+#include. The other directives you may see often and should understand
+what they mean even if you never use them.
+
+The first pair of directives are:
+#define
+#undefine
+
+The #define directive sets up a set of characters which will be replaced
+any where they exist in the code at precompiler time with their definition.
+For example, take:
+
+#define OB_USER "/std/user"
+
+This directive has the pre-compiler search the entire file for instances of
+OB_USER. Everywhere it sees OB_USER, it replaces with "/std/user".
+<* NOTE Highlander@MorgenGrauen 11.2.94:
+ WRONG. OB_USER will _not_ be replaced if within "" in which case it is
+ treated as a normal string. So it is possible to write the text OB_USER.
+*>
+Note that it does not make OB_USER a variable in the code. The LPC
+interpreter never sees the OB_USER label. As stated above, the pre-
+compiler is a process which takes place before code interpretation. So
+what you wrote as:
+
+#define OB_USER "/std/user"
+
+void create() {
+ if(!file_exists(OB_USER+".c")) write("Merde! No user file!");
+ else write("Good! User file still exists!");
+}
+
+would arrive at the LPC interpreter as:
+
+void create() {
+ if(!file_exists("/std/user"+".c")) write("Merde! No user file!");
+ else write("Good! User file still exists!");
+}
+
+<* NOTE Highlander@MorgenGrauen 11.2.94
+ But: write("Text is OB_USER foo bar\n");
+ simply writes "Text is OB_USER foo bar". Confer previous note.
+*>
+
+Simply put, #define just literally replaces the defined label with whatever
+follows it. You may also use #define in a special instance where no
+value follows. This is called a binary definition. For example:
+
+#define __NIGHTMARE
+
+exists in the config file for the Nightmare Mudlib. This allows for pre-
+compiler tests which will be described later in the chapter.
+
+The other pre-compiler directive you are likely to use often is #include.
+As the name implies, #include includes the contents of another file right
+into the file being pre-compiled at the point in the file where the directive
+is placed. Files made for inclusion into other files are often called header
+files. They sometimes contain things like #define directives used by
+multiple files and function declarations for the file. The traditional file
+extension to header files is .h.
+
+Include directives follow one of 2 syntax's:
+
+#include <filename>
+#include "filename"
+
+If you give the absolute name of the file, then which syntax you use is
+irrelevant. How you enclose the file name determines how the pre-
+compiler searches for the header files. The pre-compiler first searches in
+system include directories for files enclosed in <>. For files enclosed in
+"", the pre-compiler begins its search in the same directory as the file
+going through the pre-compiler. Either way, the pre-compiler will
+search the system include directories and the directory of the file for the
+header file before giving up. The syntax simply determines the order.
+<* NOTE Highlander@MorgenGrauen 11.2.94
+ When using standard-headerfiles one should choose <>. "" is appropriate
+ when dealing with selfdefined headerfiles.
+*>
+
+The simplest pre-compiler directive is the #pragma directive. It is
+doubtful you will ever use this one. Basically, you follow the directive
+with some keyword which is meaningful to your driver. The only
+keyword I have ever seen is strict_types, which simply lets the driver
+know you want this file interpreted with strict data typing. I doubt you
+will ever need to use this, and you may never even see it. I just included
+it in the list in the event you do see it so you do not think it is doing
+anything truly meaningful.
+
+The final group of pre-compiler directives are the conditional pre-
+compiler directives. They allow you to pre-compile the file one way
+given the truth value of an expression, otherwise pre-compile the file
+another way. This is mostly useful for making code portable among
+mudlibs, since putting the m_delete() efun in code on a MudOS mud
+would normally cause an error, for example. So you might write the
+following:
+
+#ifdef MUDOS
+ map_delete(map, key);
+#else
+ map = m_delete(map, key);
+#endif
+
+which after being passed through the pre-compiler will appear to the
+interpreter as:
+
+ map_delete(map, key);
+
+on a MudOS mud, and:
+
+ map = m_delete(map, key);
+
+on other muds. The interpreter never sees the function call that would
+cause it to spam out in error.
+
+Notice that my example made use of a binary definition as described
+above. Binary definitions allow you to pass certain code to the
+interpreter based on what driver or mudlib you are using, among other
+conditions.
+
+4.3 Summary
+The pre-compiler is a useful LPC tool for maintaining modularity among
+your programs. When you have values that might be subject to change,
+but are used widely throughout your files, you might stick all of those
+values in a header file as #define statements so that any need to make a
+future change will cause you to need to change just the #define directive.
+A very good example of where this would be useful would be a header
+file called money.h which includes the directive:
+#define HARD_CURRENCIES ({ "gold", "platinum", "silver",
+"electrum", "copper" })
+so that if ever you wanted to add a new hard currency, you only need
+change this directive in order to update all files needing to know what the
+hard currencies are.
+
+The LPC pre-compiler also allows you to write code which can be
+ported without change among different mudlibs and drivers. Finally,
+you should be aware that the pre-compiler only accepts lines ending in
+carriage returns. If you want a multiple line pre-compiler directive, you
+need to end each incomplete line with a backslash(\).
+
+Copyright (c) George Reese 1993
diff --git a/doc/KURS/LPC-KURS2/chapter5 b/doc/KURS/LPC-KURS2/chapter5
new file mode 100644
index 0000000..f45b6fa
--- /dev/null
+++ b/doc/KURS/LPC-KURS2/chapter5
@@ -0,0 +1,186 @@
+Intermediate LPC
+Descartes of Borg
+November 1993
+
+ Chapter 5: Advanced String Handling
+
+5.1 What a String Is
+The LPC Basics textbook taught strings as simple data types. LPC
+generally deals with strings in such a matter. The underlying driver
+program, however, is written in C, which has no string data type. The
+driver in fact sees strings as a complex data type made up of an array of
+characters, a simple C data type. LPC, on the other hand does not
+recognize a character data type (there may actually be a driver or two out
+there which do recognize the character as a data type, but in general not).
+The net effect is that there are some array-like things you can do with
+strings that you cannot do with other LPC data types.
+
+The first efun regarding strings you should learn is the strlen() efun.
+This efun returns the length in characters of an LPC string, and is thus
+the string equivalent to sizeof() for arrays. Just from the behaviour of
+this efun, you can see that the driver treats a string as if it were made up
+of smaller elements. In this chapter, you will learn how to deal with
+strings on a more basic level, as characters and sub strings.
+
+5.2 Strings as Character Arrays
+You can do nearly anything with strings that you can do with arrays,
+except assign values on a character basis. At the most basic, you can
+actually refer to character constants by enclosing them in '' (single
+quotes). 'a' and "a" are therefore very different things in LPC. 'a'
+represents a character which cannot be used in assignment statements or
+any other operations except comparison evaluations. "a" on the other
+hand is a string made up of a single character. You can add and subtract
+other strings to it and assign it as a value to a variable.
+
+With string variables, you can access the individual characters to run
+comparisons against character constants using exactly the same syntax
+that is used with arrays. In other words, the statement:
+ if(str[2] == 'a')
+is a valid LPC statement comparing the second character in the str string
+to the character 'a'. You have to be very careful that you are not
+comparing elements of arrays to characters, nor are you comparing
+characters of strings to strings.
+
+LPC also allows you to access several characters together using LPC's
+range operator ..:
+ if(str[0..1] == "ab")
+In other words, you can look for the string which is formed by the
+characters 0 through 1 in the string str. As with arrays, you must be
+careful when using indexing or range operators so that you do not try to
+reference an index number larger than the last index. Doing so will
+result in an error.
+
+Now you can see a couple of similarities between strings and arrays:
+1) You may index on both to access the values of individual elements.
+ a) The individual elements of strings are characters
+ b) The individual elements of arrays match the data type of the
+array.
+2) You may operate on a range of values
+ a) Ex: "abcdef"[1..3] is the string "bcd"
+ b) Ex: ({ 1, 2, 3, 4, 5 })[1..3] is the int array ({ 2, 3, 4 })
+<* NOTE Highlander@MorgenGrauen
+ Also possible in MorgenGrauen (in common: Amylaar-driver LPMuds):
+ "abcdef"[2..] -> "cdef" and
+ "abcdef"[1..<2] -> "bcde" (< means start counting from the end and with 1)
+*>
+
+And of course, you should always keep in mind the fundamental
+difference: a string is not made up of a more fundamental LPC data type.
+In other words, you may not act on the individual characters by
+assigning them values.
+
+5.3 The Efun sscanf()
+You cannot do any decent string handling in LPC without using
+sscanf(). Without it, you are left trying to play with the full strings
+passed by command statements to the command functions. In other
+words, you could not handle a command like: "give sword to leo", since
+you would have no way of separating "sword to leo" into its constituent
+parts. Commands such as these therefore use this efun in order to use
+commands with multiple arguments or to make commands more
+"English-like".
+
+Most people find the manual entries for sscanf() to be rather difficult
+reading. The function does not lend itself well to the format used by
+manual entries. As I said above, the function is used to take a string and
+break it into usable parts. Technically it is supposed to take a string and
+scan it into one or more variables of varying types. Take the example
+above:
+
+int give(string str) {
+ string what, whom;
+
+ if(!str) return notify_fail("Give what to whom?\n");
+ if(sscanf(str, "%s to %s", what, whom) != 2)
+ return notify_fail("Give what to whom?\n");
+ ... rest of give code ...
+}
+
+The efun sscanf() takes three or more arguments. The first argument is
+the string you want scanned. The second argument is called a control
+string. The control string is a model which demonstrates in what form
+the original string is written, and how it should be divided up. The rest
+of the arguments are variables to which you will assign values based
+upon the control string.
+
+The control string is made up of three different types of elements: 1)
+constants, 2) variable arguments to be scanned, and 3) variable
+arguments to be discarded. You must have as many of the variable
+arguments in sscanf() as you have elements of type 2 in your control
+string. In the above example, the control string was "%s to %s", which
+is a three element control string made up of one constant part (" to "),
+and two variable arguments to be scanned ("%s"). There were no
+variables to be discarded.
+
+The control string basically indicates that the function should find the
+string " to " in the string str. Whatever comes before that constant will
+be placed into the first variable argument as a string. The same thing
+will happen to whatever comes after the constant.
+
+Variable elements are noted by a "%" sign followed by a code for
+decoding them. If the variable element is to be discarded, the "%" sign
+is followed by the "*" as well as the code for decoding the variable.
+Common codes for variable element decoding are "s" for strings and "d"
+for integers. In addition, your mudlib may support other conversion
+codes, such as "f" for float. So in the two examples above, the "%s" in
+the control string indicates that whatever lies in the original string in the
+corresponding place will be scanned into a new variable as a string.
+
+A simple exercise. How would you turn the string "145" into an
+integer?
+
+Answer:
+int x;
+sscanf("145", "%d", x);
+
+After the sscanf() function, x will equal the integer 145.
+
+Whenever you scan a string against a control string, the function
+searches the original string for the first instance of the first constant in
+the original string. For example, if your string is "magic attack 100" and
+you have the following:
+int improve(string str) {
+ string skill;
+ int x;
+
+ if(sscanf(str, "%s %d", skill, x) != 2) return 0;
+ ...
+}
+you would find that you have come up with the wrong return value for
+sscanf() (more on the return values later). The control string, "%s %d",
+is made up of to variables to be scanned and one constant. The constant
+is " ". So the function searches the original string for the first instance
+of " ", placing whatever comes before the " " into skill, and trying to
+place whatever comes after the " " into x. This separates "magic attack
+100" into the components "magic" and "attack 100". The function,
+however, cannot make heads or tales of "attack 100" as an integer, so it
+returns 1, meaning that 1 variable value was successfully scanned
+("magic" into skill).
+
+Perhaps you guessed from the above examples, but the efun sscanf()
+returns an int, which is the number of variables into which values from
+the original string were successfully scanned. Some examples with
+return values for you to examine:
+
+sscanf("swo rd descartes", "%s to %s", str1, str2) return: 0
+sscanf("swo rd descartes", "%s %s", str1, str2) return: 2
+sscanf("200 gold to descartes", "%d %s to %s", x, str1, str2) return: 3
+sscanf("200 gold to descartes", "%d %*s to %s", x, str1) return: 2
+where x is an int and str1 and str2 are string
+
+5.4 Summary
+LPC strings can be thought of as arrays of characters, yet always
+keeping in mind that LPC does not have the character data type (with
+most, but not all drivers). Since the character is not a true LPC data
+type, you cannot act upon individual characters in an LPC string in the
+same manner you would act upon different data types. Noticing the
+intimate relationship between strings and arrays nevertheless makes it
+easier to understand such concepts as the range operator and indexing on
+strings.
+
+There are efuns other than sscanf() which involve advanced string
+handling, however, they are not needed nearly as often. You should
+check on your mud for man or help files on the efuns: explode(),
+implode(), replace_string(), sprintf(). All of these are very valuable
+tools, especially if you intend to do coding at the mudlib level.
+
+Copyright (c) George Reese 1993
diff --git a/doc/KURS/LPC-KURS2/chapter6 b/doc/KURS/LPC-KURS2/chapter6
new file mode 100644
index 0000000..98b3552
--- /dev/null
+++ b/doc/KURS/LPC-KURS2/chapter6
@@ -0,0 +1,276 @@
+Intermediate LPC
+Descartes of Borg
+November 1993
+
+ Chapter 6: Intermediate Inheritance
+
+6.1 Basics of Inheritance
+In the textbook LPC Basics, you learned how it is the mudlib maintains
+consistency amoung mud objects through inheritance. Inheritance
+allows the mud administrators to code the basic functions and such that
+all mudlib objects, or all mudlib objects of a certain type must have so
+that you can concentrate on creating the functions which make these
+objects different. When you build a room, or a weapon, or a monster,
+you are taking a set of functions already written for you and inheriting
+them into your object. In this way, all objects on the mud can count on
+other objects to behave in a certain manner. For instance, player objects
+can rely on the fact that all room objects will have a function in them
+called query_long() which describes the room. Inheritance thus keeps
+you from having to worry about what the function query_long() should
+look like.
+
+Naturally, this textbook tries to go beyond this fundamental knowledge
+of inheritance to give the coder a better undertstanding of how
+inheritance works in LPC programming. Without getting into detail that
+the advanced domain coder/beginner mudlib coder simply does not yet
+need, this chapter will try to explain exactly what happens when you
+inherit an object.
+
+6.2 Cloning and Inheritance
+Whenever a file is referenced for the first time as an object (as opposed
+to reading the contents of the file), the game tries to load the file into
+memory and create an object. If the object is successfully loaded into
+memory, it becomes as master copy. Master copies of objects may be
+cloned but not used as actual game objects. The master copy is used to
+support any clone objects in the game.
+
+The master copy is the source of one of the controversies of mud LPC
+coding, that is whether to clone or inherit. With rooms, there is no
+question of what you wish to do, since there should only be one instance
+of each room object in the game. So you generally use inheritance in
+creating rooms. Many mud administrators, including myself, however
+encourage creators to clone the standard monster object and configure it
+from inside room objects instead of keeping monsters in separate files
+which inherit the standard monster object.
+
+As I stated above, each time a file is referenced to create an object, a
+master copy is loaded into memory. When you do something like:
+void reset() {
+ object ob;
+ ob = new("/std/monster");
+ /* clone_object("/std/monster") some places */
+ ob->set_name("foo monster");
+ ... rest of monster config code followed by moving
+it to the room ...
+}
+the driver searches to see if their is a master object called "/std/monster".
+If not, it creates one. If it does exist, or after it has been created, the
+driver then creates a clone object called "/std/monster#<number>". If
+this is the first time "/std/monster" is being referenced, in effect, two
+objects are being created: the master object and the cloned instance.
+
+On the other hand, let's say you did all your configuring in the create()
+of a special monster file which inherits "/std/monster". Instead of
+cloning the standard monster object from your room, you clone your
+monster file. If the standard monster has not been loaded, it gets loaded
+since your monster inherits it. In addition, a master copy of your file
+gets loaded into memory. Finally, a clone of your monster is created
+and moved into the room, for a total of three objects added to the game.
+Note that you cannot make use of the master copy easily to get around
+this. If, for example, you were to do:
+ "/wizards/descartes/my_monster"->move(this_object());
+instead of
+ new("/wizards/descartes/my_monster")->move(this_object());
+you would not be able to modify the file "my_monster.c" and update it,
+since the update command destroys the current master version of an
+object. On some mudlibs it also loads the new version into memory.
+Imagine the look on a player's face when their monster disappears in
+mid-combat cause you updated the file!
+
+Cloning is therefore a useful too when you plan on doing just that-
+cloning. If you are doing nothing special to a monster which cannot be
+done through a few call others, then you will save the mud from getting
+loaded with useless master copies. Inheritance, however, is useful if
+you plan to add functionality to an object (write your own functions) or
+if you have a single configuration that gets used over and over again
+(you have an army of orc guards all the same, so you write a special orc
+file and clone it).
+
+6.3 Inside Inheritance
+When objects A and B inherit object C, all three objects have their own
+set of data sharing one set of function definitions from object C. In
+addition, A and B will have separate functions definitions which were
+entered separately into their code. For the sake of example throughout
+the rest of the chapter, we will use the following code. Do not be
+disturbed if, at this point, some of the code makes no sense:
+
+OBJECT C
+private string name, cap_name, short, long;
+private int setup;
+
+void set_name(string str)
+nomask string query_name();
+private int query_setup();
+static void unsetup();
+void set_short(string str);
+string query_short();
+void set_long(string str);
+string query_long();
+
+
+void set_name(string str) {
+ if(!query_setup()) {
+ name = str;
+ setup = 1;
+}
+
+nomask string query_name() { return name; }
+
+private query_setup() { return setup; }
+
+static void unsetup() { setup = 0; }
+
+string query_cap_name() {
+ return (name ? capitalize(name) : ""); }
+}
+
+void set_short(string str) { short = str; }
+
+string query_short() { return short; }
+
+void set_long(string str) { long = str; }
+
+string query_long() { return str; }
+
+void create() { seteuid(getuid()); }
+
+OBJECT B
+inherit "/std/objectc";
+
+private int wc;
+
+void set_wc(int wc);
+int query_wc();
+int wieldweapon(string str);
+
+void create() { ::create(); }
+
+void init() {
+ if(environment(this_object()) == this_player())
+ add_action("wieldweapon", "wield");
+}
+
+void set_wc(int x) { wc = x; }
+
+int query_wc() { return wc; }
+
+int wieldweapon(string str) {
+ ... code for wielding the weapon ...
+}
+
+OBJECT A
+inherit "/std/objectc";
+
+int ghost;
+
+void create() { ::create(); }
+
+void change_name(string str) {
+ if(!((int)this_object()->is_player())) unsetup();
+ set_name(str);
+}
+
+string query_cap_name() {
+ if(ghost) return "A ghost";
+ else return ::query_cap_name();
+}
+
+As you can see, object C is inherited both by object A and object B.
+Object C is a representation of a much oversimplified base object, with B
+being an equally oversimplified weapon and A being an equally
+simplified living object. Only one copy of each function is retained in
+memory, even though we have here three objects using the functions.
+There are of course, three instances of the variables from Object C in
+memory, with one instance of the variables of Object A and Object B in
+memory. Each object thus gets its own data.
+
+6.4 Function and Variable Labels
+Notice that many of the functions above are proceeded with labels which
+have not yet appeared in either this text or the beginner text, the labels
+static, private, and nomask. These labels define special priveledges
+which an object may have to its data and member functions. Functions
+you have used up to this point have the default label public. This is
+default to such a degree, some drivers do not support the labeling.
+
+A public variable is available to any object down the inheritance tree
+from the object in which the variable is declared. Public variables in
+object C may be accessed by both objects A and B. Similarly, public
+functions may be called by any object down the inheritance tree from the
+object in which they are declared.
+
+The opposite of public is of course private. A private variable or
+function may only be referenced from inside the object which declares it.
+If object A or B tried to make any reference to any of the variables in
+object C, an error would result, since the variables are said to be out of
+scope, or not available to inheriting classes due to their private labels.
+Functions, however, provide a unique challenge which variables do not.
+External objects in LPC have the ability to call functions in other objects
+through call others. The private label does not protect against call
+others.
+
+To protect against call others, functions use the label static. A function
+which is static may only be called from inside the complete object or
+from the game driver. By complete object, I mean object A can call
+static functions in the object C it inherits. The static only protects against
+external call others. In addition, this_object()->foo() is considered an
+internal call as far as the static label goes.
+
+Since variables cannot be referenced externally, there is no need for an
+equivalent label for them. Somewhere along the line, someone decided
+to muddy up the waters and use the static label with variables to have a
+completely separate meaning. What is even more maddening is that this
+label has nothing to do with what it means in the C programming
+language. A static variable is simply a variable that does not get saved to
+file through the efun save_object() and does not get restored through
+restore_object(). Go figure.
+
+In general, it is good practice to have private variables with public
+functions, using query_*() functions to access the values of inherited
+variables, and set_*(), add_*(), and other such functions to change
+those values. In realm coding this is not something one really has to
+worry a lot about. As a matter of fact, in realm coding you do not have
+to know much of anything which is in this chapter. To be come a really
+good realm coder, however, you have to be able to read the mudlib
+code. And mudlib code is full of these labels. So you should work
+around with these labels until you can read code and understand why it
+is written that way and what it means to objects which inherit the code.
+
+The final label is nomask, and it deals with a property of inheritance
+which allows you to rewrite functions which have already been defined.
+For example, you can see above that object A rewrote the function
+query_cap_name(). A rewrite of function is called overriding the
+function. The most common override of a function would be in a case
+like this, where a condition peculiar to our object (object A) needs to
+happen on a call ot the function under certain circumstances. Putting test
+code into object C just so object A can be a ghost is plain silly. So
+instead, we override query_cap_name() in object A, testing to see if the
+object is a ghost. If so, we change what happens when another object
+queries for the cap name. If it is not a ghost, then we want the regular
+object behaviour to happen. We therefore use the scope resolution
+operator (::) to call the inherited version of the query_cap_name()
+function and return its value.
+
+A nomask function is one which cannot be overridden either through
+inheritance or through shadowing. Shadowing is a sort of backwards
+inheritance which will be detailed in the advanced LPC textbook. In the
+example above, neither object A nor object B (nor any other object for
+that matter) can override query_name(). Since we want to use
+query_name() as a unique identifier of objects, we don't want people
+faking us through shadowing or inheritance. The function therefore gets
+the nomask label.
+
+6.5 Summary
+Through inheritance, a coder may make user of functions defined in
+other objects in order to reduce the tedium of producing masses of
+similar objects and to increase the consistency of object behaviour across
+mudlib objects. LPC inheritance allows objects maximum priveledges in
+defining how their data can be accessed by external objects as well as
+objects inheriting them. This data security is maintained through the
+keywords, nomask, private, and static.
+
+In addition, a coder is able to change the functionality of non-protected
+functions by overriding them. Even in the process of overriding a
+function, however, an object may access the original function through
+the scope resolution operator.
+
+Copyright (c) George Reese 1993
diff --git a/doc/KURS/LPC-KURS2/chapter7 b/doc/KURS/LPC-KURS2/chapter7
new file mode 100644
index 0000000..aa8cc0e
--- /dev/null
+++ b/doc/KURS/LPC-KURS2/chapter7
@@ -0,0 +1,298 @@
+Intermediate LPC
+Descartes of Borg
+November 1993
+
+ Chapter 7: Debugging
+
+7.1 Types of Errors
+By now, you have likely run into errors here, there, and everywhere. In
+general, there are three sorts of errors you might see: compile time
+errors, run time errors, and malfunctioning code. On most muds you
+will find a personal file where your compile time errors are logged. For
+the most part, this file can be found either in your home directory as the
+file named "log" or ".log", or somewhere in the directory "/log" as a file
+with your name.. In addition, muds tend to keep a log of run time errors
+which occur while the mud is up. Again, this is generally found in
+"/log". On MudOS muds it is called "debug.log". On other muds it may
+be called something different like "lpmud.log". Ask your administrators
+where compile time and run time errors are each logged if you do not
+already know.
+
+Compile time errors are errors which occur when the driver tries to load
+an object into memory. If, when the driver is trying to load an object
+into memory, it encounters things which it simply does not understand
+with respect to what you wrote, it will fail to load it into memory and log
+why it could not load the object into your personal error log. The most
+common compile time errors are typos, missing or extra (), {}. [], or "",
+and failure to declare properly functions and variables used by the
+object.
+
+Run time errors occur when something wrong happens to an object in
+memory while it is executing a statement. For example, the driver
+cannot tell whether the statement "x/y" will be valid in all circumstances.
+In fact, it is a valid LPC expression. Yet, if the value of y is 0, then a
+run time error will occur since you cannot divide by 0. When the driver
+runs across an error during the execution of a function, it aborts
+execution of the function and logs an error to the game's run time error
+log. It will also show the error to this_player(), if defined, if the player
+is a creator, or it will show "What?" to players. Most common causes
+for run time errors are bad values and trying to perform operations with
+data types for which those operations are not defined.
+
+The most insideous type of error, however, is plain malfunctioning
+code. These errors do not log, since the driver never really realizes that
+anything is wrong. In short, this error happens when you think the code
+says one thing, but in fact it says another thing. People too often
+encounter this bug and automatically insist that it must be a mudlib or
+driver bug. Everyone makes all types of errors though, and more often
+than not when code is not functioning the way you should, it will be
+because you misread it.
+
+7.2 Debugging Compile Time Errors
+Compile time errors are certainly the most common and simplest bugs to
+debug. New coders often get frustrated by them due to the obscure
+nature of some error messages. Nevertheless, once a person becomes
+used to the error messages generated by their driver, debugging compile
+time errors becomes utterly routine.
+
+In your error log, the driver will tell you the type of error and on which
+line it finally noticed there was an error. Note that this is not on which
+line the actual error necessarily exists. The most common compile time
+error, besides the typo, is the missing or superfluous parentheses,
+brackets, braces, or quotes. Yet this error is the one that most baffles
+new coders, since the driver will not notice the missing or extra piece
+until well after the original. Take for example the following code:
+
+1 int test(string str) {
+2 int x;
+3 for(x =0; x<10; x++)
+4 write(x+"\n");
+5 }
+6 write("Done.\n");
+7 }
+
+Depending on what you intended, the actual error here is either at line 3
+(meaning you are missing a {) or at line 5 (meaing you have an extra }).
+Nevertheless, the driver will report that it found an error when it gets to
+line 6. The actual driver message may vary from driver to driver, but no
+matter which driver, you will see an error on line 6, since the } in line 5
+is interpreted as ending the function test(). At line 6, the driver sees that
+you have a write() sitting outside any function definition, and thus
+reports an error. Generally, the driver will also go on to report that it
+found an error at line 7 in the form of an extra }.
+
+The secret to debugging these is coding style. Having closing } match
+up vertically with the clauses they close out helps you see where you are
+missing them when you are debugging code. Similarly, when using
+multiple sets of parentheses, space out different groups like this:
+ if( (x=sizeof(who=users()) > ( (y+z)/(a-b) + (-(random(7))) ) )
+As you can see, the parentheses for the for() statement, are spaced out
+from the rest of the statement. In addition, individual sub-groups are
+spaced so they can easily be sorted out in the event of an error.
+
+Once you have a coding style which aids in picking these out, you learn
+which error messages tend to indicate this sort of error. When
+debugging this sort of error, you then view a section of code before and
+after the line in question. In most all cases, you will catch the bug right
+off.
+
+Another common compile time error is where the driver reports an
+unknown identifier. Generally, typos and failure to declare variables
+causes this sort of error. Fortunately, the error log will almost always
+tell you exactly where the error is. So when debugging it, enter the
+editor and find the line in question. If the problem is with a variable and
+is not a typo, make sure you declared it properly. On the other hand, if
+it is a typo, simply fix it!
+
+One thing to beware of, however, is that this error will sometimes be
+reported in conjunction with a missing parentheses, brackets, or braces
+type error. In these situations, your problem with an unknown identifier
+is often bogus. The driver misreads the way the {} or whatever are
+setup, and thus gets variable declarations confused. Therefore make
+sure all other compile time errors are corrected before bothering with
+these types of errors.
+
+In the same class with the above error, is the general syntax error. The
+driver generates this error when it simply fails to understand what you
+said. Again, this is often caused by typos, but can also be caused by not
+properly understanding the syntax of a certain feature like writing a for()
+statement: for(x=0, x<10, x++). If you get an error like this which is
+not a syntax error, try reviewing the syntax of the statement in which the
+error is occurring.
+
+7.3 Debugging Run Time Errors
+Run time errors are much more complex than their compile time
+counterparts. Fortunately these errors do get logged, though many
+creators do not realise or they do not know where to look. The error log
+for run time errors are also generally much more detailed than compile
+time errors, meaning that you can trace the history of the execution train
+from where it started to where it went wrong. You therefore can setup
+debugging traps using precompiler statements much easier using these
+logs. Run time errors, however, tend to result from using more
+complex codign techniques than beginners tend to use, which means you
+are left with errors which are generally more complicated than simple
+compile time errors.
+
+Run time errors almost always result from misusing LPC data types.
+Most commonly, trying to do call others using object variables which are
+NULL, indexing on mapping, array, or string variables which are
+NULL, or passing bad arguments to functions. We will look at a real
+run time error log from Nightmare:
+
+Bad argument 1 to explode()
+program: bin/system/_grep.c, object: bin/system/_grep
+line 32
+' cmd_hook' in ' std/living.c' ('
+std/user#4002')line 83
+' cmd_grep' in ' bin/system/_grep.c' ('
+bin/system/_grep')line 32
+Bad argument 2 to message()
+program: adm/obj/simul_efun.c, object: adm/obj/simul_efun
+line 34
+' cmd_hook' in ' std/living.c' ('
+std/user#4957')line 83
+' cmd_look' in ' bin/mortal/_look.c' ('
+bin/mortal/_look')line 23
+' examine_object' in ' bin/mortal/_look.c' ('
+bin/mortal/_look')line 78
+' write' in 'adm/obj/simul_efun.c' ('
+adm/obj/simul_efun')line 34
+Bad argument 1 to call_other()
+program: bin/system/_clone.c, object: bin/system/_clone
+line 25
+' cmd_hook' in ' std/living.c' ('
+std/user#3734')line 83
+' cmd_clone' in ' bin/system/_clone.c' ('
+bin/system/_clone')line 25
+Illegal index
+program: std/monster.c, object:
+wizards/zaknaifen/spy#7205 line 76
+' heart_beat' in ' std/monster.c'
+('wizards/zaknaifen/spy#7205')line
+76
+
+All of the errors, except the last one, involve passing a bad argument to a
+function. The first bug, involves passing a bad first arument to the efun
+explode(). This efun expects a string as its first argment. In debugging
+these kinds of errors, we would therefore go to line 32 in
+/bin/system/_grep.c and check to see what the data type of the first
+argument being passed in fact is. In this particular case, the value being
+passed should be a string.
+
+If for some reason I has actually passed something else, I would be done
+debugging at that point and fix it simply by making sure that I was
+passing a string. This situation is more complex. I now need to trace
+the actual values contained by the variable being passed to explode, so
+that I can see what it is the explode() efun sees that it is being passed.
+
+The line is question is this:
+ borg[files[i]] = regexp(explode(read_file(files[i]), "\n"), exp);
+where files is an array for strings, i is an integer, and borg is a mapping.
+So clearly we need to find out what the value of read_file(files[i]) is.
+Well, this efun returns a string unless the file in question does not exist,
+the object in question does not have read access to the file in question, or
+the file in question is an empty file, in which cases the function will
+return NULL. Clearly, our problem is that one of these events must
+have happened. In order to see which, we need to look at files[i].
+
+Examining the code, the files array gets its value through the get_dir()
+efun. This returns all the files in a directory if the object has read access
+to the directory. Therefore the problem is neither lack of access or non-
+existent files. The file which caused this error then must have been an
+empty file. And, in fact, that is exactly what caused this error. To
+debug that, we would pass files through the filter() efun and make
+sure that only files with a file size greater than 0 were allowed into the
+array.
+
+The key to debugging a run time error is therefore knowing exactly what
+the values of all variables in question are at the exact moment where the
+bug created. When reading your run time log, be careful to separate the
+object from the file in which the bug occurred. For example, the
+indexing error above came about in the object /wizards/zaknaifen/spy,
+but the error occured while running a function in /std/monster.c, which
+the object inherited.
+
+7.4 Malfunctioning Code
+The nastiest problem to deal with is when your code does not behave the
+way you intended it to behave. The object loads fine, and it produces no
+run time errors, but things simply do not happen the way they should.
+Since the driver does not see a problem with this type of code, no logs
+are produced. You therefore need to go through the code line by line
+and figure out what is happening.
+
+Step 1: Locate the last line of code you knew successfully executed
+Step 2: Locate the first line of code where you know things are going
+wrong
+Step 3: Examine the flow of the code from the known successful point to
+the first known unsuccessful point.
+
+More often than not, these problems occurr when you are using if()
+statements and not accounting for all possibilities. For example:
+
+int cmd(string tmp) {
+ if(stringp(tmp)) return do_a()
+ else if(intp(tmp)) return do_b()
+ return 1;
+}
+
+In this code, we find that it compiles and runs fine. Problem is nothing
+happens when it is executed. We know for sure that the cmd() function
+is getting executed, so we can start there. We also know that a value of
+1 is in fact being returned, since we do not see "What?" when we enter
+the command. Immediately, we can see that for some reason the
+variable tmp has a value other than string or int. As it turns out, we
+issued the command without parameters, so tmp was NULL and failed
+all tests.
+
+The above example is rather simplistic, bordering on silly.
+Nevertheless, it gives you an idea of how to examine the flow of the
+code when debugging malfunctioning code. Other tools are available as
+well to help in debugging code. The most important tool is the use of
+the precompiler to debug code. With the code above, we have a clause
+checking for integers being passed to cmd(). When we type "cmd 10",
+we are expecting do_b() to execute. We need to see what the value of
+tmp is before we get into the loop:
+
+#define DEBUG
+int cmd(string tmp) {
+#ifdef DEBUG
+ write(tmp);
+#endif
+ if(stringp(tmp)) return do_a();
+ else if(intp(tmp)) return do_b();
+ else return 1;
+}
+
+We find out immediately upon issuing the command, that tmp has a
+value of "10". Looking back at the code, we slap ourselves silly,
+forgetting that we have to change command arguments to integers using
+sscanf() before evaluating them as integers.
+
+7.5 Summary
+The key to debugging any LPC problem is always being aware of what
+the values of your variables are at any given step in your code. LPC
+execution reduces on the simplest level to changes in variable values, so
+bad values are what causes bad things to happen once code has been
+loaded into memory. If you get errors about bad arguments to
+functions, more likely than not you are passing a NULL value to a
+function for that argument. This happens most often with objects, since
+people will do one of the following:
+ 1) use a value that was set to an object that has since destructed
+ 2) use the return value of this_player() when there is no this_player()
+ 3) use the return value of this_object() just after this_object() was
+ destructed
+
+In addition, people will often run into errors involving illegal indexing or
+indexing on illegal types. Most often, this is because the mapping or
+array in question was not initialized, and therefore cannot be indexed.
+The key is to know exactly what the full value of the array or mapping
+should be at the point in question. In addition, watch for using index
+numbers larger than the size of given arrays
+
+Finally, make use of the precompiler to temporarly throw out code, or
+introduce code which will show you the values of variables. The
+precompiler makes it easy to get rid of debugging code quickly once you
+are done. You can simply remove the DEBUG define when you are
+done.
+
+Copyright (c) George Reese 1993
diff --git a/doc/KURS/RULES b/doc/KURS/RULES
new file mode 100644
index 0000000..ac88cfc
--- /dev/null
+++ b/doc/KURS/RULES
@@ -0,0 +1,60 @@
+ DIE ZWEI GEBOTE IN MORGENGRAUEN
+ ===============================
+
+ Was sollen Gebote?
+ ------------------
+
+ Wie in jedem Spiel so haben sich auch in unserem MUD alle
+ Mitspieler (Magier eingeschlossen) an Spielregeln zu halten.
+ Allerdings machen die Spiele am meisten Spass, die die
+ wenigsten Regeln besitzen.
+
+ Um zu verhindern, dass jetzt schon angefangen wird, dass
+ unser MUD in feste Regeln gedraengt wird, habe ich mich
+ entschlossen, selber dem Spiel ein Regelwerk zu geben.
+ Aber ich werde dafuer sorgen, dass sie kurz bleiben.
+
+ 1.Gebot ) DU SOLLST NETT SEIN.
+
+ Das MUD ist ein Spiel; und Spiele machen nur dann Spass,
+ wenn man sich nicht gegenseitig versucht in die Pfanne zu
+ hauen; somit gilt diese Regel fuer Spieler wie fuer Magier.
+
+ 2.Gebot ) DU SOLLST DIE MUDLIB EHREN UND VERMEHREN.
+
+ Das MUD steht und faellt mit der Guete seiner Mudlib; und da
+ unser Hauptziel ein schoenes MUD ist, ist es die vorrangige
+ Aufgabe aller Magier, fuer den Aufbau, die Wartung und die
+ Erhaltung der Mudlib zu sorgen.
+
+ Zum Thema Vermehrung:
+ ---------------------
+
+ Es gibt in einem MUD natuerlich auch noch andere Aufgaben:
+ - Regionskoordination
+ (Regionsmagier,Erzmagier des Verkehrs)
+ - Wahrung des Gleichgewichtes der Kraefte
+ (Waffen,Ruestungen,Geld,XP,Monster,u.s.w.)
+ - Schutz des MUDs vor Spielverderbern.
+ (Sheriff)
+
+ Diese Aufgaben sind aber keine Lebensaufgaben; sie sind
+ Aufgaben, die sich den Geboten unterzuordnen haben.
+ Insbesondere sollen Magier, die nichts zur Vermehrung der
+ Mudlib beitragen, nicht ueber andere urteilen.
+
+ Zum Thema Ehrung:
+ -----------------
+
+ Hiermit meine ich den Aufruf an die Magier, keine Objekte
+ zu schreiben, die das Gleichtgewicht der Kraefte verletzen.
+
+ Und ich meine den Aufruf an die Magier, dafuer zu sorgen,
+ dass es in diesem MUD Herausforderungen gibt, die (zumindest
+ teilweise) nicht umgangen werden koennen.
+ Natuerlich ist damit auch gemeint, dass Spielern nur in den
+ Faellen geholfen wird, wo Fehler oder Luecken in der Mudlib
+ auftauchen.
+
+ Olpp, Sheriff des MorgenGrauens
+ Rumata, MudAdm des MorgenGrauens
diff --git a/doc/KURS/RULES.WIZ b/doc/KURS/RULES.WIZ
new file mode 100644
index 0000000..349f0b6
--- /dev/null
+++ b/doc/KURS/RULES.WIZ
@@ -0,0 +1,46 @@
+These are the rules for a wizard.
+(Wird noch ueberarbeitet, am besten Olpp oder Rumata fragen, was
+wirklich Sache ist. Aber eine grobe Richtung weisen diese "alten"
+Regeln schon :-)
+
+1. You may not help other players, even if they lost points due to
+ lost connection. They have to go to the post office and ask Lars,
+ or use bug.
+
+2. Never attack a player or kill him. If a player behaves badly, file
+ the complaint to Lars.
+
+3. Do not make 'deadly' trapps. A player must never die because he didn't
+ know what happens in the next room. If some room is very dangerous,
+ make some hint (like the giant footprints beside the giant lair).
+
+4. Never initialize the destination of an object outside your castle. If you
+ make a monster that can walk out of the castle, be sure that it is a
+ very nice monster.
+
+5. Never generate messages that looks like something it isn't (good and precise
+ rule :-). That is, don't try to fool the player that someone says something
+ when it isn't true etc.
+
+6. If you have a "test" character, make sure is isn't seen in the top score
+ list. He must no be wizard either.
+
+7. Try to avoid making devices, situations which makes the players loose
+ experience if they are adventuring or examining objects. Players should be
+ rewarded for adventuring and discovering things. If they get killed...
+ Well, they will then loose some experience, but this is a special case!
+
+8. The game is supposed to be in the "long distant past", and thus no
+ modern things should exist. If you want some kind of airplane, use a
+ flying horse in stead etc.
+
+9. If you make available some kind of restaurant that sells food that
+ heals, then the healing must cost on average 4 gp/hp (or more). The amount
+ of healing must also be limited per reset. Generating healing items for
+ free is only allowed if they heal at most 20 points, and are destructed.
+ Not more than one such item may be generated per room and reset.
+
+10.Teleporting items should be VERY restricted, and very rare. They must
+ not allow teleportations to anywhere, but only to one or more predefined
+ room. Never to a specific player. It must cost at least 50 spell points
+ to use each time.
diff --git a/doc/KURS/einleitung b/doc/KURS/einleitung
new file mode 100644
index 0000000..1483155
--- /dev/null
+++ b/doc/KURS/einleitung
@@ -0,0 +1,45 @@
+ Einfuehrung in die Progrmmierung der Morgengrauen-Mudlib
+ von Don Rumata, MudAdm des MorgenGrauens
+ ========================================================
+
+ EINLEITUNG:
+ -----------
+
+ Herzlich willkommen als Magier im MorgenGrauen. Du bist
+ gerade Magier geworden. Dieser Kurs soll Dir helfen,
+ in diesem MUD alles Moegliche zu programmieren.
+
+
+ WICHTIGE INFORMATIONEN FUER DEN ANFANG:
+ ---------------------------------------
+
+ Ein Magier hat sich gewissen Regeln zu unterwerfen, wie man
+ sich bein einem Spiel auch in die Spielregeln zu halten hat.
+ Diese Spielregeln stehen in RULES (das sind die wichtigen)
+ und in RULES.WIZ (das sind die technischen Hinweise).
+
+ Wenn Du Files editieren willst, gibt es mehrere Moeglich-
+ keiten:
+
+ 1.) Mit dem Befehl "ed <filename>":
+ Eine Einleitung fuer ed kannst Du in /doc/ed/* finden.
+
+ 2.) Fileuebertragung per ftp
+ 3.) Fileuebertragung per mtp
+ frage am besten einen der erfahrenen Magier.
+
+
+ KURSUEBERBLICK:
+ ---------------
+
+ I Programmierung von Raeumen
+ 1. Ein einfacher Raum
+
+ II Programmierung von Objekten
+
+ III Programmierung von Monstern
+
+
+ Achja: Ich bitte flehentlich um Korrekturlesen und
+ Verbesserungs/Ergaenzungsvorschlaege. Und noch mehr
+ um Mitarbeit. (Ich hab schon jetzt wunde Finger :-)
diff --git a/doc/KURS/objekte b/doc/KURS/objekte
new file mode 100644
index 0000000..fbb11d3
--- /dev/null
+++ b/doc/KURS/objekte
@@ -0,0 +1,29 @@
+ OBJEKTE
+
+ Als erstes musst Du wissen, dass jedes Objekt in diesem
+ Mud durch ein File repraesentiert wird. Dieses File
+ wird auch die "Blueprint" genannt. Du kannst neue Objekte
+ auf 2 Arten erschaffen.
+
+ 1.) "clone"n von Blueprints. Das bedeutet, dass Du ein
+ Objekt erschaffst, das die Eigenschaften hat, die in
+ der Blueprint programmiert worden sind. Von einer
+ Blueprint koennen mehrere "Clones" existieren.
+ Typische Beispiele fuer "Clones" sind Waffen,
+ Monster, Geld oder Spieler.
+
+ 2.) "load"en von Blueprints. Das bedeutet, dass Du
+ diese Blueprint zu Leben erweckst. In gewisser Weise
+ benehmen sich diese Objekte genauso wie die "Clones",
+ allerdings koennen von einmal geladenen Blueprints
+ keine "Clones" mehr erschaffen werden.
+ Typische geladene Objekte sind Raeme.
+
+ KNIGGE FUER MAGIER
+
+ Dadurch, dass Du beliebige Files laden oder clonen kannst,
+ bist Du in der Lage, jedem Spieler das gewuenschte Objekt
+ zu beschaffen. Aber das ist natuerlich nicht der Sinn der
+ Sache. Als Magier bist Du verpflichtet, den Spielern nur
+ noch dann zu helfen, wenn sie aufgrund von Programmier-
+ fehlern in Schwierigkeiten geraten.
diff --git a/doc/KURS/raum1 b/doc/KURS/raum1
new file mode 100644
index 0000000..b623c35
--- /dev/null
+++ b/doc/KURS/raum1
@@ -0,0 +1,137 @@
+
+ PROGRAMMIERUNG VON RAEUMEN - TEIL 1
+ von Don Rumata, MudAdm des MorgenGrauens
+ =============================================================
+
+ Ein Raum ist sehr einfach zu programmieren. Man fuellt
+ ihn mit den Informationen, die man in ihm haben will.
+
+ Am besten erklaert sich alles an einem Beispiel. Zu den
+ Funktionen sind in /doc/efuns und /doc/lfuns weitere
+ Informationen erhaeltlich.
+
+ Nachfolgend kannst Du einen (zugegebeneermassen ueber-
+ ausfuehrlich) dokumentierten Beispielraum finden.
+ In /doc/beispiele/raum1.c kannst Du den selben Raum
+ noch einmal (ohne Kommentare) finden. Den Raum
+ kannst Du uebrigens auch betreten.
+
+/* beispielraum.c von Rumata */
+
+inherit "std/room";
+ // Alle Raeume muessen diese Zeile enthalten, da in dem
+ // Standardraum wichtige Funktionen definiert werden, die
+ // innerhalb des Spieles benoetigt werden.
+
+#include <properties.h>
+ // In diesem File sind die Namen der Properties definiert.
+ // Fuer naehre Informationen kannst Du in
+ // /doc/concepts/properties und in /doc/properties.h
+ // nachschauen, da es sehr viele verschiedene Properties
+ // gibt.
+
+#include <language.h>
+ // Diese Module enthalten alle Definitionen im Zusammenhang
+ // mit Sprache. Siehe /doc/language.h
+
+create()
+// Diese Funktion wird automatisch aufgerufen, wenn der Raum geladen
+// wird. Das passiert beim Kommando "load /doc/beispiel/bspraum1" oder
+// wenn ein Spieler den Raum als erster betritt.
+{
+ ::create();
+ // Diese Funktion darf NIEMALS fehlen! Sie sorgt dafuer, dass
+ // der Raum auch die allgemeine Initialisierung durchfuehrt,
+ // da diese hier die der "Mutter-Klasse" std/room ueberlaedt.
+
+ SetProp( P_INT_SHORT, "Ein kleines Schreibzimmer" );
+ SetProp( P_INT_LONG,
+ "Du stehst in einem kleinen Schreibzimmer.\n"
+ + "Es gehoerte wohl irgendwann einmal einem Magier, aber nun\n"
+ + "ist dieser Raum verwaist und rottet vor sich hin.\n"
+ + "Ein grosser Schreibtisch in der Mitte des Raumes scheint\n"
+ + "noch einigermassen gut erhalten zu sein. Durch die Tuer\n"
+ + "im Norden faellt etwas Licht hinein.\n"
+ );
+ SetProp( P_LIGHT, 1 );
+ SetProp( P_INDOORS, 1 );
+ // Diese Properties MUESSEN in JEDEM Raum gesetzt werden.
+ // P_INT_SHORT = Beschreibung fuer Spieler im "kurz"-Modus.
+ // P_INT_LONG = Beschreibung fuer Spieler im "lang"-Modus.
+ // P_LIGHT = 1 fuer Hell, 0 fuer Dunkel
+ // P_INDOORS = 1, wenn man den Himmel nicht sehen kann.
+
+ AddDetail( ({ "schreibtisch", "tisch" }),
+ "Auf dem Tisch liegt eine dicke Staubschicht.\n"
+ + "Eine Schublade findest Du ebenfalls.\n"
+ );
+ AddDetail( ({ "staub", "staubschicht", "schicht" }),
+ "Du malst gelangweilt einige Kreise in den Staub.\n"
+ );
+ AddDetail( "schublade",
+ "So sehr Du Dich anstrengst; Du kannst sie nicht bewegen.\n"
+ );
+ AddDetail( "tuer" ,
+ "Sie steht seit Jahren offen und ist in dieser Lage\n"
+ + "hoffnungslos festgerostet.\n"
+ );
+ // Details sind Dinge, die man sich in einem Raum anschauen
+ // aber nicht nehmen kann. Je mehr Details ein Raum hat, destso
+ // schoener ist er. Schaut sich ein Spieler ein Detail an,
+ // so bekommt der die angegebene Beschreibung.
+
+ AddRoomCmd( ({ "schliesse", "oeffne", "bewege",
+ "schliess", "beweg" }), "beweg_etwas" );
+ // RoomCommands sind Befehle, die man in diesem ausfuehren kann.
+ // Es wird die angegebene Funktion ausgefuehrt.
+ // WICHTIG: Als Verben sollten immer die IMPERATIVE benutzt
+ // werden! Also nicht "lese", sondern "lies".
+
+ AddExit( "norden", "players/rumata/workroom" );
+ // Definition eines Ausgangs. Das zeite Argument bestimmt den
+ // Raum, den ein Spieler erreicht, wenn er in die angegebene
+ // Richtung geht.
+
+}
+
+beweg_etwas( str )
+// Wenn ein Spieler ein Kommando ausfuehrt, so wird alles, was hinter
+// dem Verb steht als String uebergeben, es landet also hier in "str".
+// WICHTIG: Wenn der Befehl abgearbeitet wird, MUSS er eine 1 zurueck-
+// geben. Wenn der Befehl nichts Sinnvolles tuen konnte, eine 0.
+{
+ notify_fail( "Was willst Du denn bewegen ?" );
+ // Meldung, die der Spieler bekommt, wenn ausser dem Raum auch
+ // kein anderes Objekt den Befehl verarbeiten konnte.
+ if( str == "tuer" )
+ {
+ write( "Die Tuer ist hoffnungslos festgerostet.\n" );
+ // Write gibt eine Meldung an den Spieler (und nur an ihn)
+ // aus.
+ return 1;
+ // Das Kommando bewirkt zwar aus Sicht des Spielers
+ // nichts, aber es konnte abgearbeitet werden.
+ // Also gib eine 1 zurueck.
+ }
+ if ( str == "lade" || str == "schublade" )
+ {
+ write( "Die Schublade klemmt einfach nur.\n" );
+ return 1;
+ }
+ if ( query_verb() == "bewege" &&
+ ( str == "tisch" || str == "schreibtisch" ) )
+ {
+ write(
+ "Der Tisch scheint am Boden festgeschraubt zu sein.\n"
+ );
+ say(
+ this_player()->name(WER,2)+" zerrt am Schreibtisch.\n"
+ );
+ // say gibt eine Meldung an alle Spieler im selben
+ // Raum wie der Spieler (aber nicht an ihn selbst) aus.
+ return 1;
+ }
+ return 0;
+ // Der Raum konnte nichts mit dem Kommando anfangen, also gib
+ // eine 0 zurueck.
+}