  
                              新 进 巫 师 手 册 
  
身为巫师 
-------- 
        首先恭喜你，你能看到这一篇文字表示你现在已经是东方故事中的一名巫师 
        了，巫师身份代表你已经从玩家晋升到「游戏作者」的身份。 
  
首先，请记住以下几点 
-------------------- 
  
        身为一个巫师，你所具有的能力已经超出一般玩家的范围。但这些能力表示 
        你必须为自己在这里的所作所为负较多的责任，你在做任何事之前请一定要 
        考虑清楚。举例来说，你所具有的能力已经足够改变一个房间的出口、让游 
        戏当机、甚致毁掉所有玩家的资料档，而且这些也有可能是由於你的错误而 
        意外造成的，所以千万要小心。 
  
        请记住你现在的身份已经不是玩家，当巫师的目的不是「玩」，而是让你有 
        机会把自己的点子加入这个游戏之中，让其它玩家玩你设计的游戏。 
  
        如果你不确定做某个举动会产生什麽後果，最好问一问其它较有经验的巫师 
        ，如果你知道你在做什麽，但是不确定到底该不该做，最好不要贸然行动。 
  
树状档案结构 
------------ 
  
        LPmud 模拟一个类似 UNIX 中的档案系统与处里档案的指令，一个目录是由 
        一组档案构成的，这些档案包括一般的档案和其它的子目录。所有的档案可 
        以用档名或一个由根目录开始的路径名称( 中间以斜线符号 "/" 隔开 ) 表 
        示，例如: "thing.c", "/std/user.c"。 
  
        基本上游戏中所有的房间、怪物及物品都在 /d 目录下，详细的档案组织请 
        参考每个目录下的 README 或其它文件。 
  
一些处里档案的指令 
------------------ 
        ls              - 列出目录下的内容 
        cd              - 改变目前的工作目录 
        pwd             - 显示目前的工作目录路径名称 
        cat             - 显示整个档案的内容 
        more            - 显示整个档案的内容，一次一个萤幕 
        tail            - 显示一个档案最後几行 
        ed              - 用 LPmud 内部的文书编辑器编辑档案 
        cp              -   贝档案 
        mv              - 移动档案( 或更改档名 ) 
        rm              - 删除档案 
  
如何获得说明文件 
---------------- 
  
        1. 输入 "help <函数名称>" 
        2. 用 "cd" 指令到 /doc 下找 
  
        如果你仍然找不到你想要的说明文件，可以去问其它巫师，或乾脆直接去看 
        程式码( *.c 的档案 )，里面可能会有一些相当有用的注解，再不然就实际 
        去试试看。 
  
        通常较资深的巫师都乐於帮助新进巫师，而且这也是他们工作的一部份。 
  
        在这里特别指出一点，有关内建的 ed 编辑器说明可以在进入 ed 之後用 
        "h" 命令获得，ed 是你编修档案时最常用到的指令，和 UNIX 下的 ed 十 
        分类似。"more" 指令可以用来读取几乎所有的档案，例如 "more thing.c" 
        、"more /doc/wizhelp/wizcmds" 等，在 more 显示完一个萤幕暂停状态 
        下，可以用 "?" 命令得到有关 "more" 功能的简介，如卷页、搜寻等。 
  
  
物件导向程式设计 
---------------- 
  
        当你在 LPmud 中，所有你接触得到的东西如怪物、武器、房间甚至玩家都是一 
        个物件(OBJECT)，每个物件都是一种物件型态(CLASS)的实体(INSTANCE)，物件 
        型态可以由其它物件型态继承各种特性。 
  
        所有的物件实体都是经由复制(CLONE)或载入(LOAD)物件型态产生的，而这些物 
        件型态都是用一种类似 C 叫作 LPC 的程式语言写成的档案所定义( 一个 *.c 
        档代表一个物件型态 )。 
  
        这些物件型态与物件实体就是构成这整个游戏的单位，所有你写出来的程式码 
        都是藉由定义一个物件或物件型态，并且利用复制或载入产生一个物件实体而 
        执行。 
  
        许多常被用到的物件实体都利用『继承』的方式以节省系统资源，通常是写好 
        一个『标准物件』提供所有该类型物件的基本功能，让你写的物件继承，并设 
        计一个可供修改设定的界面，让你用最快最简易的方式作出一个具有各种特性 
        的物件。举例来说，一只怪物有体力、法力、属性等变数，还有战斗、谈话、 
        移动等能力，如果每一只怪物都去写一个程式控制这些特性，整个游戏大概放 
        不了几只怪物，於是我们写了一个『标准怪物』(/std/monster.c)让所有想要 
        具有怪物能力的物件继承，你只要设定怪物的名称、体力、攻击能力等变数就 
        可以做出一只活生生的怪物。 
  
