tmi-2 efun 與 simul_efun 簡單說明 - MUD Game

Rachel avatar
By Rachel
at 2014-06-28T10:26

Table of Contents

所有的 simul_efun 都位於 /adm/simul_efun 目錄下,有些 .c 檔
內只有一個 simul_efun,有些會包含好幾個。

底下有說明的部份就是我判斷會用到、常用的、重要的,相反的若我有
說這東西沒用、很少用、用不太到、我不太熟....這類的,就代表我判
斷就算不知道這些東西也沒關係,有興趣的可自行研究這樣。

依據就是我在 sanc 1x 年的經驗。


int adminp( mixed ob_or_str )

判斷一個物件或是 id 是不是 admin,因為可接物件跟字串,所以它用
mixed 宣告,然後再用底下的判斷式區隔:

if(stringp(ob_or_str)) // 如果是字串的話
.
.
else if(objectp(ob_or_str)) // 如果是物件的話

然後其讀取的源頭就是 /adm/obj/master.c 的 query_member_group
函數。

int wiz_lv(string str)

這個則是我仿 sanc 新增的函數,例如說 laechan 是 wiz,則

wiz_lv("laechan") > 0

它主要是讀取玩家的 /data/std/connection 目錄下的連線資料檔去做
判斷的,而且當該玩家在線時它直接做 adminp(str) 的判斷。

string cap_words( string str )

基本上如果 str = "laechan", cap_words("laechan") = "Laechan",
如果 str = "abc def",cap_words(str) = "Abc Def"

這函數我摸 lpc 摸了十幾年用都沒用過。

string article(string str)

這東西主要是用在英文版的 tmi2-mudlib,比方我們要形容一隻鳥時是
"a bird",要形容一顆蛋時則用"an egg",那如何判斷啥時該用 a 啥
時該用 "an"? 就是用這函數,它會判斷 str 的首字字母是不是母音字
母 'a', 'e', 'i', 'o', 'u' 開頭。

int atoi(string str)

簡單的說它可以把字串 "123" 變成數字 123,它的做法很簡單

int num;
sscanf(str,"%d",num);

那有沒有 itoa?不需要,因為

int num=123;
string str;
str=""+num;

這樣 str 就是 "123"。

string htoa(string map_string,int e)

這個則是我為地圖系統新增的函數,它的關鍵段落在底下..

while(j-->0)
{
tmp=(s%2)+tmp; // 一直做 s mod 2 的動作
s=s/2;
}
map_string+=tmp;

從上面就可以想像 tmp 會一直做 "0" "1" 這兩個字串的累加。

簡單的說,例如底下的字串

str="7680,992,7,0,1020"

做 htoa 之後就能變成像底下這樣的字串:

map_string="110101010101010010101......"

而 e 就是其長度。

這東西基本上也只有地圖系統會用到。

int cant_attack(object me,object tar)

這個是我為 tmi2_v3_改 新增的 /adm/simul_efun/attack.c 裡面
的函數之一,主要是做 me 與 tar 能否進入戰鬥狀態的判斷,不能
的話就傳回 1(代表 cant)

當這樣的判斷被寫成全域函數時,則不管今天玩家是下 k mob,還
是 spell 法術 mob,還是 force 法術 mob,都只需要呼叫這個函
 數來判斷即可,相同的,管理者要控制今天 me 能不能攻擊 mob,
也是修改這個函數即可,則所有的攻擊指令就會全部適用。

string damage_str(int damage,int hp)

這個日後會改成 varargs 宣告。

這東西簡單的說就是,當某一目標受到 damage 的傷害時,這時跟
它剩餘的 hp 對照,就會得到一個比例。

 比方剩餘 hp 剩 1000 時,受到 500 的傷害,這時受傷比例就是
50%,damage_str 就會依據這個比例,決定要吐出什麼受傷訊息

