mud吧 关注:20,800贴子:95,205
  • 39回复贴,共1

【求救】请教present用法及room地址的赋值问题

只看楼主收藏回复

dtsl的mudlib终于快要修补完毕了,目前差的最大一个模块就是公共武功的quest解密测试及修复。但第一个公共武功云帅轻功解密那里就卡壳了,原版dtsl代码有问题导致不能正常解密。我想出了方案但代码写不明白了,需要涉及到present和对非当前room的判断,排列组合折腾了好久写出的代码都编译出错
请教问题:
1、present能否查询非当前房间的物件?
2、如果能查询,代码应该怎么写?
问题详述:
当前房间:/d/job/cisha/chunzailou里有个npc xiang,然后通过询问xiang触发对房间
/d/quest/yunshuai-dodge/migong8的查询,判断/d/quest/yunshuai-dodge/migong8里是否已经存在lian rou(档案名lianrou.c)和ren fanzi(档案名killer.c)的id,代码应该怎么写?
我已经试过的有:
(1)present("lian rou",/d/quest/yunshuai-dodge/migong8)、present("lian rou","/d/quest/yunshuai-dodge/migong8"),编译均出错。
(2)前面没通过,猜想可能需要赋值,于是随便写了个变量名place,语句换成了present("lian rou",place).但无论是object place 还是string place,搭配写法place=/d/quest/yunshuai-dodge/migong8或者place="/d/quest/yunshuai-dodge/migong8"均报错,不知道这种room地点怎么赋值
没辙了,求代码正确写法或者能达成我目的的方法。


