Re: [閒聊] tmi-2 efun 與 simul_efun 簡單說明

作者: laechan (揮淚斬馬雲)   2014-06-26 15:39:01
繼續。
int inherits(string, object default: F__THIS_OBJECT);
void replace_program(string);
mixed regexp(string | string *, string, void | int);
mixed *reg_assoc(string, string *, mixed *, mixed | void);
這四個沒用過,不清楚。
mixed *allocate(int, void | mixed);
這東西簡單的說就是可以對一個陣列做初始化,例如說
mixed tmps;
tmps=allocate(3); // 配 size = 3 給這個陣列
則此時 tmps = ({0,0,0});
mixed *call_out_info();
這東西就是讀目前線上有哪些物件用到 call_out,實際傳回的結
果類似底下:
({
call_out 執行於哪個物件 哪個函數 幾秒後
({ OBJ(/cmds/wiz/_running), "clean_tmp_ob", 5 }),
({ OBJ(/adm/daemons/weather_d), "change_weather", 73 }),
({ OBJ(/adm/daemons/event), "initiate_sweep", 13 }),
({ OBJ(laechan /std/user#3), "autosave_user", 564 }),
({ OBJ(/adm/daemons/weather_d), "change_phase", 951 }),
({ OBJ(/adm/daemons/network/I3), "(: check_router :)", 253 }),
({ OBJ(/adm/obj/master), "free_objects", 1153 })
})
也就是說它是一個二維陣列。這東西的 size 越大對系統的負擔
就越重,執行效率高的 mud 是很少使用 call_out 的。
所以當一個 mud 開放很久了,然後想檢查到底哪些 wiz 目前有
寫 call_out 的東西,這函數叫出來跑一下就知道了。
int crc32(string OR_BUFFER);
mixed read_buffer(string | buffer, void | int, void | int);
int write_buffer(string | buffer, int, string | buffer | int);
這三個很少用到。
int write_file(string, string, int default:0);
int write_bytes(string, int, string);
write_bytes 很少用到,write_file 就很常用,簡單的說
write_file("要寫入的完整路徑檔名","要寫入的字串內容");
不需要先 fopen 也不需要 fclose 就是 LPC 的好處。
int rename(string, string);
檔案改名
rename("/d/area/wiz.c","/d/area/wiz.bak"); 這樣就改名了
int file_size(string);
int file_exists
對一個不曉得是目錄還是檔名的東西做 file_size 判斷,就會得
到一些回傳值
int f=file_size(str);
f = -2 str 是一個目錄
f = -1 str 這個檔案不存在
f = 其它 str 這個檔案的 bytes 大小
最常做的就是回傳值是否等於 -2,因為判斷檔案存不存在可以用
file_exists(str) 去做,在使用及閱讀上會更直覺。
string read_file(string, void | int, void | int);
string tmp=read_file("/x/x/xxx");
則 tmp 就是 /x/x/xxx 這個檔案的全部內容。
int cp(string, string);
cp("/d/area/wiz.c","/d/area/wiz2.c");
就可以把 /d/area/wiz.c 拷貝一份變成 /d/area/wiz2.c
int link(string, string);
這很少用,大概類似弄出捷徑之類的。
int mkdir(string);
mkdir("/open/test"); 就可以在 open 目錄下建立 test 子目
錄。
int rm(string);
rm("/d/area/wiz.c"); 就可以把 /d/area/wiz.c 刪除掉
int rmdir(string);
既然有 mkdir 就有 rmdir,刪除目錄的函數。
string clear_bit(string, int);
int test_bit(string, int);
string set_bit(string, int);
int next_bit(string, int);
string crypt(string, string | int);
string oldcrypt(string, string | int);
這幾個很少用。crypt 是用來加密一個字串用的,通常使用在對
密碼加密,例如
tmp="abc123xyz";
tmp=crypt(tmp,1);
tmp 就變成 "ljeohbi`!gm`kliceoamfjndfn`dcbgblaldobibc" 這
樣的東西。
可以把 tmp 後面接的 1 當成類似一個加密金鑰的東西,該金鑰
可以是字串也可以是整數,例如
tmp="abc123xyz";
tmp=crypt(tmp,"laechan");
tmp 就變成 "j`liklbf!kmaliibmjnffoakbmh`lbflehhnoengl"
或許你會問,有 crypt 那有 uncrypt 或 decrypt 嗎? 沒有。
因為要比對你輸入的東西與 crypt 後的東西是不是一樣,並不需
要這兩種函數,只需要把你輸入的東西同樣做 crypt,再比對兩
個已 crypt 過的東西是否一樣就行了。
string ctime(int|void);
這東西簡單的說就是
string tmp=ctime(time());
則 tmp = "Thu Jun 26 13:56:59 2014"
上面「各欄位」都很固定,而且以 " " 空格分隔,因此
mixed tmps=explode(tmp)," ");
tmps[0] = "Thu" = tmp[0..2] 星期幾欄位
tmps[1] = "Jun" = tmp[4..6] 幾月欄位
tmps[2] = "26" = tmp[8..9] 幾號欄位
tmps[3] = "13:56:59" = tmp[11..18] 幾點幾分幾秒的欄位
tmps[4] = "2014" = tmp[20..23] 西元幾年的欄位
int exec(object, object);
mixed *localtime(int);
很少用,就不提哩,localtime 就類似「當地時間」
秒 分 時 日 月 年 星期幾 今年已過幾天 與格林威治時間的秒差
({ 21, 1, 14, 26, 5, 2014, 4, 176, -28800, "台北標準時間", 0 })
上面就是 localtime 傳回的「陣列」,其實它還蠻好用的可以省
去從 ctime 去分離出字串再做解析的時間。
(這應該多多推廣才對XD)
string function_exists
string file_exists
這兩個也可以一起講,照字面上的意思就是「函數存不存在」以及
「檔案存不存在」。
if(file_exists("/d/area/wiz.c"))
因為這檔案存在所以上面的判斷結果為真。
object ob=find_object_or_load("/d/area/wiz.c");
if(function_exist("create",ob))
因為 /d/area/wiz.c 這個被載入的物件有宣告 create 函數,所
以它的判斷結果也為真。
string query_host_name();
string query_ip_name
string query_ip_number
上面三個如果都接 me 的話其回傳結果回別是
"sanctuary"
"127.0.0.1"
"127.0.0.1"
從上面可以發現 query_ip_name 跟 query_ip_number 結果是一樣
的,因為實際上沒有透過 dns 去解析 ip 的 name。
一般用 query_ip_name 就夠了。
int query_idle(object);
它可以傳回一個玩家目前已經發呆多久的秒數。
object snoop(object, void | object);
object query_snoop(object);
object query_snooping(object);
當呼叫主體對一目標物件做 snoop 時,該被 snoop 的物件所接收
到的所有訊息,都會拷貝一份傳送給呼叫主體。
這個就不做太深入的說明,有興趣可自看 /cmds/wiz/_snoop.c
int remove_call_out(int | void | string);
這個可以想成它能中止一個 call_out 的動作,一般是接字串,比

call_out("call_out_over",100);
然後在 100 秒到之前
int n;
n=remove_call_out("call_out_over");
就可以中止這個 call_out, 而且傳回的 n 值就是剩餘幾秒。
void set_heart_beat(int);
int query_heart_beat(object default:F__THIS_OBJECT);
這兩個是一組的,set_heart_beat 可以讓呼叫主體的心跳跳動,
或是心跳停止,1 就是跳動,0 就是停止。
而 query_heart_beat(ob) 可以傳回 ob 這個物件有沒有心跳,
有的話就是 1,沒有的話就是 0。
void set_hide(int);
void set_reset(object, void | int);
object shadow(object, int default: 1);
object query_shadowing(object);
這幾個很少用,set_hide 可參考 /cmds/adm/_hide.c 就知道它是
做什麼用的,hide 實際上就是呼叫了 set_hide。
mixed *sort_array(mixed *, int | string | function, ...);
這個要講同樣可以講好幾頁,所以只舉一個例子
int sort_value(int a,int b)
{
// 有三種回傳值
// 1 : 代表順序要變成 b 在前 a 在後
// -1 : 代表順序要變成 a 在前 b 在後
// 0 : 代表不調換順序
return a>b ? 1 : a<b ? -1 : 0;
}
int test()
{
mixed tmps=({5,4,6,2,3,1});
tmps=sort_array(tmps, (:sort_value:) );
write("tmps="+identify(tmps)+"\n");
}
上面的結果 tmps=({1,2,3,4,5,6});
比方一開始做 5 與 4 的排序,5>4 所以 5,4 變 4,5
之後換 4,6 比順序, 4 < 6 所以 4,6 順序不變.
比過一次後就變成 1,5,6,4,3,2
↑最小的值就被推到了最前面
接著換第 2 個跟之後的開始比
5 跟 6 比順序不變,5 跟 4 比順序要變 4,5 .....
比過第二次後就變成 1,2,6,5,4,3
^^^^
↑最小的前兩個就被推到了最前面
這樣一路比下來一路替換陣列的順序,就自然得到排序結果。
字串排序的話就簡單多了因為有 strcmp 可用
int sort_string(string a,string b)
{
return strcmp(a,b);
}
int test()
{
mixed tmps=({"laechan","spock","ruby","tinlans"});
tmps=sort_array(tmps, (:sort_string:) );
write("tmps="+tmps+"\n");
return 1;
}
這樣 tmps=({"laechan","ruby","spock","tinlans"}); 因為
四個人剛好 id 字頭都不一樣,然後 l < r < s < t 的關係。
反過來說,如果你要 t 先列 l 後列,就是這樣
return -strcmp(a,b) 或 return strcmp(b,a)
void throw(mixed);
沒用過不清楚.
int time();
傳回目前總秒數.
mixed *unique_array(mixed *, string | function, void | mixed);
mapping unique_mapping(mixed *, string | function, ...);
這兩個沒用過,但應該蠻好用的,有興趣可研究。
string *deep_inherit_list(object default:F__THIS_OBJECT);
string *inherit_list deep_inherit_list(object default:F__THIS_OBJECT);
這東西很簡單,比方以 /d/area/wiz.c 為例
ob=find_object_or_load("/d/arae/wiz");
write(identify(deep_inherit_list(ob))+"\n");
傳回的結果就是
({ "/std/room.c", "/std/object/ob.c",
"/std/object/contents.c",
"/std/object/ob_logic.c" })
也就是說如果你下 update -R /d/area/wiz.c 就會看到
> update -R /d/area/wiz.c
/std/object/ob_logic.c: Updated and loaded.
/std/object/contents.c: Updated and loaded.
/std/object/ob.c: Updated and loaded.
/std/room.c: Updated and loaded. ↑這裡以上就是 inherit list
/d/area/wiz: Updated and loaded.
string *shallow_inherit_list(object default:F__THIS_OBJECT);
沒研究,不清楚。
void printf(string,...);
就是 write,想成 write 就對了,只是它可以加 %s %d 什麼的比
較酷,ex:
printf("你的等級是 %d.\n",me->query("level"));
write 的話就是
write("你的等級是 "+ppl->query("level")+".\n");
string sprintf(string,...);
可以對你要輸出的訊息做格式化,例如說你要做線上玩家的等級列
表,沒格式化就輸出的話類似底下
laechan : 10
spock : 15
tinlans : 13
這樣就比較難看,所以才要做格式化,才會比較好看、易讀。
obs=users();
foreach(ob in obs)
tmp+=sprintf("%-11s : %3d\n",
ob->query("name"),ob->query("level"));
它的意思就是用 "11個字母的長度" 去放玩家的 name,用 3個數字
的長度去放玩家的等級:
123456789012345678
xxxxxxxxxxx : ooo
laechan : 10
spock : 115
tinlans : 103
%s 就是針對要格式化的參數是字串、%d 就是針對整數,一般最常
用的就是這兩種。
mixed *stat(string, int default: 0);
很少用不清楚。
int interactive(object default:F__THIS_OBJECT);
比方 interactive(me),就是看 me 是不是處於連線狀態,傳回 1
就是處於連線狀態,非 1 就是「斷線狀態」。
int has_mxp(object default:F__THIS_OBJECT);
int has_zmp(object default:F__THIS_OBJECT);
void send_zmp(string, string *);
int has_gmcp(object default:F__THIS_OBJECT);
void send_gmcp(string);
這幾個很少用。
string in_edit(object default:F__THIS_OBJECT);
int in_input(object default:F__THIS_OBJECT);
這兩個就是說,比方你下 running 指令,在你編完 running code
按 . 離開之前的狀態就是 in_edit。
又比方你看到一個訊息「請輸入: 」然後接著就等待著你輸入什麼
後按 enter,則在你未按 enter 前的狀態就是 in_input。
int userp(object);
就是判斷一個物件是不是玩家.
void enable_wizard();
void disable_wizard();
int wizardp(object);
enable_wizard 就是用在 makewiz,disable_wizard 就是用在
dewiz。
wizardp(me) 就是判斷 me 這個物件是不是一個 wiz,是的話就傳
回 1 不是就傳回 0。
object master();
這個函數傳回來的東西就是 /adm/obj/master。
int memory_info(object | void);
mixed get_config(int);
string query_privs(object default:F__THIS_OBJECT);
void set_privs(object, int | string);
沒用過不清楚。
int get_char(string | function,...);
這東西要講可以講很久。它跟 input_to 是相對的,input_to 是
等你輸入完什麼後按 enter(包括不輸入按 enter),但是 get_char
是只要你有碰到按鍵就算,比方
write("請在底下開始隨便輸入什麼......\n");
get_char("get_char_over");
return 1;
}
int get_char_over(mixed c)
{
write("\n你輸入的字元是 "+c[0..0]+", ASCII 數值是 "+c[0]+"\n");
return 1;
}
程式執行結果,比方你按 a
你輸入的字元是 a, ASCII 數值是 97
如果輸入的是 ctrl+c,ASCII 數值就是 3。
所以如果我們要做一個允許玩家一直重覆 get_char,直到玩家輸入
ctrl-c 才停止的東西,get_char_over 就可以這樣寫:
int get_char_over(mixed c)
{
// 碰到 ctrl-c 才離開
if(c[0]==3) return 1;
write("\n你輸入的字元是 "+c[0..0]+", ASCII 數值是 "+c[0]+"\n"+
"請繼續輸入....\n");
get_char("get_char_over");
return 1;
}
所以如果有人想寫用方向鍵操作走路的話,就可以用這函數來寫。
void reload_object(object);
void error(string);
void raise_error error(string);
很少用到。
int uptime();
mud 從開機後到現在已經過多少秒。
int strcmp(string, string);
比較兩個字串的函數,如果前面的字串比後面的字串大就傳回 1,
比後面的字串小就傳回 -1,相等就傳回 0。
mapping rusage();
沒用過不清楚。
void flush_messages(void | object);
沒用過,好像 edit 或 input_to 什麼時會用到。
void ed
進入一個編輯狀態,可參考 /cmds/file/_edit.c 或者是
/cmds/wiz/_running.c 都有例子可參考。
string ed_start(string | void, int | void, int | void);
string ed_cmd(string);
int query_ed_mode();
string cache_stats();
這幾個沒用過。
mixed filter(string | mixed * | mapping, string | function, ...);
mixed filter_array filter(mixed *, string | function, ...);
mapping filter_mapping filter(mapping, string | function, ...);
這幾個是一樣的東西,簡單的說就是可以「過濾」陣列,例如說
tmps=({1,2,3,4,5,6});
然後我們想把 3 以下(包含3) 給去掉
int filter_tmps(int a)
{
// return 0 就代表該元素是應剔除不應保留的
if(a<4) return 0;
return 1;
}
int test()
{
mixed tmps=({1,2,3,4,5,6});
tmps=filter_array(tmps, (:filter_tmps:) );
}
這時 tmps 就剩下 ({4,5,6})
它的運作原理就是把 tmps 的每一個元素都拿去呼叫 filter_tmps
函數,比方 filter_tmps(1),因為 1<4 所以 return 0,它得到
return 0 的結果就把 1 這個元素剔掉。
mixed map(string | mapping | mixed *, string | function, ...);
mapping map_mapping map(mapping, string | function, ...);
mixed *map_array map(mixed *, string | function, ...);
string malloc_status();
string mud_status(int default: 0);
void dumpallobj(string | void);
string dump_file_descriptors();
string query_load_average();
int set_light(int);
string origin();
int reclaim_objects();
int set_eval_limit(int);
int reset_eval_cost set_eval_limit(int default: 0);
int eval_cost set_eval_limit(int default: -1);
int max_eval_cost set_eval_limit(int default: 1);
void set_debug_level(int|string);
mapping debug_levels();
void clear_debug_level(string);
void opcprof(string | void);
mapping *function_profile(object default:F__THIS_OBJECT);
int resolve(string, string|function);
int set_encoding(string);
string to_utf8(string, string);
string utf8_to(string, string);
這幾個不太會用到,通常是系統或系統指令在用的。
int *str_to_arr(string);
string arr_to_str(int *);
固名思義就是把字串變陣列、把陣列變字串,但是基本上很少用
字串變陣列 : 字串本來就是陣列
陣列變字串 : string tmp=implode(tmps,",")
用 implode 還可以自訂分隔符號
void act_mxp();
void request_term_type();
void start_request_term_type();
void request_term_size(void | int);
沒用過。
void shutdown(void | int);
就是做 shutdown 用的,裡面給整數的話就是幾秒後 shutdown。
以上是 efun 的部份。

Links booklink

Contact Us: admin [ a t ] ucptt.com