switch(p)
{
case 0 : return "但是沒有造成任何傷害。"; break;
case 1..40 : return "形成輕微的傷害。"; break;
.
.

varargs mixed defence_attack(object me,object tar,int damage,int hit_chance)

這個也是 attack.c 的函數,me 與 tar 在戰鬥狀態時的閃格擋
處理函數。

我在這個函數裡有建立基礎的盾擋、武器擋兩種類型的格擋方式
 ,使用者可參考。簡單的說就是呼叫這個函數來專門處理閃格擋
,並依據它回傳的陣列來判斷是否受傷。

({tar 實際受到多少傷害, "相關訊息"})

比方 ({0, "但是被$O以盾擋開了"}), ({15,"形成輕微的傷害"})

varargs int normal_attack(object me,mixed attackers,int n)

這個就是當 me 與「它的戰鬥對象們」處於攻擊狀態時,me 會透
過 continue_attack 循環呼叫的函數,直到戰鬥結束才停止呼叫

attackers 就是 me 的戰鬥對象們,n 就是內迴幾次。

比方三連擊,傳統的做法可能如下

for(i=1;i<=3;i++)
normal_attack(me,attackers);

但採用內迴的做法,normal_attack 呼叫一次即可:

normal_attack(me,attackers,3);

normal_attack 每內迴一次,defence_attack 就會呼叫一次,唯
有 defence_attack 是無法內迴的,因為每一次的閃格擋都是獨立
的。

string base_name(mixed obj)

簡單的說如果一房間 ob = /d/area/wiz.c,那 base_name(ob) 就
傳回 "/d/area/wiz"。

varargs string explode_base_name(string str)

如果一 str = "/d/area/wiz",則 explode_base_name(str) 就等
於 "/d/area*wiz",也就是最後一個 / 會被替換為 *。

這是我為 tmi2_v3_改 新增的函數,它有什麼好處呢,就是方便使
用者對 base_name 出來的結果分離出[目錄]與[檔名]。

str="/d/area*wiz";
int s=strsrch(str,"*");

則此時:

[目錄] = str[0..s-1]
[檔名] = str[s+1..strlen(s)-1]+".c"

string to_chinese(string str)
string skill_name(string str)
string chinese_number(int n)

這三個函數寫在 /adm/simul_efun/chinese.c,它們則會呼叫
/adm/daemons/chinesed.c 去讀取儲存的中文資料。

比方 to_chinese("knight") = "騎士",能做這樣轉換的原因就在
於 knight 有透過 chinese 指令設定其中文是 "騎士" 的緣故

> chinese knight==騎士
chinese: knight==騎士 設定 ok.

chinese_number 很簡單:

int num=123456789;
string str=chinese_number(num);

則 str = "一億兩千三百四十五萬六千七百八十九"

有興趣者可參考 /adm/daemons/chinesed.c 裡面看這函數怎麼寫。

varargs int cat( string path, int start, int num )

一般簡易的 cat 用法就是 cat("/d/area/wiz.c") 這樣就可以馬上
秀出 /d/area/wiz.c 這個檔案的內容。

但是它也可以加參數,start 就是「要從哪一行開始 cat」,num就
是「要看多少行」,例如

::create();
seteuid(getuid(this_object()));
set("light",1);
set("short",HIY"\t\t\t神"HIW"之"HIG"國度\n"NOR);
set("long", @LONG
這裡是神居住的地方,在這裡遍佈著許多美麗的花園,裡頭
開滿了漂亮的花,還有幾隻蝴蝶在花叢裡飛舞著。中間有一條小
河流,潺潺的流水聲使你忘卻了心頭的煩悶!另外,還有幾位天
神正在坐在一旁的石頭上聊著天!

::create(); 就是 /d/area/wiz.c 的第 10 行,而上面也總共秀
出 10 行的資料。

varargs string extract( string str, int from, int to )
object first_inventory( mixed ob )
object next_inventory( object ob )
object shadowp( object ob ) { return query_shadowing( ob ); }

這幾個從來沒用過。

void log_file( string file, string text )

這個簡單的說就是,比方 file="editing",那實際上檔案是寫
在 LOG_DIR+file,也就是 "/log/editing"。

所以它實際上是 write_file,只是它更針對了要將 text 寫在哪
個指定目錄內,並且會依據原本檔案的大小做特殊的處理,比方原
本的紀錄檔已經很大了,就將其更名為 xxx.old,然後才寫入一個
新的 xxx 檔。

mixed copy(mixed var)

簡單的說,它可以傳回一個變數 var 的 copy。

var="123" copy(var) = "123"
var=({"1","2","3"}) copy(var) = ({"1","2","3"})
var=(["1":2,"3":4]) copy(var) = (["1":2,"3":4])

它的重要用途是,比方 mapping new_var=copy(var),則 new_var
與 var 之間是獨立的、不會連動的。

string creator_file(string str)

從來沒用過。

string data_dir(object obj)
string data_file(object obj)
varargs string user_data_dir(object obj, string name)
varargs string user_data_file(object obj, string name)
void assure_user_save_dir(object user)
void assure_save_dir(object user)

其實這五個寫成 simul_efun 是蠻浪費的,因為上面會看到它們都
有接 object obj 或 object user,代表這五個平常其實很少在其
它物件會用到的東西,是可以寫在 /std/user.c 或其相關繼承檔
 裡面的。

比方 me = laechan 這個玩家,則

data_dir(me)=/data/std/user
data_file(me)=/data/std/user/laechan
user_data_dir(me)=/data/std/user/l
user_data_file(me)=/data/std/user/l/laechan

上面的結果透過 running code 就可以跑出來:

write("data_dir(me)="+data_dir(me)+"\n"+
"data_file(me)="+data_file(me)+"\n"+
"user_data_dir(me)="+user_data_dir(me)+"\n"+
"user_data_file(me)="+user_data_file(me)+"\n");

後面兩個函數就沒用過了但也是 user data file 相關的函數。

void domain_log_file(string file, string message)

沒用過這東西,domain 在 tmi-2 裡面有時是指 /d 的意思,這點
我也是之後才知道的。

string domain_master( mixed domain )

這東西主要是用來找 /d 下面的物件,其控制的 d_master.c 檔,
比方可透過在 /d/area 下各個物件檔,透過 domain_master.c 可
找到它們的 d_master.c 檔(一般是在 /d/area/adm/ 目錄下)。

而且要該 d_master.c 檔存在才算數。

d_master.c 顧名思義就是用來控制 /d 下面各目錄的存取權用的。

string dump_socket_status()
varargs string dump_variable(mixed arg, int indent)

這兩個東西沒用過,dump 可以想成「要吐出什麼訊息」的意思。

後面那個蠻簡單的,它就跟 identify 是類似的東西,把 identify
函數會做的事情透過 dump_variable 秀給你看。

比方底下的 running code

obs=({"1",2,({"3",4}),(["5":6])});
write("identify(obs)="+identify(obs)+"\n"+
"dump_variable(obs)="+dump_variable(obs)+"\n");

========== 程式執行區 ==========
identify(obs)=({ "1", 2, ({ "3", 4 }), ([ "5" : 6 ]) })
dump_variable(obs)=ARRAY:
[0] == "1"
[1] == #2
[2] ==
[0] == "3"
[1] == #4
[3] ==
["5"] == #6
========== 程式執行區 ==========

總之這東西很少用。

varargs int emote (object sender, string msg_self, string msg_others,
mixed target, string msg_target, string extra)

這東西已經沒用了,目前 emote 都用 /adm/daemons/channeld.c
來控制。

然後從這東西就能看得出來,就算 tmi2_v3 有撰寫 emote 系統,
使用者(例如我)依舊可以無視它,自己寫新的 emote 與公頻系統
,關鍵就在於你將系統寫好後,要如何使它 work,並無視舊的系
統─即便今天舊的東西被寫成了 simul_efun 一樣可無視。

那為什麼我寫好新的公頻系統後不拿掉這個舊的 emote 呢?因為
 或許有 tmi2_v3_改 的使用者會想用舊的不想用新的。

varargs mixed *exclude_array(mixed *array,int from, int to)

這東西簡單的說就是

obs=({1,2,3,4,5});
obs=exclude_array(obs,1,3);
write(identify(obs)+"\n");

========== 程式執行區 ==========
({ 1, 5 })
========== 程式執行區 ==========

為什麼剩 1 跟 5,因為 obs[1..3] = ({2,3,4})

所以 exclude 的意思在這裡就可以想成「排除掉元素 1..3」的意
思,也就是 ({1,2,3,4,5}) 排除掉 ({2,3,4}) 就是 ({1,5})

這東西我蠻少用的,因為一般都是明確知道 obs 裡面有什麼,然後
做 obs-=({其中的元素}),不過有時會用得到它。

然後同樣的,這裡也能仿 exclude_array 寫 exclude_string,這
函數用到的機會就比較多了。

/adm/simul_efun/existence.c

這裡面宣告的一些函數都是「判斷OOXX是否存在」的相關函數。

int file_exists(string file) 判斷檔案存不存在
int directory_exists(string dirname) 判斷目錄存不存在
int user_exists(string user) 判斷一個玩家 id 存不存在

第三個我在 sanc 蠻少用的,但是 tmi2_v3_改 有機會用到。

例如在獵人的貪婪之島遊戲裡,要判斷「比諾透」這個玩家還有
 沒有活著:

if(user_exists("比諾透"))

object find_object_or_load (string str)

這個函數非常非常的重要而且常用。

find_object_or_load 顧名思義就是先在記憶體裡面找 str 這個
物件檔案有沒有被載入,有的話就直接傳回該物件,沒有的話就
load 該物件。

也就是先做 find_object,找不到就做 load_object,而 load 一
個物件的方法就寫在裡面:

catch( call_other( str, "???" ) );

用 catch 包住就是即便 call_other 的時候產生錯誤也能無視。

string format_string (string format, mixed *variables)

這東西我幾乎沒用過。

string substr(string ostr1,string cstr1,string cstr2)

這東西是我新增的,而它其實就等於 replace_string。

string substr(string ostr1,string cstr1,string cstr2)
{
return replace_string(ostr1,cstr1,cstr2);
}

string no_ansi_color(string str)

比方 str = "$HIR$test$NOR$",那 no_ansi_color(str)="test"

string get_ansi_color(string str)

比方 str = "$HIR$test$NOR$",那 get_ansi_color(str)="test"

這兩個函數就是做這些處理用的。

varargs string Ctime(int t,int no_color)

用底下的 running code 來測

i=time();
write("ctime(i)="+ctime(i)+"\n"+
"Ctime(i)="+Ctime(i)+"\n"+
"Ctime(i,1)="+Ctime(i,1)+"\n");

========== 程式執行區 ==========
ctime(i)=Sat Jun 28 20:45:55 2014
Ctime(i)=6/28 20:45(六)
Ctime(i,1)=6/28 20:45(六)
========== 程式執行區 ==========

Ctime 是 sanc 的 adm 寫的函數,用習慣了所以也寫進 tmi2 裡
面,並加了一個 no_color 的參數。

然後 Ctime 可以透過之前介紹的 local_time 來更簡化,新的版
本就會以 local_time 來處理。

varargs string format_time(int tm, int verbose)

這函數很好用,比方要知道 99999 秒到底是幾天幾小時幾分幾秒

write(format_time(99999)+"\n");

========== 程式執行區 ==========
1天 3小時 46分 39秒
========== 程式執行區 ==========

比方要 show 玩家已經發呆了幾分幾秒、玩家從創角色到現在已經
過了多久,都可以呼叫這個函數來 show。

varargs string intl_date_stamp( int time_flag )

這函數用都沒用過。

ret = sprintf( "%d-%02d-%d", year, 1 + member_array( month, MONTHS ), day );

嘛,排出來大概是 西元-月-日,然後如果有給 time_flag,就再
show 出幾點幾分幾秒,不然就只秀出 2014-06-28 這樣。

它也算好用,但是應該再給使用者可以自訂什麼分隔符號的參數,
例如 intl_date_stamp(0,"/") 那就秀出 2014/06/28 這樣,或是
intl_date_stamp(-1,"-") 那就秀出 28-06-2014 這樣。

使用者可根據這個概念自訂適合自己 mud 的時間顯示相關函數。

/*
varargs void get_char (string fun, int flag)
*/

這東西已經被 tmi2_v3 abort 掉了,而其實 efun 就有了只要呼
叫 efun 的就夠了。

(因為 get_char 並不需要做什麼特殊的處理,反過來說需要做特
殊處理的話應該要使用 input_to)

varargs object get_object( string str, object player )

這東西我幾乎沒用過,不過從函數的內容來看應該是蠻好用的,它
甚至可能還比 find_object_or_load 好用。

 不過我猜使用的時機多半是在 wiz 使用指令時。

簡單的說,比方今天做 get_object(str),它的搜尋順序依序就是

1.str="me" 時就傳回自己
2.str 這 id 就是身上某物的 id 時就傳回該物品
3.str="here" or "env" or "environment" 時就傳回 environment(me)
4.str=某線上玩家的 id 時就傳回該玩家
5.str=某線上生物的 living_name 時就傳回該生物
6.真的都找不到時就將 str 視為物件檔案,試著載入並傳回該物件

(通常只有 wiz 會用到 5,6)

這東西在 /cmds/object/_data.c 可以找到,data 指令接的 str
就有這個特質,所以使用者才可以 data me、data here、..

more 指令理論上也應該要用 get_object。

varargs mixed get_objects( string str, object player, int no_arr )

就想成是 get_object 的多次呼叫版本,然後不需呼叫多次,只
要呼叫一次 get_objects 就可。

str 要依它指定的格式以 ":" 分隔。

幾乎沒用過,就不介紹哩。(因為有其它替代做法不一定要呼叫它)

varargs string get_stack( int x)
getoid(object obj)
int gettype (mixed item)
string strtype (mixed item)
int comptype (mixed item, mixed other)
int hiddenp( object ob )

以上幾個從來沒用過,我也不是很熟,節省時間,不介紹哩。

要判斷一個東西的 type 我通常都用 stringp、mapp、pointerp、
等等的函數,甚至用 identify 也可。

有興趣的可自行研究。

varargs string identify( mixed a, string indent )

這個函數非常的好用,我也很頻繁地使用它,因為它可以把任何變
數變成以字串的形式顯示出來,這樣就不必花時間解析變數的內容
 再做格式化輸出,有時考量到效率問題以 identify 把變數轉成字
串輸出出來即可。

有興趣的可自行用 running code 把任何變數塞進 identify 裡面
再對照輸出的結果,就知道它是做什麼的。

它最大的好處我認為是可以用來憑空生出 .o 檔,我的意思就是說
 ,.o 檔的產生不一定都只能靠 save_object 這個函數,它也可以
靠 write_file + identify 來辦到。

string query_idle_string( object player, int verbose )

這東西用都沒用過,它其實是 query_idle + format_time 的結合
,而通常我們需要知道一個玩家發呆多久時是在 "who" 的時候,
 更多時候是需要知道玩家有沒有斷線、已斷線多久。

所以這函數用到的時機是很少的,除非使用者的 mud 有很在意玩
家發呆了多久而且會經常顯示出來這樣,比方

> l
[/d/area/wiz ]
神之國度

這裡是神居住的地方,在這裡遍佈著許多美麗的花園,裡頭
開滿了漂亮的花,還有幾隻蝴蝶在花叢裡飛舞著。中間有一條小
河流,潺潺的流水聲使你忘卻了心頭的煩悶!另外,還有幾位天
神正在坐在一旁的石頭上聊著天!

明顯出口有: whitetile, quad, shadow, 和 newbie.

神之僕人(servant) [已發呆 3 分 20 秒]

int index(mixed target, mixed *array, int offset)

這東西很少用到。它可以從 array 的指定位置開始找 target 這
個元素的位置。比方說今天 array 是一個 size 超過 10000 的陣
列,那我們每次找東西都得從位置 0 開始找的話太耗效率,反之,
若大略知道我們要找的東西差不多位於 5000 起的話

index(要找的東西,該size=10000的陣列,5000)

這樣就可以從 5000 找起,找到了就會傳回它的位置。

這東西很少用的原因是因為通常靠 member_array 就可以解決半數
以上的搜尋問題,剩下的就靠 for 或 foreach 或 while。

string int_string (int num)

這東西只有英文版 tmi2 用的到,可以把 2 轉成 "two" 這樣,
其它就以此類推。

varargs string iwrap(string str, int width, int indent)

這東西用都沒用過。

/adm/simul_efun/mail_package.c

處理 mud 內的 mail 用的。沒用過,有興趣可自行研究。

static int m_str2(int mp, int sp)

蠻奇怪的一個 function,我很少看到 simul_efun 這樣命名。

int match_string(string pattern, string source)

這函數我蠻少用的。用 running code 來試

write(match_string("abc","abc")+"\n"+
match_string("abc","abd")+"\n");

========== 程式執行區 ==========
1 <= abc = abc
0 <= abc != abd
========== 程式執行區 ==========

實在沒啥意義啦我覺得,做 if(str1==str2) 不就好了..

int member_group(string user, string group)

這東西就是用來判斷一個 user id 跟一個 group id 兩者是不是
match。例如 "laechan" 今天是一個 admin

write(member_group("laechan","admin")+"\n");

========== 程式執行區 ==========
1 <= 就代表 laechan 確實是 admin
========== 程式執行區 ==========

要知道有哪些 group 只要 more /adm/etc/groups 就可以知道。

void mkdirs(string path)

這東西還蠻好用的,比方今天我們要建立 /x/xx/xxx/ 目錄,只要
這樣做

mkdirs("/x/xx/xxx");

它會判斷如果沒有 /x 目錄就先建 /x 目錄,建好後發現沒有
/x/xx 目錄就建 /x/xx 目錄,之後再判斷又沒有 /x/xx/xxx 目
錄就建 /x/xx/xxx 目錄 這樣。

不過用到的機會很少就是了。

int destruct(object destructee)

就是用來消滅一個已載入記憶體的物件用的,BJ4。

nomask varargs void shutdown(int code)

shutdown 時會呼叫的函數。

nomask varargs object snoop(object snooper, object snoopee)
nomask object query_snoop(object who)
nomask object query_snooping(object who)

做 snoop 時呼叫的函數。

nomask int exec(object to_obj, object from_obj)

沒用過。

nomask int export_uid(object ob)

export 就是匯出的意思,匯出 ob 的 uid。沒用過。

nomask int set_eval_limit(int num)

沒用過。

以上幾個都寫在 /adm/simul_efun/overrides.c,它的意思就是它
想用自己寫的 simul_efun 去 override(覆蓋) efun,而需覆蓋的
原因就是因為它想自訂一些額外處理。

nomask int set_eval_limit(int num)
{
// 這一段就是它想做的額外處理判斷
if ( getuid(previous_object()) != ROOT_UID ) return 0;

// 前置處理完就呼叫 efun 做原本這函數該做的事情
efun::set_eval_limit(num);
return 1;
}

所以假設 time 函數也是 efun,你想針對 time 函數做什麼額外
處理的話就把 time 函數寫在 overrides.c 裡面,比方

int time()
{
int t=efun::time();
return t-3600;
}

這樣每次 time() 傳回來的時間都會少 3600 秒。比方以刀劍神域
 裡面的 ALO 世界為例,現實是白天,遊戲裡實際上是晚上,就可以
修改 time() 函數來達到目的。

mixed *path_file(mixed full_path)

這東西沒用過,剛看了才知道這東西跟 explode_base_name 是一樣
的,用 running code 跑如下

tmp="/d/area/wiz";
write(identify(path_file(tmp))+"\n");

========== 程式執行區 ==========
({ "/d/area", "wiz" })
========== 程式執行區 ==========

所以不習慣 explode_base_name 的人也可以考慮 path_file 函數
,它一樣可將 path 與 file 分離出來。

這就我說的,「很多東西我在知道之前我已經先寫了,而且也在一
大堆物件都用了,然後才發現這個時就已經來不及了」的意思。

/adm/simul_efun/pluralize.c
/adm/simul_efun/pronouns.c

我不太清楚這兩個是幹嘛的。

不過這兩個應該只有英文版的 tmi-2 用得到。

varargs string resolv_path(string cur, string newvalue)

這函數在寫 wiz 可用的指令時還蠻常用的,簡單的說就是,比方
你目前正在 /d/area 目錄,data me 就會看到如下的東西

> data me
cwd : "/d/area"

那麼,當你下 more wiz.c 時,它如何判斷是 /d/area/wiz.c 呢
? 就是用 resolv_path

resolv_path(me->query("cwd"),"wiz.c");

它就會去依據你的 cwd 參數,與後面的 wiz.c 參數,來解析後
得到 wiz.c 的完整檔名是 /d/area/wiz.c

如果你 more ../README,它同樣會拿 cwd 來跟 ../README 做解
析,得到你要 more 的目標是 /d/README 這個檔。

這就是 resolv_path 的用途。後面的參數就叫做「相對檔名」,
而前面的參數就叫做「絕對參考目錄」,絕對+相對 就能得出正確
的完整檔名,它就像是..

你的正確位置 = resolv_path("絕對參考座標","往右移兩格")

類似這樣的概念。

varargs void say(string msg, mixed exclude)

這函數值得一提的地方就是後面還可以加 exclude,所以它實際上
比 tell_room 更好用。

(我也是今天才知道 say 後面可以加 exclude,然後同樣的,我在
知道前已經用 tell_room(env,...,({欲排除的對象})); 寫了一堆

varargs void shout(string msg, mixed exclude)

同樣的悲劇,今天才知道 shout 可以接 exclude。

mixed *slice_array(mixed *arr, int from, int to)

這東西沒啥意義,要取得陣列中的 a..b 就直接取就好。

slice_array(obs,3,5) 跟直接 obs[3..5] 是一樣的。

(正確的做法是 slice_array 應判斷 size 及邊界,才有寫成函數
的價值)

/adm/simul_efun/system.c

這裡面定義了一些可直接回傳系統參數的函數。

string version() 傳回 mud 版本資訊
string arch() 傳回 mudos 執行在什麼作業系統的資訊
string mud_name() 傳回 mud 的名字
int mud_port() 傳回 mud 開在什麼 port (如 5000)
string mudlib_name() 傳回這個 mud 使用的這份 mudlib 的 name
string mudlib_version() 傳回這份 mudlib 的版本

int tail(string file)

這個從來沒用過。

varargs void tc(string str, string col, object dude)

這個函數真的很不好,因為它的名字太短了。

而且內容更腦x,直接無視吧。

int tell_group (mixed file, string msg)

這東西很少用,非常少,而且它用了非常沒效率的 read_file。

簡單的說假設有個檔案叫做你的好友名單,然後你要線上傳訊息給
所有好友,file 就是指那個檔案,它會把檔案讀進來看你有幾個
好友,然後就把 msg 傳給那些好友這樣。

void tell_object(mixed ob, mixed msg)

這東西實際上就是在做 message("tell_object", msg + "", ob);

而且 mixed ob 代表可接複數個 ob。

message 就是 efun,它會依據第一個參數是什麼,來決定要執行
什麼樣的訊息呈現。

varargs void tell_room(mixed room, string msg, mixed exclude)

tell_room 跟 say 一樣的意思,不同之處就是 tell_room 可以指
定要 tell 給哪個 room。悲劇的就是,絕大部份的情況就是 tell
給呼叫主體所在的 room──這時候用 say 就夠了。

varargs int show(object me,object tar,string msg,int damage)

這東西是 sanc 在用的函數,我在 tmi2_v3_改 也寫了一個,它好
用的地方就是可以依所給定的 me 與 tar,自動解析 $N、$O 等字
串要 substr 成什麼,然後再 tell_room 出來,比方

show(me,tar,"$N用砂鍋大的拳頭打向$O",100);

這意思就是 $N 會替換成 me 的名字、$O 會替換成 tar 的名字,
而最後面接傷害數值的話,在顯示該訊息的同時 tar 也會受到傷
害。

可自行 more /adm/simul_efun/tell_room.c 即可知。

理論上 say.c 也可以併入 tell_room.c,這個新的版本會做。

varargs string temp_file( string base, object obj )

很少用,只有少數指令會用到。

string tilde_path(string path, string name)

從來沒用過。

/adm/simul_efun/un_article.c
/adm/simul_efun/un_pluralize.c
/adm/simul_efun/unart_indefinite.c

英文版 tmi-2 在用的。

mixed *uniq_array(mixed *arr)

這東西就類似說,arr 是一個陣列,然後我們希望複製一個跟 arr
一樣的陣列 new_arr,而且不與 arr 有連動關係。

new_arr = uniq_array(arr);

大概是這樣。用到的機會不多。

mapping unique_mapping(mixed *arr, string func, string var)

這函數很少用,不過跟上面很類似,只是不清楚 func 是幹嘛的。

string *update_file(string file)

這個我從來沒用過,它的意思也不是像它字面寫的 update 啥。

string user_path(string name)
varargs mixed is_user_path (string path, string name)

這東西現在幾乎沒用了,/student 目錄我甚至打算在 tmi2_v3_改
讓它無效化了。

(因為會用到這東西通常也只有 wiz 指令時)

varargs int visible( object detectee_obj, object detector_obj )

這東西沒用過,大抵上它的意思就是說,一個 detector 想要"看到"
一個 detectee,要判斷「能不能看到」,就是用 visible 這個函數
來判斷。

不過它的判斷是寫死的,如果要沿用這個函數名的話,裡面的判斷就
改成適合自己的 mud 就可,它就類似生活在三次元空間的人,看不到
四次元(wiz 看不到 adm)的人,為何看不到? 因為 visible 回傳 0。

類似四次元 三次元
if( detectee_vis > detector_rank )
return 0; // detector can't see detectee.

/adm/simul_efun/vt100.c

這裡面所有的函數幾乎都用不太到,因為目前的連線軟體幾乎都能自
行調整一些顯示了,而不需要 mud 針對 vt100 介面的使用者來做什
麼特別的調整。

varargs string wrap(string str, int width)

這東西只對英文句子有用(也就是以 , ? . 為分隔的句子),一串落
落長沒有分行的英文長句,透過 wrap 就可以分行為指定寬度的段落
,它透過的就是 sprintf 內建的能力:

sprintf("%-=*s\n", width, str);

但是上面的 %-=*s\n 到底是啥意思? 我只能說 -= 就是你所想像的
那個 -= (以方 obs-=({xxx}) 的 -=),當 sprintf 裡面有 -= 時,
它就類似在做一個遞迴的東西。

隨便去 cnn 找一個 cnn 的英文,複製貼上到這裡就變底下

Whalers say they've been catching and eating whales in the area for centuries. This year's hunting season, which began on June 20, is the first since an international court ordered Japan to end its controversial research whaling expedition in the Antarctic, after failing to find evidence the program had legitimate scientific value.

透過 wrap 寬度指定 58 的話就變底下

Whalers say they've been catching and eating whales in the area for
centuries. This year's hunting season, which began on June 20, is the first
since an international court ordered Japan to end its controversial
research whaling expedition in the Antarctic, after failing to find
evidence the program had legitimate scientific value.

至於為啥第二行特別長? 阿災...XD

上面只適用英文,因為如果是中文段落的話它只認 , . ? 這些,中文段落字
與字之間是沒有空白的。

void write(string msg)

這函數沒啥好講的

message("write", msg + "", this_player());

總之它就是交給 message 函數處理。

「理論上」,當然也可以在 simul_efun 自定 message 函數來實現
簡繁轉換,這個我有空再試試,它的做法就是之前提過的:

void message(string kind,string msg,mixed tars)
{
// 對 msg 做簡繁轉換的判斷
msg=.......;

// 然後再 call efun 的 message
return efun::message(kind,msg,tars);
}

簡繁轉換的函數要上網找一下,這樣就不需要動 mudos,但缺點就
是 simul_efun 的執行效率畢竟不如 efun。

string writef( string str, int n, int flags )

從來沒用過。


simul_efun 大概就到這囉。

laechan


--
Tags: 線上

All Comments

蔡 (Cai) 道松 (Daosong)

Annie avatar
By Annie
at 2014-06-28T08:54
轉會到期最後期限(台灣時間) :2014/07/01 08:50 球員姓名 :蔡 (Cai) 道松 (Daosong) 球員ID :(397242280) 球員年紀 :17.33 特技 :Unpredictable 經驗 :2 領導能力 : (以上兩欄,可填可不填, 自行判斷) TS ...

愛麗莎 分解師

Suhail Hany avatar
By Suhail Hany
at 2014-06-28T03:02
注意:標題請用=andgt; [揪團] 伺服器-x XX團 ↑ 要空格 提醒 : 揪團文標題格式範例為 : [揪團] 貝婷-5 覆蓋 修改標題請按shift+t 修改內文請按shift+e ============ 以上閱畢請 ...

金卡多球隊未出人選

Isla avatar
By Isla
at 2014-06-28T01:02
金卡多球隊出了兩波大部分有跨球隊的都出了 剩下幾張還沒出 2B 羅世幸 可能球隊 TML 金剛 TML 太陽 TML 勇士 C 陳金茂 可能球隊 興農牛 2B 康雷 可能球隊 TML 雷公 TML 金剛 RF 林仲秋 可能球隊 興農牛 RP 劉義傳 可能球隊 兄弟象 ...

女武鬥該選哪種成長武

Gilbert avatar
By Gilbert
at 2014-06-28T00:53
感覺成長武器 以女武鬥來說 要玩暴力 就選臂鎧 但命中率真的很XXX 東方棍感覺中庸 有距離 有命中率 拳套 手套不知差在哪裡 因為對女武鬥不熟 各位有推薦的嗎 - ...

遠3固定團徵一位團員

Andrew avatar
By Andrew
at 2014-06-28T00:04
因為團裡有人畢業,所以又來徵人囉 伺服器:卡恩 頻道:CH30 ID:志村新八 職業:目前有狂戰、魔彈、冰結/召喚(已經有這三個人還缺一) 徵求一位抗魔有90,職業不衝突,會打遠三會準備補品的玩家 目前固定每天23:00出發,用競時通聯絡,我是用中華電信 意者請推文或站內信,明晚測試沒衝線就出發 ...