载入、复制、与更新(UPDATE) 
-------------------------- 
  
        「载入」一个物件表示将一个 *.c 档读入记忆体中，做成物件实体。每当一个 
        物件内所定义的函式被呼叫，而这个物件又不存在於记忆体中的时候，系统就 
        会去将它载入，例如走进一个房间、用 new 函式复制未载入的物件等。 
  
        当物件被载入之後，记忆体中就会存有一份物件实体，对某些物件实体只能有 
        一份的物件( 如房间、指令 )等，这就是它唯一的实体。 
  
        如果你需要几个相同物件( 同一个 *.c )的物件实体，可以用「复制」来达到 
        目的，你可以用巫师的 clone 指令复制一个物件，如 "clone /obj/torch"， 
        或在 LPC 程式中用 new() 函式如: 
        许多常被用到的物件实体都利用『继承』的方式以节省系统资源，通常是写好 
        一个『标准物件』提供所有该类型物件的基本功能，让你写的物件继承，并设 
        计一个可供修改设定的界面，让你用最快最简易的方式作出一个具有各种特性 
        的物件。举例来说，一只怪物有体力、法力、属性等变数，还有战斗、谈话、 
        移动等能力，如果每一只怪物都去写一个程式控制这些特性，整个游戏大概放 
        不了几只怪物，於是我们写了一个『标准怪物』(/std/monster.c)让所有想要 
        具有怪物能力的物件继承，你只要设定怪物的名称、体力、攻击能力等变数就 
        可以做出一只活生生的怪物。 
  
载入、复制、与更新(UPDATE) 
-------------------------- 
  
        「载入」一个物件表示将一个 *.c 档读入记忆体中，做成物件实体。每当一个 
        物件内所定义的函式被呼叫，而这个物件又不存在於记忆体中的时候，系统就 
        会去将它载入，例如走进一个房间、用 new 函式复制未载入的物件等。 
  
        当物件被载入之後，记忆体中就会存有一份物件实体，对某些物件实体只能有 
        一份的物件( 如房间、指令 )等，这就是它唯一的实体。 
  
        如果你需要几个相同物件( 同一个 *.c )的物件实体，可以用「复制」来达到 
        目的，你可以用巫师的 clone 指令复制一个物件，如 "clone /obj/torch"， 
        或在 LPC 程式中用 new() 函式如: 
  
        this_torch = new("/obj/torch"); 
  
        如果你复制的物件尚未被载入，系统自动会去将它载入。 
  
        当你写好或修改了一个档案，要把这个新版的物件定义载入到记忆体中，可以用 
        巫师的 update 指令，如 "update /obj/example/sword"，值得注意的是如果你 
        直接用 clone 复制的时候，若是记忆体中已经有其它来自同一档名的物件实体 
        ，系统会直接去复制那个物件实体，而不去载入新版的档案，必须经过 update 
        之後才会变成新的版本。 
  
        另外，有些只有一个物件实体的物件如房间，不必用 clone 去复制，别忘了载 
        入的时候就会产生一份物件实体，只要用 update 就可以了。 
  
  
