㈠ 請問什麼是LPC
第一章 Lpc程序和編程環境
-----------------------------------------------------------
第一節 編程環境
通常我們所見到的Mud大多是LpMud。LpMuds使用Unix的指令和文件結構。如果你對Unix有所了解,那麼LpMud中的一些指令和它的文件結構與普通的Unix基本一樣。如果你從未使用過Unix,那麼它與Dos不同的是在文件的路徑用"/",而不是Dos的"\".
一個典型的LpMud的文件是這樣的:
/clone/player/player.c
"/clone/player/"是路徑,player.c是文件名。
在多數的LpMud中,下面這些的基本的Unix指令是可以使用的:
pwd, cd, ls, rm, mv, cp, mkdir, rmdir, more, tail, cat, ed
如果從未使用過Unix,那麼下面這張表也許是有用的。
pwd: 顯示當前目錄
cd: 改換你當前的工作目錄,和Dos的cd一樣。
ls: 列出指定目錄下的所有文件,如果沒有指定任何目錄,那就列出當前目錄底下的文件。和Dos的dir一樣。
rm: 刪除一個文件 和Dos的rmdir一樣
mv: 從命名一個文件 和Dos的move一樣
cp: 復制一個文件 和Dos的一樣
mkdir: 創建一個目錄
rmdir: 刪除一個目錄
more: 按頁顯示一個文件在你的當前屏幕。
cat: 顯示整個文件。和Dos的type一樣。
tail: 顯示一個文件的結尾幾行。
ed: 允許你使用Mud自帶的編輯器,編輯一個文件。
-----------------------------------------------------------
第二節 Lpc程序
2.1 Lpc程序。
Lpc的程序看起來和一般的C區別不斷大,語法基本一樣,但是Lpc和一般的語言有著根本的不同,Lpc程序是編寫一個一個的"Object"。這有什麼區別呢?一般的程序是在執行過程中,通常有一個明顯的開始和和結束。程序從一個地方開始,然後順序執行下去,到了結束的地方就中斷了。Lpc的Object不是這樣的。
所謂的不同的Mud,實際上是一些不同的Lpc的Object在一個Driver的上的各種不同的表現。也就說,Lpc的Object是運行在一個Driver上的。這些Object組成了LpMud的豐富多彩的世界。Driver幾乎不參與創建你所接觸到的世界,它所完成的工作只是讓那些Lpc的Object活動起來。Lpc的Object可能沒有明顯的開始和結束的標志,它可能
永遠在工作。
和一般的程序一樣,Lpc「程序」也是由一個或多個文件組成。一個Lpc的Object是按如下方式被執行的:Driver把和這個Object相關的文件讀入內存,然後解釋執行。但是要記住的是,讀入內存,並不是說,它就開始按順序執行。
2.2 Driver和Mudlib關系
在有些游戲中,整個游戲包括Driver和游戲世界都用C寫好,這樣能快一些,但是游戲的擴充性很差,巫師們不可能在游戲進行中添加任何東西。LpMud則相反。Driver理論上應該和玩家所接觸的世界幾乎沒有任何直接的聯系。游戲世界應該是自己獨立的,而且是「即玩即加」的。這就是為什麼LpMud使用Lpc作為編程語言的原因。它允許你創建一個游戲世界,再由Driver在需要時讀入解釋執行。Lpc甚至比C更簡單,更容易明白,但是它可以創建一個可以讓許多人在上面游戲的世界。
在你寫完一個Lpc的文件時,它存在於主機的硬碟上。在游戲進行中,當需要整個Object時,這份文件將被調入內存,一個特殊的函數被調用來初始化這個Object的一些變數。現在你不用關心什麼是變數,什麼是函數以及游戲本身怎樣來調用這個object,你只要記住Driver從硬碟中讀入一個文件,然後放在內存中,如果沒有任何
錯誤的話。
2.3 一個Object被裝人內存。
一個Object不會也不必有一個特點的地方讓Driver去執行它,通常Drvier會在Object中找一個地方去初始化它。一般都是這個函數叫做create()。
Lpc的Object是一些變數(它的值能變化)和函數(函數通常是用來操縱那些變數的一段程序)的組合。函數操縱變數的方式有:調用其他函數,使用Driver內部定義的函數(efun),基本的Lpc表達式以及流控制。
我們來看個變數的例子: wiz_level。這個變數記錄你的巫師等級,如果是0呢,通常是普普通通的玩家了。這個值如果越大就表示你的巫師等級越高。這個也同時控制了你能不能執行一些巫師指令。基本上來說,一個Object就是一些變數「堆」在一起的東西。一個Object改變了,也就是某一個或者一些變數改變了。總的來說,一個Object如果要被內存中的另一個Object調用,Driver會去找這個Object的那堆變數放在哪裡,如果這些變數沒有值,那麼Driver會調用一個特定的函數create來初始化這些變數。
但是create()不是Lpc代碼開始執行的地方,只是大多數的Object從這里開始。事實上,create()可以不存在。如果這個Object不需要對變數初始化,那麼create()可以不存在。那麼這樣的Object開始執行的地方就完全的不同於一般的Object,可以從任何地方開始。
那麼究竟什麼是Lpc的Object?Lpc的Object就是一堆變數的集合,它帶有一個或者更多的函數來操縱控制這些變數,函數的排列順序是無所謂的,隨便那個排在前面對這個Object的特性沒有影響。
2.3 代碼風格
在上面說過函數的順序對這個Object的特性是毫無影響的。但是一個有著良好代碼風格的程序對LpMud是很重要的。因為LpMud通常不會也不可能是一個人完成的,如果程序沒有較好的可讀性,那麼別人理解你的「作品」是很困難的。而且有個良好的程序風格能給人以優雅的感覺,因此希望大家寫的Lpc程序能有個好的風格。大家中的有些人可能以後會加入XO team創建自己夢想中的世界,我們要求你採用如下的格式書寫程序。
2.3.1 頭文件
在一個文件的開頭是一段說明。採用如下格式:
/* /u/trill/obj/test.c
* from XO Object Library
* 測試用的Object
* created by trill 19970808
* version @(#) test.c 2.1@(#)
* last modified by trill 19971008
* 測試tell_wizard這個simul_efun
*/
第一行是這個文件的絕對路徑,就是全路徑。
第二行是它所在的Mudlib
第三行是它的功能的簡單的描述,可以超過一行。
第四行是這個文件的作者和創建時間。
第五行是它的版本號,可能做了多次修改,甚至可能會重寫,這個數字2.1標志了它大概做過多少次改動。
第六行是最後一次修改的人和時間。
第七行是最後一些修改什麼東西。
對於一個Object我們要求必須有這樣一段說明,特別是前面的五行必須存在,如果做了改動那麼最後兩行也要加上。這樣一般的一個Object,我們從這段說明就能了解到一些很重要的信息。
下面是include一些文件和繼承(inherit)一些Object。
#include <ansi.h>
#include "include/test.h"
inherit NPC;
先系統的文件,後自己定義的一些頭文件。特別要求的是必須有個和這個Object同名的".h"文件,比如"test.h"放在這個Object所在的目錄的下一級目錄"include"底下,就是說在include部分的最後一行是#include "include/test.h"。
在test.h定義所有在test.c用到的函數的原形,以及定義一些宏和常量。
這樣做的好處是:
第一不用出現一個函數在引用時沒有說明,
第二如果想知道這個Object有什麼函數,直接看這個文件就可以了,不必去看那個test.c,可能test.c非常長。
第三如果建立一個help系統,用來查詢每個Object存在的函數,那麼這樣直接去讀test.h就可以,否則是一件很麻煩的事。
關於inherit我們在繼承部分再說。
2.3.2 變數說明
在變數說明部分,大家最好在每個變數後面加一個簡單的說明。
2.3.3 函數
一個Object的函數的順序和名字對這個Object的表現是毫無影響的。但是為了讓這個Object有良好的可讀性,我們要求一個Object的函數按如下方式排列和命名:
首先是變數的介面部分,這些函數統一用Set+變數名來改變該變數的值,用Get+變數來返回變數的值。比如
static int level;
void SetLevl(int i)
{
level = i;
}
int GetLevel()
{
return level;
}
其次是一些操縱和控制變數的一些函數。比如
void AddLevel(int i)
{
一個Object的函數的順序和名字對這個Object的表現是毫無影響的。但是為了讓這個Object有良好的可讀性,我們要求一個Object的函數按如下方式排列和命名:
首先是變數的介面部分,這些函數統一用Set+變數名來改變該變數的值,用Get+變數來返回變數的值。比如
static int level;
void SetLevl(int i)
{
level = i;
}
int GetLevel()
{
return level;
}
其次是一些操縱和控制變數的一些函數。比如
void AddLevel(int i)
{
level += i;
}
這兩類函數要求每個單詞的第一字母大寫。
再是一些Object所能做的事件(event),比如戰斗,結婚等等。比如
void eventQuit()
{
...
}
這些函數要求事件的每個單詞的第一字母大寫,比如eventFight,eventMarry等等。
再下面的是由Driver調用的一些函數,比如create(), heart_beat,setup()。
最後是一些這個Object自己私有的函數,完成一些特別的功能。這些函數通常讓要求每個單詞的小寫,中間用下劃線(_)隔開。
要注意的是每個函數之間用一個空行隔開。
這些是對一個文件的整體要求,如果你有興趣將來在XO team寫程序,最好從現在開始就養成這樣的編程習慣。如果你是別的Mud裡面的巫師,我想一個Mud裡面最好也有一個統一的整齊的風格。
也許你會問,這樣要求有必要嗎?這樣太麻煩,程序寫了自己能明白就可以了。這是不對的,LpMud是大家合作的項目,如果你做的程序別人沒法看懂,不知道寫的東西裡面有些什麼,能調用什麼函數,那麼實際上你寫的東西是失敗的,沒人會去用它,它可能永遠「死」在硬碟上。而且函數統一的命名法能盡快找到你所需要的函數,同時也能提高整個程序的可讀性。
對於代碼風格XO還有一些別的要求,我們將在以後的文章中介紹,如果你加入了XO team,代碼風格將是第一篇要讀的文章。
小結:
關於Lpc程序和編程環境,就介紹到這里。看完這一章,我想大家要記住的是LpMud是採用Lpc做為編程語言,Unix文件結構作為文件組織形式。Lpc是編寫Object的一種語言,它的程序沒有特殊的開始和結束的標志。如果Object被使用到,那麼它被調入內存,如果這個Object有一個叫create()的函數,首先被執行,來初始化一些變數。
Lpc的Object是一堆變數的集合,同時帶有一些能操縱改變這些變數的函數。Lpc的代碼風格,我想一個Mud最好有一個統一的風格,特別的XO有自己的特別的要求。
題外話:
當了好久的巫師,也用Lpc寫了一些東西。我一直在試著理解Lpc,因為以我看如果一個巫師沒有真正理解Lpc,他就不可能真正理解LpMud。理解Lpc並不僅僅意味著會使用它,許多巫師能使用它但是並不真正理解它。我希望在這個Lpc的介紹文章,能給大家一個Lpc的整體的印象,真正把握和理解Lpc,能創造自己心中夢想的世界。
-----------------------------------------------------------
-----------------------------------------------------------
第二章 Lpc的數據類型
-----------------------------------------------------------
第一節 序言
Lpc的Object是由零個或更多一些的被一個或一個以上函數操縱控制的變數組成的。在代碼中函數排列的順序是不影響Object的特性,但是影響代碼的可讀性。當你寫的那個Object被第一次調用時,Driver將你寫的代碼裝入內存。當每一個Object被調入內存時,所有的變數是沒有值的。create()這個函數被調用來初始化Object值。
create()這個函數在Object裝入內存後立即被調用。在你讀本文時可能對編程一無所知,你可能不知道什麼是函數以及它是怎麼調用的;或許你有了一些編程的經驗,你可能對一個新創建的Object的函數相互調用過程是怎樣開始感到迷惑。在這些困惑得到解決之前,你更有必要了解的是這些函數操縱控制的到底是什麼東西。所以你最好先來讀讀這一章:Lpc的數據類型。可以這么說,幾乎90%的錯誤(包括丟失{}和())是由於錯誤的使用Lpc的數據類型。我認為真正理解這一章能幫助你更容易的編程。
-----------------------------------------------------------
第二節 讓計算機理解你
2.1 計算機語言
眾所周知的計算機懂得的語言實際上由「0」和「1」組成的機器碼。計算機根本不懂得人類的自然語言,實際上它也不懂得我們使用的高級語言,比如BASIC,C,C++,Pascal等等。這些高級語言能讓我們更容易的實現我們的想法。但是這些高級語言最終都要被翻譯成「0」和「1」組成的計算機語言。
有兩種方法能把高級語言翻譯成計算機語言:編譯和解釋。編譯類的在程序寫完之後用一個編譯器將其翻譯成計算機語言。編譯在程序執行之前就完成了。解釋類的翻譯的過程在程序執行時進行。由於解釋類的語言程序是邊執行邊解釋,所以一般都要比編譯編譯執行的慢。
不管是哪種語言,他們最終都要被翻譯成0和1。但是變數,那些
你存在內存裡面的變數,卻不可能只是0和1。
所以你必須有一種你
使用的那種編程語言裡面的方法來告訴計算機這些0和1應該被當做
整數還是字元,或者是字元串,或者別的什麼東西。這樣就必須使
用到數據類型。
2.2 數據類型
一個簡單的例子:你現在有了一個變數,你把它叫做『x』並且
賦予它一個十進制整數值65。在Lpc你可以這樣的語句來做這件事:
------
x = 65;
------
接著你可以做象下面這樣的事:
-----
write(x + "\n");
y = x + 5;
-----
第一行把65和字母"a"輸出到屏幕上
第二行把70這個值賦於變數y
對計算機來說有個問題:它不知道你所說的 x = 65;中的65什麼意思.
你認為是65,但是計算機可能認為是:
但是,對計算機來說,字母'A'也是被當做:
所以,當你想讓計算機明白 write( x + "\n" );, 它必須有一種方法
知道你想看到的是65而不是'A'.
計算機就是通過數據類型來區分65和'A'. 一種數據類型簡單的說就
是在內存的某處, 那裡代表了或者說指向某個給定的變數, 這些內存
儲存的數據是什麼類型的. 每個LPC的變數都必須有它對應的變數類型.
在上面給的例子, 本應在那些代碼之前有下面一行:
-----
int x;
----
這一行告訴Driver x應該指向什麼類型的值, 它應該被當做數據類型'int'
來使用. 'int' 是一個32位的整數. 到這里, 你應該有數據類型的基本
印象, 以及為什麼必須有數據類型. 他們可以讓Driver知道計算機存在
內存裡面的'0'和'1'到底是什麼東西.
2.3 Lpc的數據類型
所有的LpMud的Driver都會有以下的數據類型:
void, int, string, object, mixed, int *, string *,
object *, mixed *
大多數的Driver都會有下面這些重要的數據類型:
float, mapping, float *, mapping *
有一些Driver同時還支持下面這些數據類型:
function, struct, class, char
特別的有MudOS支持的數據類型:(以v22pre8為例)
void, int, string, object, float, mapping, function,
class, mixed, int *, string *, object *, float *,
mapping *, function *, class *, mixed *
2.4 一些簡單的數據類型
在Lpc入門裡面將介紹以下的數據類型:
void, int, float, string, object, 以及mixed. 對於復雜的數據
類型比如: mapping, array, 以及一些不常用的類型比如: class,
function, 我將在Lpc進階介紹. 這一節我們主要介紹三種數據類型:
int(整型), float(浮點數)和string(字元串).
一個int(整型)是一個整數, 比如1, 42, -18, 0, -10002938這些
都是整型. 在MudOS中一個整型是一個32位的整數, 有符號的整數.
在實際中int得到廣泛的使用, 比如開始介紹變數中的wiz_level,
再比如生物的天賦, 年齡等都通常都是int(整型).
一個float(浮點數)是一個實數, 比如2.034, -102.3453, 0.0,
1132741034.33這些都是一個浮點數. 在MudOS中一個浮點數也是一個
32位的實數, 有符號的實數. float通常不常用.
在Object的數值性質中, 我們通常也就使用int和float, 甚至只用
int, 在變數的初始化中int和float自動被賦為0. 但是一般的Driver
比如MudOS不檢查數值越界的情況, 還要注意的是這里的int和float
都是有符號的數, 這兩點要注意.
string(字元串)是由一或更多的字元組成, 比如"a", "我是飛鳥!",
"42", "飛鳥15歲.", "I am Trill.", 這些都是字元串. 注意的是,
字元串都是被""括起來, 這樣第一能區別象int(整型)42和string(字
符串)"42", 第二可以區別變數名(比如 room)和同名的字元串(比如
"room"). string類型的變數在初始化時, 如果沒有顯式的賦於一個
字元串比如: 空字元串"", 那將是0, 就是一空的指針.
作為最基本的數據類型int, float和string, 是一些復雜的數據
類型的基礎. 對這些數據進行運算和操作的操作符, 將在後面介紹,
不過Lpc的操作符和一般的C/C++的操作符一致. 只是有一點, 就+
Lpc支持string和int或者float直接相加, 比如我們上面提到的:
write(x + "\n");
"\n"是一個字元, x是一個整型的變數, 在Lpc解釋執行中, 自動將
x代表的數值轉化成一個字元串, 然後把兩個字元串接在一起.
當你在編程中使用一個變數, 你必須首先讓Driver知道這個變數
代表什麼樣的數據類型. 這個過程叫做變數聲明. 這必須在一個函
數或者一個Object的開始部分進行變數聲明. 怎麼做呢阿? 就是把
數據類型的名字放在你所要用的變數名前面, 舉個例子:
-----
void add_x_and_y()
{
int x;
int y;
x = 2;
y = x + x * x;
}
----
上面就是一個完整的函數. 函數名就是add_x_and_y(). 在這個函數中
一開始聲明落兩個變數x, y都是int.
下面介紹MudOS支持的數據類型:
int
一個整數(32位).
float
一個浮點數(32位).
string
無限長的字元串.
object
指向一個對象的指針.
mapping
一個關系型數組.
function
一種特殊的指針, 指向(object, 函數名)這樣一個組合.
arrays
數組的聲明採用使用 '*' 跟在一種基本的類型.
void
這種類型對變數沒有任何用處, 只對函數有用. 它表明這個函數
不返回任何值.
mixed
這是一種特殊的數據類型, 可以指向任何的數據類型. 如果一個
變數被聲明成mixed, 那麼Driver不會對它做任何檢查.
class
自定義的數據類型, 類似C的struct而和C++和class不一樣.
一上是MudOS支持的數據類型.
小結:
對一個變數, Driver需要知道存在計算機內存中的'0'和'1'到底
指的什麼東西, 這樣我們引入落數據類型. 我們學習3種簡單的數據
類型, 同時了解了MudOS支持的各種數據類型. 對於各種操作符, 不
同數據類型有各自不同的操作符, 比如你讓 "飛鳥"/"trill", 那
Driver一定會返回一個錯誤的. 大多數數的操作符和C/C++的一樣,
只是+ 還支持字元串和數字相加.
-----------------------------------------------------------
-----------------------------------------------------------
第三章 Lpc的函數
-----------------------------------------------------------
第一節 序言
在前面的介紹中,大家應該知道了Lpc的Object包含能處理變數的函數。
當函數被執行時,它的工作就是處理操作變數,還有是調用(call)別的函
數。變數在函數中被改變操作。變數必須有個數據類型使得計算機能明白
它指向的內存中"0"和"1"到底是什麼東西。一個Object的性質通常由它的
包含的變數確定,但是它的特性的表現卻是依賴於它包含的函數。一個
Object如果不含有任何一個函數那是不可想像的。那麼:什麼是函數。
-----------------------------------------------------------
第二節 函數
2.1 什麼是函數?
和數學的函數一樣,你給Lpc的函數一個值,它能返回一個值。有些語
言,比如Pascal,會區分過程和函數。Lpc和C/C++一樣,沒有過程,但是
明白這種區別還是有用的。Pascal叫做過程的東西,Lpc叫做類型是void
的函數。換句話說,過程就是什麼都不返回的函數。Pascal叫做函數的,
必須返回一些東西。在Lpc中,最無聊的,最簡單的,但也是正確的函數
是這樣的:
-----
void eventDoNothing() {}
-----
這個函數不接收任何輸入,不執行指令,也不返回任何值。
每一個Lpc函數都由三部分組成:
1) 函數聲明
2) 函數定義
3) 函數調用
和變數一樣,函數必須先有個聲明。這樣可以讓Driver知道:
1) 這個函數將返回的是哪種數據類型。
2) 需要的輸入是什麼,多少。通常把輸入叫做參數。
一個函數聲明通常是這樣的:
類型 函數名(參數1, 參數2, ..., 參數N);
下面是一個函數聲明的例子,這個函數叫 DrinkWater,有一個string
類型的參數,返回的是一個int。
-----
int eventDrinkWater(string str);
-----
在上面的聲明中, str是輸入的參數的變數名,也可以沒有。就是說可以
象下面這樣聲明 eventDrinkWater()
-----
int eventDrinkWater(string);
-----
函數定義就是代碼,它描述了這個函數對傳人的參數究竟做了些什麼。
函數調用就是別的函數在任何地方使用執行了這個函數。一個函數在它
寫完後永遠不會被調用,那這個函數的存在的唯一意義只能是浪費內存和
硬碟。一個函數寫出來的目的是為了被調用。
下面是兩個函數相互調用的例子,兩個函數是 eventPrintValue() 和
add(),
-----
/* 首先是函數聲明,這個通常是在一個Object的開始部分。
*/
void eventPrintValue();
int add(int x, int y);
/* 其次是函數 write_vals() 的函數定義。我們假定這個函數將被調用
* 是為了描述這個Object.
*/
void eventPrintValue()
{
int x;
x = add(2, 2); // 我們指定 x 接收調用函數 add() 後返回的值。
write(x + "\n");
}
/* 最後是函數 add() 的函數定義。 */
int add(int x, int y)
{
return (x + y);
}
-----
有一點是指明的,在XO的編程的風格我們要求所有的函數都必須有聲
明,這個在我們最開始時候說明過。但是實際上必須有函數聲明的函數
是那些被調用在函數定義之前的函數。我們規定必須有函數聲明,這個
只是規定,但是它會給編程帶來好處。
在這一節我們知道什麼是函數,函數是由什麼組成。要記住,寫一個
函數的根本目的是為用它,調用它。一個函數永遠不會被調用,那它就
失去了存在的價值。通常別人使用你寫的函數,通常只關心它能對傳人
的參數做些什麼加工,就是這個函數的功能是什麼,返回什麼。因此一
個函數有一個好的函數名,能直接描述這個函數的功能是很重要的。我
在第一章中說明了XO規定的對函數的命名機制。採用統一的命名方式有
助於相互合作提高效率。
2.2 Efuns
也許你已經聽說過efun這個詞了,他們是外部定義的函數,是
externally defined function 的縮寫。就是說,他們是由Mud Driver
定義好的。如果參加過Lpc的編程,或者看過Lpc的代碼,你可能找到這
樣的一些表達式:this_player(), strcmp(), implode(), filter(),
等等,看起來象是一個函數,而你找遍整個Object以及這個Object繼承
的所有Object中都沒有這些函數,這就表明他們是efun。efun存在價值
是因為他們執行起來要比一般的Object帶有的函數速度快的多,為什麼
快呢,因為他們是以計算機直接能理解的二進制的形式存在。對於Object
內部定義的函數,我們通常叫他們是lfun(local function)。一個巫師
主要工作也就是編寫一些lfun組成的Object。
在上面的例子中的 eventPrintValue() 中調用了兩個函數,第一個是
函數 add(), 這個是有你聲明和定義的,這個就是lfun。第二次調用,
是調用函數 write() 這個函數通常就是efun。Driver已經替你聲明和定
義好了。你所要做只是調用它。
efun被創立是為了
1) 處理一些很常用的,每天都有許多函數會調用的。
2) 處理internet socket的輸入輸出。
3) 以及一些Lpc很難處理的事,畢竟Lpc是C的很小的子集。
efun是用C寫好的,內嵌在Driver裡面的。在Mud起來之前,和Driver
一起編譯好的,他們執行起來會快的多。但是正和你期望的一樣,他們
的調用和你寫的函數的調用方法是完全一樣的。總的來說,需要關心的
和一般函數一樣,它需要傳入什麼參數,它將會返回什麼的東西。
怎樣得到一些efun的信息,比如傳入參數和返回的類型,通常在一個
Mud裡面,你可以在類似這樣的 /doc/efun 的目錄底下找到,或者直接
用 help <efun名> 指令就可以得到幫助。efun及其依賴於你所在的Mud
的Driver,不同的Driver帶有的efun區別是很大。
對於XO,使用的是MudOS,一般的efun,只要用 help 指令就能得到
幫助,或者你多看看源碼,看看別人是怎樣使用的,當然你如果無論如
何也不能明白一個efun,你可以問問大巫師,他們通常會很樂意和你探
討的。但是有一點是指出,能自己解決的問題最好自己解決。
2.3 自己動手寫函數
用Lpc寫Object的函數,是為了表現這個Object的特性。這個特性的
函數實際上就是一些代碼按順序排列,排列的順序決定了這個函數。一
個函數被調用,函數的代碼就按照函數定義中代碼按順序執行。在
eventPrintValue()中,下面這個語句:
-----
x = add(2, 2);
-----
必須在 efun: write() 之前調用,如果你想看到正確的結果。
為了返回這個函