|
大概找了一些代码,觉得可以把随机行走问题解释明白了,所以大体解释一下吧
首先,在一个叫“char.c”文件中,有如下代码:
void heart_beat()
{
int wimpy_ratio, cnd_flag;
mapping my;
object ob;
if (!environment()) return;
if ((ob = query_temp("link_ob")) && !ob->is_character() && --save == 0) {
save = 285 + random(30);
ob->save();
this_object()->save();
write(HIG "您的资料已经自动保存好了。\n" NOR);
}
ob = this_object();
my = query_entire_dbase();
// check user's client type
if( userp(ob) ) CLIENT_D->CheckStateChange(ob);
if (my["neili"] < 0) my["neili"] = 0;
if (my["max_neili"] < 0) my["max_neili"] = 0;
if (my["combat_exp"] < 0) my["combat_exp"] = 0;
if (my["potential"] < 0) my["potential"] = 0;
// here is the change.
if (my["eff_qi"] > my["max_qi"])
my["eff_qi"] = my["max_qi"];
if (my["qi"] > my["eff_qi"] + query_temp("apply/qi"))
my["qi"] = my["eff_qi"] + query_temp("apply/qi");
/*
if (userp(ob) && --exp_tick == 0) {
exp_tick = 300;
if (exp > 0) {
exp -= my["combat_exp"];
if (exp < -800) message("wizard:yuj", sprintf("%s:%d\n", my["id"], -exp), users());
}
exp = my["combat_exp"];
}
*/
// If we are dying because of mortal wounds?
// and here
if( (my["eff_qi"] + query_temp("apply/qi")) < 0
|| (my["eff_jing"] + query_temp("apply/jing")) < 0 ) {
remove_all_enemy();
die();
return;
}
// If we're dying or falling unconcious?
if( my["qi"] < 0 || my["jing"] < 0 || my["jingli"] < 0) {
remove_all_enemy();
if( !living(ob) ) die();
else unconcious();
return;
}
continue_action();
if (is_busy()) {
// halt from dazuo, tune, heal ... etc.
if (query_temp("pending") && is_fighting() && !userp(ob))
interrupt_me();
// We don't want heart beat be halt eventually, so return here.
// return; // 这里如果返回会造成 condition 无法更新,所以屏蔽掉。
}
else
{
// Is it time to flee?
if (is_fighting()
&& intp(wimpy_ratio = (int)query("env/wimpy"))
&& wimpy_ratio > 0
&& (my["qi"] * 100 / (my["max_qi"]+query_temp("apply/qi")) <= wimpy_ratio
|| my["jing"] * 100 / (my["max_jing"]+query_temp("apply/jing")) <= wimpy_ratio
|| (my["jingli"]+1) * 100 / (my["eff_jingli"]+query_temp("apply/jingli")+1) <= wimpy_ratio) )
// Modified by mxzhao 2004/04/28
{
int success = 0;
string wimpycmd = query("env/wimpycmd");
if (stringp(wimpycmd))
{
int count = 0;
foreach (string cmd in explode(wimpycmd, "\\"))
{
if (count++ > 4)
{
break;
}
if (command(process_input(cmd)))
{
success++;
}
}
}
if (success == 0)
{
GO_CMD->do_flee(ob);
}
}
// End
// Do attack or clean up enemy if we have fleed.
attack();
}
if( !ob ) return;
if( !userp(ob) ) {
ob->chat();
// chat() may do anything -- include destruct(this_object())
if (!ob) return;
}
if( tick-- ) return;
tick = 7 + random(5);
if( userp(ob) ) UPDATE_D->check_inventory(ob);
if (!is_ghost()) {
cnd_flag = update_condition();
if( !ob ) return;
}
// heal_up() must be called prior to other two to make sure it is called
// because the && operator is lazy 
if( (cnd_flag & CND_NO_HEAL_UP) || !heal_up());
if (!interactive(ob)) {
if (!query_condition("killer") && !is_fighting()
&& !sizeof(filter_array(all_inventory(environment()), (: interactive )))
set_heart_beat(0);
return;
}
// Make us a bit older. Only player's update_age is defined.
// Note: update_age() is no need to be called every heart_beat, it
// remember how much time has passed since last call.
ob->update_age();
if (query_idle(ob) > IDLE_TIMEOUT)
//if (query_idle(ob) > 10)
{
//ob->user_dump(DUMP_IDLE);
call_out("eval_function", 1,(:call_other,ob,"user_dump",DUMP_IDLE );
}
}
别的不用看,只看涂红部分即可。
大体意思,就是每次心跳,都调用一个叫chat()的函数
这个函数的位置,在npc.c文件里
内容如下:
int chat()
{
string *msg;
int chance, rnd;
if( !environment() || !living(this_object()) ) return 0;
if (query("neili")>100 && query("max_neili") > 200
&& query("race") == "人类" && !is_busy()) {
if (!is_fighting()) {
if (query("eff_jing")
&& query("jing")*100/query("eff_jing") <= 80)
command("exert regenerate");
if (query("eff_qi") && query("qi") >= 0
&& query("qi")*100/query("eff_qi") <= 80)
command("exert recover");
if (query("eff_jingli")
&& query("jingli")*100/query("eff_jingli") <= 80)
command("exert refresh");
} else {
if (query("eff_qi") && query("qi") >= 0
&& query("qi")*100/query("eff_qi") <= 40)
command("exert recover");
if (query("eff_jingli")
&& query("jingli")*100/query("eff_jingli") <= 40)
command("exert refresh");
}
if (!is_fighting() && query_temp("embed") && random(10) < 3)
command("remove "+query_temp("embed"));
if (query("eff_qi") && query("qi") >= 0
&& query("max_qi") && !is_fighting() && !query("mute")
&& query_skill_mapped("force")
&& query_skill("force") > 50
&& query("eff_qi") < query("max_qi")
&& query("eff_qi") >= query("max_qi")/3
&& !query("no_heal")) //set no_heal tag by campsun 2004.2.4
command("exert heal");
}
if( !chance = query(is_fighting()? "chat_chance_combat": "chat_chance") )
return 0;
if( arrayp(msg = query(is_fighting()? "chat_msg_combat": "chat_msg")) && !is_busy()) {
//return while msg is null add by campsun 2004.2.4
if (!sizeof(msg)) return 0;
if( random(100) < chance ) {
rnd = random(sizeof(msg));
if( stringp(msg[rnd]) )
say(msg[rnd]);
else if( functionp(msg[rnd]) )
return evaluate(msg[rnd]);
}
return 1;
}
}
同样,别的不用看,看涂红部分即可
这个函数的作用,是npc自动说话,比如徐霞客等人,都是话唠,各种说。
其中前半部分没有涂红的,就是什么情况下说,什么情况下不说,跟npc各种属性有关,这个不提
涂红部分,是谈的说话的几率。
每个会说话的npc,都有个属性,叫chat_chance,这个就是说话的几率
比如徐霞客,xu.c文件里,就有如下代码
set("chat_chance", 3);
换句话说,参照涂红部分代码,在条件允许的情况下,每次心跳,徐霞客有3%的概率会说话。
那么说什么话呢?
每个npc文件里,只要会说话,就有这么一个属性:chat_msg
比如,徐霞客就是
set("chat_msg", ({
(: random_move ,
CYN"徐霞客摇头晃脑地讲道:你看这大江南北好地方可真不少!\n"NOR,
CYN"徐霞客道:想当年我走遍嵩山、西域、终南山、昆仑山和武当山。。。\n"NOR,
(: random_move ,
CYN"徐霞客又说道:那南疆大理城和西疆伊犁城虽小,却和我们江南苏州、扬州一样繁华。\n"NOR,
(: random_move ,
CYN"徐霞客露出恐惧的表情:去星宿海、光明顶和铁掌峰都会遇到凶徒阻拦。\n"NOR,
CYN"徐霞客拍了拍脑袋:上次去到东海,听人说海中有个桃花岛仙境,不知是真是假。\n"NOR,
(: random_move ,
}) );
看吧,这就是徐霞客说的话,一共5种
等等,为什么这里有random_move呢?
呵呵,这个就是本文的主题:随机行走啦
其实呢,随机行走,也是说话的一种,换句话说,要么行走,要么说话,在代码里,把两者视为等同
我们数一数,一共出现了4次random_move,5次说话,一共9种
所以,徐霞客的代码,参照涂红部分代码,结合起来就是:
每次心跳,都有3%的概率行动,这个行动有5/9的概率是说话,每种话的概率是1/9,另外有4/9的概率是随机行走
那么具体怎么走呢?有如下代码:
int random_move()
{
mapping exits;
string *dirs;
object me = this_object();
if( !environment()
|| !mapp(exits = environment()->query("exits"))
|| me->is_fighting() || me->is_busy()
|| me->query("jingli") < me->query("eff_jingli") / 2 ) return 0;
dirs = keys(exits);
if (sizeof(dirs) < 1) return 0;
add_temp("random_move", 1);
command("go " + dirs[random(sizeof(dirs))]);
}
换句话说,这个是随机行走的条件。有些情况下,是不走的,比如精力不足什么的。
但更重要的是,我觉得他用的是:command go,而不是直接的move,也就是说,npc是“随机行走”,而不是随机移动,他也跟玩家一样,受到各种行走的限制,比如碰到挡路npc,比如一些迷宫,他也是要走的,而不是直接移动进去。
另外,在go.c中,有如下代码:
if (random(me->query_temp("random_move")) > 15)
me->return_home(dest);
}
我们之前在npc.c文件中的random_move函数中,记录了自动行走的次数
add_temp("random_move", 1);
在go.c中用到了。
只要自动行走超过15次,就回家了
return_home函数同样在npc.c当中,代码如下:
int return_home(object home)
{
if (home && !query("startroom")) return 0;
if (!home && stringp(query("startroom")))
if(!objectp(home = load_object(query("startroom")) ))
return 0;
// Are we at home already?
if( !environment()
|| environment()==home )
return 1;
// Are we able to leave?
if( !living(this_object())
|| is_fighting()
|| is_busy() ) return 0;
// Are we beast?
if( query("master") && find_player((string)query("master")) )
return 0;
// Leave for home now.
message("vision", name() + "急急忙忙地离开了。\n",
environment(), this_object());
if (move(home)) {
message("vision", name() + "急急忙忙地走了过来。\n",
environment(), this_object());
delete_temp("random_move");
return 1;
}
return 0;
}
从代码看,这个是直接瞬移到的
那么研究这个有啥用呢?
其实意义不大,我只是发现,wd任务的匪徒,也会自动行走......
代码如下:
set("chat_chance", 5);
set("chat_msg", ({
(: random_move 
}) );
换句话说,每次心跳,匪徒都有5%的概率,自动移动
所以......wd任务必须迅速找到劫匪,否则他就不一定跑到哪里去了......
|
|