□  如何建造一个房间

    房间是构成这整个世界的要素之一，在此我们提供了一个房间的标准物件来让
所有的房间继承。而如同其他的物件一般，你需要写一个 create() 来设定房间中
的叙述、出口、物品、生物等等。这里，我喜欢说你用 create() 这个函式来赋予
这个房间的属性。一般来说，要建造一个简单的房间，你只要赋予它基本的属性即
可。当然，我们不认为一个区域中几十个房间没有任何的机关或秘密，是个会吸引
玩家一游的好地方。

    下面，提到了一些建造房间所需要留意的事项，也会配合一些例子来说明。

  一、基本篇

    一个基本的房间，要有 short <短叙述> 、 long <长叙述>、 exits <出口>

□  当你在写一个房间的 long <长叙述>时，其格式为：

	set("long", @LONG

房间的叙述.......

LONG
	);
      
    其中 @LONG 和 LONG  是互相对应的，你可以用任何字接在 @  後面，但是前
後两个字一定要一样，这样系统才能判别，而房间的叙述写完时，一定要换行後再
接第二个 LONG ，且同一行不能再有其他任何的字元，不然系统无法判定叙述是否
该结束了，会造成编译时的错误。

    而为求区域看起来外观上整齐、统一，房间的长叙述中每一行的长度必须一样
，而一行的长度建议为 29 到 32 个中文字，约占萤幕的三分之二。并且一个房间
的叙述最好不要低於三行，区域各个房间的叙述重复性降到越低越好，这样你的区
域看起来才不会太过阳春。当然，有时候为了某些目的，比如一个迷宫，你可能会
相邻的几个房间都用到一样的叙述，那自然不在此限。

□  一个房间的出口则以下列格式赋予：

	set("exits", ([
		"方向"		: "连接到的房间之档名",
		...........
	]);

    在这里，为了一个以後区域开放後搬移目录的便利性，建议采用__DIR__ 这个
由系统提供的巨集来写路径，比如说：

		"west"		: __DIR__"path3",
	和
		"west"		: "/u/d/davidoff/goathill/path3",

是完全一样的。但前者显然在以後目录的搬移上方便的多。而在下面会提到设定房
间中的物品或生物时，也建议采用这种方式写作。

□  item_desc 这是用来设定个别景物的描述，当玩家用 look 这个指令时就会作
    用。其格式为：

	set("item_desc", ([
		"景物名称"	: "景物叙述",
		...........
	]);

    其中景物叙述可以是字串或是一个 function ，所以你可以利用这个功能加以
变化，当玩家 look 一个景物时，可能看到叙述，也可能发生一些特殊的事件，而
你就可以在被呼叫的函式中写下这些事件。

□  objects 可以让这个房间在每次 reset时载入某些生物或某些物品：

	set("objects", ([
		"物品或生物的档名"	: 数量,
		...........
	]);

    如同前面所提到的，建议采用 __DIR__来编写你的路径，而数量则要用整数。
 
□  要为这个房间添上门户时，记得前面必须先 #include <room.h>。而格式为：

	create_door("出口方向", "门的名称", "进入方向", 预设状态);

    比如说，这里明显的出口有 west、east 和 up。 而你要让西边有一个关上的
红木门，你可以这样写：

	create_door("west", "红木门", "east", DOOR_CLOSED);

    当玩家进入这个房间时，他会看到：

	这里明显的出口有 east 和 up。

    而当他 look west 时，会看到：这个红木门是关上的。

 
    其他的一些属性，你可以参考 /doc/build/room_prop 或是读一下标准物件的
room.c。也建议你可以多用 more here来观看一间特殊的 room。

  二、进阶篇

    要让你的区域中富有变化，生动有趣，除了文字叙述的丰富度以外，你更可以
利用 init() 这个函式为你的房间增加一些「机关」或「秘密」。

    这里，先让我们了解一下 init() 的用途为何，和为什麽要用到它。每一个房
间的 create() 只有当 reset时才会被呼叫到，而 init() 则是在 B物件进入到 A
物件时都会呼叫到 A物件的 init() 。看到这，你应该可以看出差别了，我们希望
当一个物件（此处较多是玩家）进到一个房间时，能够经由某个动作启动这个房间
的机关的话，自然是利用 init() 来编写。

    一般的使用方式，是在 init() 中利用 add_action() 来呼叫你写的函式，其
格式为：
	add_action("function type", "action");

    function type 即是被呼叫的函式名	action 是启动的动作

    而你就可以将被 action 启动後要发生的事，都写在被呼叫的函式里面。理论
上来说，利用这个方式我们可以做到任何事，当然，能不能达成就看写程式的功力
了。下面举个简单的例子：

void init()
{
        add_action("do_pick", "pick");
}

int do_pick(string arg)
{
        object me;

        me = this_player();
        if ( !arg || ( arg != "flower" ) ) return notify_fail("你要摘什麽？\n");

        else if ( random((int)me->query("kar")) < 7 )
                message_vision("$N将花摘了下来，但一不小心被刺了一下。\n", me);

        else
                message_vision("$N摘下一朵美丽的血红色鲜花。\n", me);

        return 1;
}
   
    当玩家利用 pick 这个指令时就会呼叫到 do_pick() 这个 function，而启动了
这个房间的机关。

    这里特别提到一点，一个简单的 room 我们为了使记忆体的使用量降到最低，会
在 create() 最後加上一行 replace_program(ROOM); 。这是因为在房间的标准物件
中有定义了如 init() 等其他的函式，而一个简单的房间根本没有用到，所以我们用
replace_program() 来将原本的被继承的标准物件「重置」（或说取代）掉，但是一
旦房间中用到了 init() 来编写时，就绝对不可以用 replace_program()，因为系统
届时找不到 init() 便会随便呼叫一个记忆体中的位址而随便传进一些乱七八糟的东
西，情况严重时，甚至可以让整个 mud crash。但是，我们自不可因噎废食，该用的
时候还是要用，这些应该是一个好的程式写作人员自己必须留意的，发生状况要自己
负责。

  三、建议

    这里我们提供了一个工具来让巫师们可以方便的编写一个房间，那就是房间编辑
器(Roommaker) ，你可以 clone /obj/roommaker 来使用它。一般的步骤是，先利用
mkroom来造一个空房间，然後利用 goto 这个指令到房间里去，再用 rset short 和
connect 来设定这个房间的短叙述及出口，而像其他的一些属性例如 outdoors 等等
也都可以利用他来做到，接著用 to rset long 来设定这个房间的长叙述，最後再用
saveroom将这个房间存档。要是这只是一个基本的房间，那到这里就大功告成了，要
是□想让这个房间富有变化，那就再用线上编辑器 edit 或将这个房间的档案 ftp
回去继续修改。

Davidoff@ES2 (10-04-95')