IP属地:上海1楼2014-09-24 14:00回复
    附上相关代码及背景详述:
    npc xiang的部分先关代码:
    void create()
    {
    set_name("香玉山",({ "xiang yushan","xiang","yushan" }) );
    //省略
    set("inquiry",([
    "贩卖人口":(:give_job:),
    "放弃":(:cancel_job:),
    "救人":(:do_action1:),
    ]));
    set("target_id","####");//防止别人用 ansha 等命令杀他。
    setup();
    carry_object(__DIR__"chouyi")->wear();
    }
    ……
    //中间无关代码省略
    ……
    int accept_object(object ob,object obj)
    {
    object target,killer;
    if(obj->query("daughter")!="lianrou")
    return 0;
    if(ob->query("dtsl_quest_ysdodge_help_ok"))
    return 0;
    command("grin");
    command("say 你可真行啊,找来这么漂亮的女人!\n");
    message_vision("$N一挥手,出来一个手下,把莲柔带走了!\n",this_object());
    target=new("/d/quest/yunshuai-dodge/lianrou");
    killer=new(__DIR__"killer");
    copy_object(target,obj);
    target->move("/d/quest/yunshuai-dodge/migong8");
    killer->set_status(ob);//这里有问题
    killer->move("/d/quest/yunshuai-dodge/migong8");
    ob->set("dtsl_quest_ysdodge_help_ok",1);
    return 1;
    }
    int do_action1()
    {
    object ob;
    ob=this_player();
    if(ob->query_skill("jiuying-dodge",1)){
    command("say 你甭想打这个歪主意了!\n");
    return 1;
    }
    command("say 好,敢来我这里救人,有胆量,就怕你是有去无回!");
    ob->move("/d/quest/yunshuai-dodge/migong1");
    return 1;
    }
    背景详述:解密要求一个协助player把莲柔(lian rou)打昏交给香玉山,然后解密player去问香玉山“救人”触发解密流程。
    但关键是killer->set_status(ob);这句代码存在问题:第一个问题是它复制的状态是协助player的,按道理应该复制解密player的状态才对;第二个问题是dt的系统有任务人物专属设定,复制了协助player的状态后这个killer就只有协助player能kill了,其他人kill会返回“xxx根本不理会你的战斗请求”。完全背离了谜题设计初衷。
    于是我就想把killer的出现和复制代码转到ask 救人那里(do_action1部分),这样就解决了上述的问题。但是带来了新问题:每有player ask 一下就会产生一个killer,所以需要对migong8的room来检查判断,如果里面没有莲柔或者已经有killer了就不再产生killer。
    但是判断代码没搞定啊……


    IP属地:上海2楼2014-09-24 14:15
    回复
      亲,不要修改代码。把原代码放回去,把原代码和报的错误贴出来,然后发个贴,然后你的问题就搞定了。至于复制错误只是你传参的错误。


      3楼2014-09-24 20:17
      收起回复
        一,present可以判断任何物件内是否存在指定物件(或指定id的物件),首先你要理解这个efun的用法。如果present没有经过simul_efun中重载的话,那么present这个efun是这样定义的:
        object present( mixed str, object ob )
        这个efun会判断在ob的inventory内是否有str这个物件,这里有两种情况:
        1,str是一个物件,则直接看ob的inventory内是否有这个物件,如果有,直接返回该物件。
        2,str是一个string,也就是一个物件的id,那么会看ob的inventory内是否有id为str的物件,如果有,直接返回该物件。
        如果没有给定ob,则将搜索调用该efun的当前物件的inventory和当前该物件environment物件的inventory。
        ps.某物件的inventory可以理解为某物件内(比如房间物件内的物品人物或人物物件内的携带物),某物件的environment就是指该物件的所在环境物件。
        所以说,对于你的问题1,答案是肯定的,可以。
        你的错误在于,place的赋值方式有误,下面例子中会告诉你如何正确的做。
        至于问题2,该怎么写,我给你一个简单地写法作参考:
        object qstroom;
        if ( !( qstroom = find_object("d/quest/yunshuai-dodge/migong8") ) )
        qstroom = load_object("d/quest/yunshuai-dodge/migong8");
        // 上面这种写法十分常见
        if( objectp( present( "lian rou", qstroom ) && objectp( present( "ren fanzi", qstroom ) )
        {
        ooxx.....//如果在的话,你要做什么。。。放在这里
        }
        二、你所说的set_status()函数存在问题,这个函数不是efun,至于他为什么会出问题,出了什么问题,如何修正,那要看代码才知道了。


        IP属地:北京4楼2014-09-25 10:11
        收起回复
          1,仔细看下我说的present的定义,你会发现直接present("lian rou", ob) 其实是判断ob的inventory中是否有lianrou,肯定是不行的。同样的,objectp不可省略,这是判断你是否找到了目标物件。
          2,我提供的方式是可用的,可以不必move过去。。。- -!
          3,你的这个move方法么。。。怎么说呢。。。场景穿越之类的都以避免,比如直接用efun:move_object(),或者修改move()函数的定义增加个flag,判断下什么时候不执行look。不过这种方式真是很不正常,倒不是绝对不行,但基本没人会这样弄。。。相当于是绕了一个不靠谱的大弯。。。- -!是否有错误和隐患的话,思路应该是没太大问题,但是具体还要看你的代码实现。我个人感觉,完全没必要去纠结这种没意义不靠谱的方式。。。- -!


          IP属地:北京5楼2014-09-25 17:23
          收起回复
            前面的大神太高深,我给个更简单的建议。如果你每次判断的另一个地点固定,直接给那个地点加一个函数,进行本地判断后返回一个int。任务中直接调用那个房间的那个函数即可。注意要先判定那个房间存在。


            IP属地:天津来自Android客户端6楼2014-09-25 23:13
            收起回复
              我就分享一段我自己写的代码吧。我做了一个解谜任务,玩家拿着名为“聚风幡”的法宝,对着二郎神摇动,成功则会把二郎神连同自己抓到一个独立空间去谋害他。在摇旗的时候先要做个判定,就是那个空间内是否有人。我在独立空间里做了个函数:
              int is_clear() {
              object *inv=all_inventory();
              for (int i=0;i<sizeof(inv);i++)
              if (userp(inv[i])) return 0;
              return 1;
              }
              聚风幡这个item有个函数是对应摇旗动作的,里面定义了一条:
              object fan_room=find_object("/d/public/leibu/inside_fan");
              当摇旗的时候,swing flag,会调用一个判断:
              if(fan_room && fan_room->is_clear()==0)
              return notify_fail("你催动"+me->name()+",却没有反应,好像有其他人刚刚用过。\n");
              也就是如果这个房间是存在的,且其中有人在,就不能使用了。
              对照你的情况,你只要在前面的is_clear()函数中,把我写的判定物品改成present("xxx xxx",this_object())即可
              是不是很简单


              IP属地:天津7楼2014-09-25 23:47
              收起回复
                但关键是killer->set_status(ob);这句代码存在问题:第一个问题是它复制的状态是协助player的,按道理应该复制解密player的状态才对;第二个问题是dt的系统有任务人物专属设定,复制了协助player的状态后这个killer就只有协助player能kill了,其他人kill会返回“xxx根本不理会你的战斗请求”。完全背离了谜题设计初衷。
                按你意思这是两个玩家合作完成的任务?如果是这样,那么协助player和解密player必定在某个地方有关联,比如说协助player身上标记着协助对象的物件,那么在它身上找到这个物件传给killer->set_status();(比如ob2=ob->query("assit_ob"),killer->set_status(ob2));如果你找不到关联,你必须自己标记一个关联,让程序知道你这个是在协助谁(比如在开始任务的时候:协助player->set("assit_ob",解密player))
                关于第二个问题,你可以找到killer的文件,里面应该有个函数void intit(){add_action("do_kill","kill");修改do_kill函数可以让你想怎么杀它就怎么杀它。
                第三个问题:函数的参数数据类型不对,不报错才怪!present函数:object present( mixed str, object ob );你把,/d/quest/yunshuai-dodge/migong8(未定义的标识)和“,/d/quest/yunshuai-dodge/migong8“(字符窜)当成ojbect传给present,能不出错吗?把一个object 传到第二个参数,present才能检查那个object里面是否有叫作str的这个物件。
                第四个问题:还是数据类型与函数的问题:/d/quest/yunshuai-dodge/migong8这一串字符是什么?它跟a,b,c或hello,kill,have,place,....是一样的,是一个未定义类型的数据!


                8楼2014-09-26 00:02
                收起回复
                  killer部分代码
                  int set_status(object ob)
                  {
                  object guard;
                  guard=this_object();
                  guard->set("last",time());
                  guard->set("target_id",ob->query("id"));//这个控制
                  //后面省略
                  }


                  IP属地:上海9楼2014-09-26 00:46
                  收起回复
                    @hcc01 说的是都是正确的,特别是关于第三个问题一阵见血,我上面没有如此明确的指出你代码发生错无的原因。其实是这样,对于无论efun,simul_efun,lfun来说,都需要弄明白这些函数的用法,输入变量,处理过程,返回值或变量的类型,意义等等。
                    另外就是对于一些任务、想法等等一切要用代码实现的东东来说,可以说能找到n中实现的方式,无论@一叶之林 还是@hcc01 所说的方式或者我说的方式都是可以的。只不过有些方式方法经过多年的编码已经成了一种约定俗成的习惯,当然也未必都是最佳方式,但只要多读代码,多写东西,逐渐就会融会贯通了,到时候会发现(注意:我的经典语录再次出现了!!哈哈哈哈):技术编码永远不是瓶颈,难的是游戏世界的整体规划和平衡设定。


                    IP属地:北京10楼2014-09-26 07:57
                    回复
                      回复 xiuliinlove :你知道set("target_id")是干什么用的吗?它只是在KILLER上增加了一个数据,要让这人数据有意义,就得在某地方使用它,这个数据要在哪里使用?没有加kill的action的话,kill里面一般会有一个accept_kill()的判断。自己去找。还有,没什么特色不特色,整个游戏都是基于前人改的,根本就不会有特色!!你对函数和变量太不理解了。告诉你怎么做:在每个使用变量的地方,你都要找出这个变量在哪里定义,用来干什么;在每个调用函数的地方,也都要找出这个函数在哪里定义,怎么定义;在每个赋值的地方,你要懂得赋这个值的作用!函数或变量除了EFUN只能是本物件中定义过(找不到就去找inherit),而->这个符号可以让你调用别的物件中的函数。记住:函数名只是让你容易了解这个函数的作用,而不是你说英语计算机就听懂,所有的函数都是人工设定的用来执行一些动作的。PS:你知道set()在哪里定义了吗?你知道set()的数据是怎么保存的吗?


                      11楼2014-09-26 09:29
                      收起回复
                        if(stringp(obj->query("target_id"))&&obj->query("target_id")!=me->query("id"))
                        return notify_fail(obj->name()+"根本不理会你的战斗请求。\n");
                        if(arrayp(obj->query("target_id"))&&
                        member_array(me->query("id"),obj->query("target_id"))==-1)
                        return notify_fail(obj->name()+"根本不理会你的战斗请求。\n");
                        这个是kill里相关控制的代码。
                        能够找到这段代码的确更容易理解。但因为我对代码结构不熟,很多时候找不到源头,但结合函数名字和自己测试对一些函数功能还是能猜个大概的,之前我就是从killer->set_status(ob);和实际测试不让叫杀猜到set_status(ob);里的ob决定set的状态和能叫杀的id,这样我只要把ob弄正常了就好了。这样的确是不求甚解,但只要能达到目的就好了。对于代码盲来说纠结中间的问题过于高深。当然再解决了问题的基础上能再理解下原理也是非常不错的。其实对于我的问题,只要大家直接告诉我room赋值和判断是
                        object qstroom;
                        if ( !( qstroom = find_object("d/quest/yunshuai-dodge/migong8") ) )
                        qstroom = load_object("d/quest/yunshuai-dodge/migong8")
                        if( objectp( present( "lian rou", qstroom ) && objectp( present( "ren fanzi", qstroom ) )
                        这样写就可以了。其余的都算是各位超值附送的相关知识,非常感谢!
                        对待同一个问题,高手可能要弄明白原理,但菜鸟一般只要最后结果也就知足了。对待业余人士就不要从专业的角度提要求了,压力山大


                        IP属地:上海12楼2014-09-26 11:08
                        收起回复