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