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

看板mud (網路地下城/文字遊戲)作者 (小太保)時間11年前 (2014/06/26 15:39), 11年前編輯推噓1(102)
留言3則, 3人參與, 最新討論串2/5 (看更多)
繼續。 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 的部份。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 210.61.157.53 ※ 文章網址: http://www.ptt.cc/bbs/mud/M.1403768344.A.FC3.html

06/26 16:27, , 1F
simul_efun 要明天後了
06/26 16:27, 1F

06/26 22:18, , 2F
受益良多!
06/26 22:18, 2F
mudos 目錄(下載原本的 tmi2_fluffos_v3 裡面就有)裡面就有這些 函數列表,然後啟動 tmi2_v3_改 很多函數都能實際 run 看看,我 自己的學習歷程是「並非從這些基礎開始」,所以我看到有人願意 從啃原文 document 開始我認為這是很好的事情,因為寫物件寫技 能寫指令甚至已經在寫系統了,然後也寫到一定程度了(我很多東西 在 2000 年以前就都已寫了),才發現基礎的重要時已經來不及了, sanc 目前在用的家族系統就是 2000 年後重寫過的產物,舊版是用 read_file/write_file... so 我現在也很重視 document,能寫多少算多少,tmi2_v3_改 能塞 多少就塞多少(我今天有把從 sanc 下載的東西集中到 sanc 資料夾) ,剩下的就是看大家還需要知道什麼就盡量問,我就盡量回這樣。 ※ 編輯: laechan (61.224.75.82), 06/26/2014 22:48:12

06/27 01:45, , 3F
這兩篇跟API一樣 都是很重要有幫助
06/27 01:45, 3F
文章代碼(AID): #1JgyuO_3 (mud)
文章代碼(AID): #1JgyuO_3 (mud)