□  如何建造一個房間

    房間是構成這整個世界的要素之一，在此我們提供了一個房間的標準物件來讓
所有的房間繼承。而如同其他的物件一般，你需要寫一個 create() 來設定房間中
的敘述、出口、物品、生物等等。這裡，我喜歡說你用 create() 這個函式來賦予
這個房間的屬性。一般來說，要建造一個簡單的房間，你只要賦予它基本的屬性即
可。當然，我們不認為一個區域中幾十個房間沒有任何的機關或秘密，是個會吸引
玩家一遊的好地方。

    下面，提到了一些建造房間所需要留意的事項，也會配合一些例子來說明。

  一、基本篇

    一個基本的房間，要有 short <短敘述> 、 long <長敘述>、 exits <出口>

ˇ  當你在寫一個房間的 long <長敘述>時，其格式為：

        set("long", @LONG

房間的敘述.......

LONG
        );
      
    其中 @LONG 和 LONG  是互相對應的，你可以用任何字接在 @  後面，但是前
後兩個字一定要一樣，這樣系統才能判別，而房間的敘述寫完時，一定要換行後再
接第二個 LONG ，且同一行不能再有其他任何的字元，不然系統無法判定敘述是否
該結束了，會造成編譯時的錯誤。

    而為求區域看起來外觀上整齊、統一，房間的長敘述中每一行的長度必須一樣
，而一行的長度建議為 29 到 32 個中文字，約佔螢幕的三分之二。並且一個房間
的敘述最好不要低於三行，區域各個房間的敘述重複性降到越低越好，這樣你的區
域看起來才不會太過陽春。當然，有時候為了某些目的，比如一個迷宮，你可能會
相鄰的幾個房間都用到一樣的敘述，那自然不在此限。

ˇ  一個房間的出口則以下列格式賦予：

(一般)  set("exits", ([
                "方向"          : "連接到的房間之檔名",
                ...........
        ]);
        
(隱藏)  set(hide_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("對應門的出口方向", "門的名稱", "另一邊門的進入方向", 預設狀態);

    預設狀態有: DOOR_OPENED(開), DOOR_CLOSED(關), DOOR_LOCKED(鎖), DOOR_SMASHED(壞)

    比如說，這裡明顯的出口有 west、east 和 up。 而你要讓西邊有一個關上的
紅木門，你可以這樣寫：

        create_door("west", "紅木門", "east", DOOR_CLOSED);

    當玩家進入這個房間時，他會看到：
    
	這個紅木門是關上的。
        這裡明顯的出口有 east 和 up。

 [補充] 如果要將房門上鎖..
 
	create_door("對應門的出口方向", "門的名稱", "另一邊門的進入方向", 預設狀態, 鑰匙辨識代號);

    例如:    create_door("east","紅色大門","west",DOOR_LOCKED,"redkey");

	這時鑰匙的寫法是:
	
	//key for locked door
	inherit ITEM;

	void create()
	{
	  set_name(HIR"紅色鑰匙"NOR,({"red key","red","key"}));
          set_weight(60);
          set("unit", "隻");
          set("long","這隻"HIR"紅色鑰匙"NOR"的正面還刻了["HIY"龍蝦"NOR"]兩個字。\n");
          set("door","redkey");		// <== 這裡設定的就是鑰匙辨識代號!!
          set("value", 10000);
          set("usage","開啟某一扇門");  // <== 建議非裝備類的道具加上 usage (使用說明)
	}


ˇ  outdoor 這個設定專用於戶外的room, 用來設定戶外的天氣敘述。
    其格式為：

        set("outdoor","天氣名稱");

    例如: set("outdoors", "snow"); 
    
    snow 部分可以為 land, forest, desert, heat, snow
    不同的環境會有不同的氣候, 如果是室內就不用設定。

另外, set("light",1); 可以設定此房間為光亮狀態.
      set("light",-1);  則是白天也看不見, 必須使用照明工具才能看到.

 
    其他的一些屬性，你可以參考 /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
回去繼續修改。


