BEING A WIZARD IN LPmud ----------------------- Congratulations. That you are reading this probably means that you have just become a Wizard in a LPmud game. As a wizard, you have just received a portable castle from Leo the Archwizard. Drop it in a nice place somewhere in the world of LPmud, and watch it grow to a real castle. Then you can start to redesign it and fill it with monsters and treasures. Try to pick a good place to drop it so that you don't have to move it later. Moving the castle is not difficult but it confuses the players. First of all, try to remember this at all times ----------------------------------------------- As a wizard, you have immense powers. But, with those powers comes responsibility - so always think before you do anything. For example, it is possible to move other wizards' castles, to crash the game, and to kill all the players. And it IS possible to do all these things accidentally, so PLEASE be careful! Remember that as far as the game is concerned you are NO LONGER a part of it. Wizards do not play the game, they are above that and participate only by adding new ideas, like quests and rooms. If you don't know what you are doing, then you probably shouldn't do it. If you know what you are doing, but not if you should do it, then you probably shouldn't do that either. There is a file called /doc/build/RULES, which you should read immediately after finishing this scroll. It contains the rules for how a wizards should behave in GENESIS. You can look at it with the command "more /doc/build/RULES". I will remind you later about this, don't worry! :) The file structure is a tree ---------------------------- LPmud mimics the file system hierarchy and file handling commands of UNIX. A directory is a set of files, where those "files" can be both normal files and other directories. Everything starts with the so-called root directory, the name of which is "/" (at least from inside LPmud!). As in UNIX, a file or a directory is referred to by its file name or its path name, i. e. for example "thing.c" and "/players/padrone/thing.c". The rooms in the "basic" LPmud world are in the directory "/room", and the objects (like the weapon and monster objects) are in "/obj". Each wizard has his own home directory, called for example "/players/padrone". Some commands for handling files: ls - list the files in a directory rm - remove a file ed - edit a file using LPmud's built-in, line-oriented, editor cat - print the contents of a file on the screen more -- print the contents of a file, approx. one screenful at a time tail -- print the last few lines of a file cd -- change the current directory Where do I find the documentation? ---------------------------------- There is a directory called "/doc" (try the commands "ls" and "ls /doc"), that contains documentation. The subdirectory "/doc/LPC" contains files with information about the language LPC, and the subdirectory "/doc/build" contains files about how to build. In the directory "/doc/efun" you will find descriptions of the external functions, and "/doc/lfun" contains descriptions of commonly used local functions. It can happend that you won't find what you look for in the documentation. In that case, either ask another wizard, read the code (which actually contains some very useful comments), or find out by testing. You can also use the built in 'man' command defined by /obj/trace. It will list search for and list documentations. One of the first things you should do is to read the entire contents of /doc. This is not as much work as it seems and it really pays off very soon, since you later will remember where to look for explanations of commands and routines. Remember also that the Archwizards, i.e all wizards with level > 21, have as part of their duties the obligation to help other wizards with their problems in GENESIS. The best way of reading the documentation is to do "cd /doc" and then "ls" to see what you have there. Then you can change directory down into the different subdirectories and do "ls" in them to see what you can read there. I specially want to point out that the information on the editor "ed" can be found in "/doc/build" in the files ed0 - ed4. You read any file with the command "more" like "more /doc/build/ed0" or just "more ed0" if you already have written "cd /doc/build". Object-oriented programming in LPmud ------------------------------------ When you play LPmud, everything you encounter (weapons, monsters, players, rooms etc.) are OBJECTS. Each object is an INSTANCE of a CLASS of objects. One class can INHERIT part of its design from another class. In LPmud, an instance is either created by CLONING or LOADING the object class, and each class is described in a file, written in a C-like language called LPC. These "class descriptions" are the programs in LPmud. All program code that you write as a wizard, or that is part of the standard LPmud world, will be part of a description of an object class, a class of objects that can be loaded and cloned. Loading, cloning and updating ----------------------------- "Loading an object" means the process of taking a class description file, for example "/obj/weapon.c", and reading it into the game. This is done as soon as that object is used in any way, for example if a function in the object is called from LPC, or if another object tries to enter it (as when a player walks into a room). When the object is loaded, one instance of the object class is created. If there should be only one instance, as for example for (most) rooms, this is enough. If you need to create several instances of a class of objects, you clone it. Objects can be cloned using the wizard command "clone", as in "clone /obj/torch", and with the LPC function clone_object(), as in this_torch = clone_object("obj/torch"); Cloning an object will cause it to be loaded, if it wasn't already loaded. When you have changed the description of an object by editing the file, and want to load the new version of the object, you can use the wizard command "update". Then load (or clone) the new version. If the object in question is a room, a "goto ROOMNAME" will load the room as well. LPC --- LPC is a dialect of C and differs from C mainly in being simplified and in that it allows for handling the objects. It has only four data types (plus arrays of those data types), fewer operators and a simplified control structure. Note that before the contents of a file is read it is run through the standard C pre-processor. This program can be used to insert other files into the file being read, and to define constants and macros. Lines starting with "#", as the line (no blanks before the #!) #include "std.h" #define INSURANCE_LIMIT 1000 #define CLONE(var, file) var = clone_object(file); are all commands to the preprocessor. Read more about LPC in the files in the directory /doc/LPC ! You can read more about the C preprocessor in any book about C, but that is hardly neccesary for the ordinary use of LPC. Functions: ---------- There exists two types of functions in LPC, called LOCAL and EXTERNAL functions. A local function is defined in LPC code in an LPC file, and is contained in an object. A local function can be called from LPC code inside the object or from LPC code in another object. Objects communicate with each other by calling functions in each other. A local function can be declared STATIC, meaning that it can only be called from LPC code within the same object. External function are "built in" in LPC, so it has no definition in LPC code. Examples of local functions are the functions set_value and query_value in "/obj/treasure.c". Examples of external functions are write(), time() and add_action(). Read more about functions in the file "/doc/LPC/function". All external functions are documented in "/doc/efun/FUNCTION", where FUNCTION is the name of the function. Many local functions are documented in "/doc/lfun/FUNCTION". Not all can be documented, as they are unlimited. Error messages -------------- If an error occurs when LPmud is trying to load one of your objects, an error message will be printed on the file "/log/PLAYERNAME" (where PLAYERNAME is your name). Those error messages, for all the wizards, and also some other error messages, are also written on the file "/lpmud.log". Sometimes you have to look at that file too to find awhat caused an error. That file will usually grow quickly, and the command "tail /lpmud.log" will prove useful. The last error is stored for every wizard. It can be obtained simply by doing 'ed'. If there was an error, it will be displayed with the offending line number, and the correct file will be edited. Also, don't forget to periodically check "/log/PLAYERNAME.rep". When a player files a bug report in one of your rooms, using "bug", "typo" or "idea", the message ends up in that file! Building -------- Start by looking at the existing rooms. As a wizard, when you enter a room, LPmud prints the path name of the object that is the room, for example "/room/forest2". You can look at the definition of the room by using the command "more /room/forest2.c" or "cat /room/forest2.c". For most purposes it is sufficient to use the standard room routines that you get by inheriting "/room/room". Read more about how to build in the files in the directory "/doc/build". Remember also that there exists a special directory called "/doc/examples" which contains nothing but the introductory texts and examples of how to write objects in LPC. More about that later in this text. An example of a room -------------------- This is an example of how a file describing a room can look like (This file exists and is called "/room/workroom.c"): /* Generic workroom, just change it to your fit your tastes */ inherit "room/room"; /* * Function name: reset * Description: Reset the room */ reset(arg) { if (arg) return; set_light(1); short_desc = "Wizards workroom"; long_desc = "This is the workroom of a powerful wizard, the question is only who?\n" + "Someday someone will come to claim this room for his own, and then all\n" + "will change...\n"; no_castle_flag = 1; dest_dir = ({ "room/church", "church", "room/shop", "shop", "room/adv_guild", "guild" /* Just add on rooms as you if you need more exits */ }); } When the first player enters the room after the game was started, the file is run through the C preprocessor, yielding a much larger code that is stored in a file called "/room/workroom.i". These ".i"-files makes the loading of the game after reboot much quicker. Don't touch them since they are created and modified by the program itself. Of course, if you remove or rename the c-file you can remove the .i-file since it won't be referenced any more. The .i-files are not listed by the 'ls' command. The code produced is much larger and contains a lot of other functions besides the "reset()" that was actually written above. Four of these local functions are of special interest, and many objects will have them locally defined: reset():This function is called automatically, with the argument 0, when the object is created (that is, loaded or cloned), and after that every three hours or so, but then with the argument 1. It is used to initialize things in an object, and to periodically reset it (like putting new monsters in the different rooms, when they have been killed by all those brutal players). long(): This function should print the long description of the object, using the external function write. If this function is defined the "long_desc" can just as well be set to be = 0 since it won't be referenced. init(): When a living object (a player or a monster) sees this object (if he, she or it enters the object, or arrives in the same room as the object, or the object is moved into the player or monster, or the object is moved into the same room as the player or object), the living object calls the function init in this object, with the living object as current player. If you redefine functions that are automatically defined by the inherited objects, you will sometimes want to call that function in the inherited code. You do that with the operator "::". If you define the function "init()" in your room but still would like to call the "init()" in "/room/room" you do that with the command "::init();". Typically this IS something that you want to do but remember to put the call to the inherited function first. The example above was a special room called a "workroom". As a wizard you have a command called "home" that will bring you to your workroom if you have one. To get the workroom described above do like this: > cd > ed workroom.c : r /room/workroom.c : w workroom.c : q And then just "home". You can change this room later to fit your own tastes. There will be some messages from ed while you do this, but ignore them and just write as it says above. Some more local functions that are defined in many objects ---------------------------------------------------------- heart_beat(): For objects that have a heart beat, the local function heart_beat will be called (automatically) every two seconds. The heart beat is started by calling the external function "set_heart_beat()", with a non-zero argument from the object. This can be used to simulate that time is going between events in the room, but usually the external function "call_out()" is better to use for that purpose. exit(): The opposite of init. Called when someone leaves the room. Be very careful when using this function. If there is an error in it, the occupants of the room can't quit, die, leave the room or perform anything that involves them or anything moving out of the room. And if this should happend to you despite this warning (which it most problably will, *sigh*) DON'T call for help. Anyone who enters the room will only get stuck as well. The only thing you can do is hope for a reboot of the game within the near future :) . drop(): If an object has a local function called "drop", and it returns a non-zero value, the object cannot be dropped. If such a non-droppable object is held by a player that quits, it is destructed automatically. get(): For a player or monster to be able to pick up an object, that object must have a local function called "get", that returns a non-zero value. query_value(), query_weight(), query_level(), query_npc(), etc: Lots of different functions returning values of local variables in the objects. set_value(), set_weight(), set_level(), set_npc(), etc: Lots of different functions for setting local variables in the objects. To find all the available functions you should read the following files and try to understand them, since they are the most inherited and cloned objects in the game. /obj/player.c - For player functions. /obj/monster.c - For monster functions. /obj/living.c - For common monster and player functions. /obj/weapon.c - For weapon functions. /obj/armour.c - For armour functions. /room/room.c - For standard room functions. Player commands --------------- A living object (a player or a monster) can perform commands. Every command has to be defined in an object, although some commands are defined by the player object itself, like "quit" and "look". All other commands, like "south", "north" and "buy" (in the shop) has to be defined in an object. If you look at the example of a room above, you can see how the external function add_action is used to add one commands. This is usually done in the local function "init". The "current player" -------------------- The external function "this_player()" will return the current player. This is the player OR monster that performed the command that LPmud is now executing or caused the function "init()" in an object to be run. The external function "write()" will send the text it is given as argument to the current player. The function "say()" will send the text to all living objects that are in the same room as the current player (or that are inside the current player!), but NOT to the current player itself. When changing your rooms etc ---------------------------- ALWAYS, ALWAYS, ALWAYS test all changes that you make to your code, at least by doing update and clone or load on the object that you changed. Do this even after a trivial change, like correcting the spelling of a word in a message. It is very easy to accidentaly put a period or a semicolon somewhere in your code, and even if the your code is correct there can be bugs in the LPmud game itself that can cause it not to work. Some non-technical hints on how to be a good and/or popular wizard ------------------------------------------------------------------ In this section I will relate parts of the /doc/build/RULES file. I believe that some of the things discussed in the rules and guidelines can be of general interest to how a wizard should behave and what things he (or she or it) should build and not build. So here are some of the rules and guidelines: Do not harm a player directly! This means, among other things, that you should never attack or kill a player. Also take care not to zap or teleport away (or heal) a monster a player is currently fighting (stat the monster first). Avoid teleporting a player without asking first. Do not help a player directly! This means, for example, that you must not help by killing or attacking monsters, healing players or giving away items (an occasional beer might be excused). Also take care not to leave valuable items lying around, e. g. don't zap a monster and leave its weapon-containing corpse to rot on the street. Remember that the business of players is their business only! A typical case is when one player kills another and the killed one starts yelling for blood. Let them sort it out on their own. You may NOT interfere and if you get really mad about it, tell or mail an Archwizard or administrator. Do not make deadly traps! 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 outside the giant's lair). Deathtraps is about the only case when Lars allowes a player to get back his previous level and equipment, excluding bugs in the code. It also results in an angry letter from him or an Archwizard, which you don't need or want! :) Do not send killer-monsters out into the world! This means that if you create a monster that can walk out of the castle, make it a nice monster (i. e. it should never attack players). Don't make too good things! For example, don't create weapons with weapon class > 20 if there is no big drawback with them. Weapons with wc 20 should be at least as hard to get as the swords of the three giants in the giant conference. Also, body armour (type "armour") should be max armour class 4, and additional armour, like helmets, always class 1. And don't make the monsters too easy to kill. A monster with much treasure and/or many experience points should be big, dangerous and very hard to kill. Remember that the purpose of the game is for it to be fun and enjoyable both for players and for wizards - not to have all players converge on your castle just to get that wc 30 sword. Don't make healing too easily available! It's an important part of the game that players have to wait for their hit points to regenerate. Also, the pub is one of the main sources of player interaction and role playing. Remember that even if you only heal a few points per player command (like "drink from fountain"), many players use macros and abbreviations and can still heal almost instantly. Make the players drunk, the healing very limited, the cost very high, or the place very hard to get to! Portable healing in the way of potions and food upsets the balance of the game. If you create such an object make sure they are rare and very expensive. Don't build lots and lots of extra pubs and shops! The pub, as mentioned above, and also the shop, are natural meeting points and important sources of player interaction. Therefore you should try not to build your own pub or shop if you don't really need it (for example in a quest or for a guild). Don't make your own "perfect tool". It seems that every wizard wants to make a perfect tool that can do anything. Use /obj/trace instead, and the quicktyper if are are a lazy typist. Prices of equipment. Should be set with some sense. A player will NEVER be payed more than 1000 coins in a shop. The only reason to set a higher value is to prevent another player from buying the same object back from the shop at a too low price. It is very easy to create powerful magic items in LPmud, but this is generally NOT a good idea. The balance of the game must be kept and remember that NOTHING in the world is given away for free. It's very hard to write rules that define how magic may and may not be used, and becuace of that the wizard's own judgement must be trusted in almost all cases. There are however some things I'd like to warn about right now. Teleporting players is a nuisance. It wreaks havoc with quests and is generally disliked. If you allow a player to teleport it should only be to one or at most two predifined locations, like the church or your guild, and the cost in spellpoints should be high. At least 50 SP is the current ruling by Lars. New magic spells for players. Are very easy to write but it is very hard to judge what effect they will have on the game in advance. A discussion about magic and how it should be limited is currently on the way. Some very loose rules exist and the best option is to ask an Archwizard FIRST and implement the spell AFTERWARDS, if ever. If you happily make something and put a lot of time into it only to be told in no-negotiation-possible- terms to remove it, you will only get mad and frustrated. Use your good judgement and in doubtful cases do something else or ask the other wizards what they think first. Examples of rooms, monsters, objects etc. ========================================= Read the files in the directory /doc/examples. They are all just documented examples of standard problems in LPmud. Like creating new rooms, monsters and equipment along with some general advice. The best thing might be to "go" there by typing "goto /doc/examples/path1" and walk around for a while, before actually viewing the code. NOW: Read /doc/build/RULES by typing "more /doc/build/RULES" .