LPC 
--- 
  
        LPC 是一种简化及修改过的 C 语言，使得它能适用於物件导向的程式设计。在 
        LPC 中，只有整数、浮点数、字串、物件等几种资料形态，与阵列、对映( 
        mapping)、混合(mixed)等资料结构。 
  
        在你的 LPC 程式码被编译之前，会先经过标准的 C 前置处理器的处理，你可以 
        用 #include, #define, #if, #ifdef 等指令节省不少时间。以下是几个例子: 
  
        #include "config.h" 
        #define INSURANCE_LIMIT 1000 
        #define CLONE(var, file) var = clone_object(file); 
  
  
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() and query() in 
/std/object/prop_logic.c. Examples of external functions are write(), time() 
and add_action(). 
  
  
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/lpmud.log".  You can read 
the last 25 lines of so of this file using the command "log lpmud.log". 
Sometimes you have to look at that file to find what caused an error. 
"lpmud.log" will usually grow quickly, and the command "log lpmud.log" will 
prove useful.  There will also be an error message in your own directory, 
suchs as /u/b/buddha/log.  Be sure to remove this from time to time. 
  
        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. 
  
  
  
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 "/doc/workroom.c"): 
  
  
/* 
 *      Andrew's workroom.c 
 */ 
#include <stats.h> 
#include <config.h> 
inherit "/usr/lib/room"; 
  
void create() { 
    set_short("Andrew's workroom."); 
    set_long("This is Andrew's workroom.\n" + 
             "Not that Andrew ever, EVER, works though you understand.\n"); 
    set_exits(({ "/room/start"}), 
              ({ "out"}) ); 
    set_light(1); 
} 
  
  
When the first player enters the room after the game was started, the 
file is run through the C preprocessor. 
The code produced is much larger and contains a lot of other functions 
besides the "create()" that was actually written above. Four of these 
local functions are of special interest, and many objects will have them 
locally defined: 
  
create();       This function is called automatically, with the argument 0, 
                when the object is created (that is, loaded or cloned). 
                It is used to initialize things in an object. 
  
reset();        This function is called periodically to reset an object, 
                (like putting new monsters in the different rooms, when they 
                have been killed by all those brutal players). 
  
query_long();   This function should return the long description of the 
                object. 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 the standard room you do 
that with the command "::init();". Typically this IS something that you want 
to do (especially if you want exits to work) 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 /doc/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. 
                (This time is approximate.) The heart beat is started by 
                calling the external function "set_heart_beat(1);", 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. 
                To turn off the heart_beat, do "set_heart_beat(0);". 
  
query_name(), query_cap_name(), query_weight(), query_level(), query_npc(), 
query_position(), query_total_hp(), query_short(), query_long(), etc: 
  
                Lots of different functions returning values of local 
                variables in the objects. 
  
set_value(), set_weight(), set_level(), set_short(), 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. 
  
  
        /usr/lib/room.c         - For standard room functions. 
        /usr/lib/Object.c       - For generic object functions. 
        /usr/lib/player.c       - For player functions. 
        /usr/lib/living.c       - For common monster and player functions. 
        /usr/lib/monster.c      - For monster-specific functions. 
  
Note that many of these may use something called "inherit" to get all the 
functions of other files.  The most basic object that all other objects 
will be descendents of is /usr/lib/Object.c 
  
  
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 Alluviamud 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 
game itself that can cause it not to work. 
  
  
Some non-technical hints on how to be a good and/or popular wizard 
------------------------------------------------------------------ 
  
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 NPC 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. 
NOTE: player killing player is not allowed, so report all cases of it. They 
are allowed to beat each other sensless however (knockouts). 
  
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, unless 
        they are in an area where such things should be expected, such as 
        a Supervillians 'secret base'. 
  
Don't make too good things! 
        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 sections just to get that wc25 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, bars are 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. 
        In the super genre you shouldn't worry about this much, players will 
        have powers letting them heal fast anyway... but in others genre's it 
        is a major concern... 
  
Don't build lots and lots of extra bars and shops! 
        The bar, 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 bar or shop if you don't really need 
        it (for example in a quest or for a guild). 
  
Prices of equipment. 
        Should be based on 'real world' values of the area/genre the game 
        is set in. 
  
New powers 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 powers 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. 
  
  
I hope you have found this to be of some use to you. 
I realize that it is in need of being updated, and extended... 
If you have additions, please let me (the editor.  not the author.) know and 
I'll add them. 
        Just send additional documentation to adam@dogstar.colorado.edu and 
it will no doubt get distributed to someone if it's any good. 
  
  
Happy mudding! 
  