ltblue@tx 发表于 2015-5-1 20:21:41

关于随机行走问题的详解

大概找了一些代码,觉得可以把随机行走问题解释明白了,所以大体解释一下吧

首先,在一个叫“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 :P
      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) )
                                say(msg);
                        else if( functionp(msg) )
                                return evaluate(msg);
                }
                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);
}


换句话说,这个是随机行走的条件。有些情况下,是不走的,比如精力不足什么的。
但更重要的是,我觉得他用的是: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任务必须迅速找到劫匪,否则他就不一定跑到哪里去了......

recollec@tx 发表于 2015-5-2 16:03:35

看这个玩意没什么大用的,随机数的,没办法

fansi@tx 发表于 2015-8-6 22:57:51

zmud可以直接调用函数随机行走不

ltblue@tx 发表于 2015-8-7 22:53:23

fansi@tx 发表于 2015-8-6 22:57 static/image/common/back.gif
zmud可以直接调用函数随机行走不

调用哪个函数?mud里没有现成的吧

byqiang@tx 发表于 2015-9-24 02:52:06

高手啊,看来楼主下了不少功夫

duguit@tj 发表于 2016-10-5 20:51:33

这个有啥用处呢< 求教

tianyi@tj 发表于 2016-10-7 23:21:23

duguit@tj 发表于 2016-10-5 20:51
这个有啥用处呢< 求教

就是研究一下mud的代码。。。。。。
页: [1]
查看完整版本: 关于随机行走问题的详解