无名杀吧 关注:64,845贴子:289,475
  • 5回复贴,共1

【水】来开一个如何写AI的“教程”贴

取消只看楼主收藏回复

其实早就想写点什么“教程”类的东西,但是由于本人今年才刚接触JS和无名杀,半桶水的水平,而且很多方面其他的大神都已经讲的很详细了,也实在没什么可说的。不过在技能AI方面好像教程屈指可数,那我就尽我可能讲点我知道的吧,希望能帮到刚入坑无名杀技能写作的新人。


IP属地:湖北1楼2022-10-10 13:50回复
    由于我没有构思一个大纲就直接来写,所以我打算想到哪就说哪,并不系统。当然也很有可能说错,说错的地方欢迎行家大神批评指正,我的目的主要是希望新人能通过这个帖子基本知道“该怎么写AI”,“为什么我写的AI不管用”之类的基础问题。


    IP属地:湖北2楼2022-10-10 13:53
    回复
      那就正式开始了:
      无名杀的AI其实比较杂,并没有专门的一part来汇集所有的AI,一个技能里通常还会有几处需要用到AI。写AI其实搞清楚两个地方,写出来的AI就不会有问题,这两个就是:(敲重点)
      1、格式
      2、返回值
      比如我们看这么一条AI(先从简单例子开始)
      player.chooseTarget([1,game.countPlayer()],get.prompt('dcpijing'),'令任意名角色获得技能〖自牧〗').set('ai',function(target){
      return get.attitude(_status.event.player,target);
      });
      这是新杀刘虞辟境的ai
      这里面的格式就是.set('ai',function(target){ xxxxxx})这个完整格式是不能错的,不然必定出错。
      有点JS基础的人或许会改成箭头函数,比如.ai=(target)=>{xxxxx} 效果是一样的。
      但是新人最好不要记那么多,认准一个固定格式就行了。
      然后这个xxxx就是ai的具体计算部分了。
      上面这个 return get.attitude(_status.event.player,target); 就是此技能ai的计算部分;
      这里就要谈到第二个重点了,返回值。
      比如chooseTarget这个函数,他接收的ai返回值必须是“数字”,正数或者负数都行,但是程序“只会选择正数且数字最大的那个目标”,这个每个函数需要什么样的返回值是需要你去记的,或者多写两个技能自然就记住了,比如有的ai接收的返回值是布尔型的(真或假),那么你最后return(返回值)就不能是数字型,不然大部分会达不到你想要的效果,而要return true或者false。
      那么回到上面这个例子 return get.attitude(_status.event.player,target); 就是返回选择目标的人和目标之间的attitude值,所以这个返回的也是一个数字,是正确的返回值。众所周知get.attitude(对象1,对象2)就是返回对象1 对 对象2的态度,如果是友好态度就是一个正数,不知道是敌是友就是0,是敌人就是负数。所以上面这个例子最后chooseTarget选择的目标就是选择使用者的态度友好的目标,达到了选队友的目的,如果是选敌人前面加负号就可以了


      IP属地:湖北4楼2022-10-10 14:10
      收起回复
        书接昨日,关于.set('ai',function(target){
        return get.attitude(_status.event.player,target);
        });
        还有一个地方要说的,就是“参数”,也就是括号里的(target),有少部分的情况这个参数可以省略,就是下面的xxxx计算中不需要涉及到target,但是很显然上面这个例子里涉及到了,所以如果不填target也会弹窗报错。这个只要记住就行了。
        无名杀已经定义好的,在技能的content内需要写AI的函数除了chooseTarget以外,还有chooseCard,chooseBool等等之类的,写法基本相同,不同的只是在xxxx计算中加入更多条件,来达到更为复杂的选择,比如下面这个:
        target.chooseCard('he','交给'+get.translation(player)+'一张牌并摸一张牌,或不能响应其使用的牌直到回合结束').set('ai',function(card){
        var player=_status.event.player,target=_status.event.getParent().player,val=get.value(card);
        if(get.attitude(player,target)>0){
        if(get.name(card,target)=='sha'&&target.hasValueTarget(card)) return 30-val;
        return 20-val;
        }
        return -val;
        });
        这是新杀董承发动技能血诏,其他人选择给他牌的AI,我们具体来看看,首先set('ai',function(card)把card这个参数传进去,因为下面的判断需要对card进行相关操作,这个没问题。第一行var player=_status.event.player,target=_status.event.getParent().player,val=get.value(card)定义三个变量,其中player是做选择卡牌这个动作的玩家,target就是给牌的目标(即董承),val是这张卡的价值(是一个数值)。然后下面条件判断,如果给牌的角色与董承为友,那么进行下一步判断,如果卡牌是杀,那么返回(30-卡牌价值),因为卡牌如果为杀的话,价值一般不会超过10,所以通过30-卡牌价值来提高卡牌价值,那么如果选择者与董承为友,且手上有杀就会优先给杀,没杀才会给其他牌。然后如果选择者不是董承的友,就返回负的卡牌价值,一般只有【毒】本身的卡牌价值低于0,那么负负得正如果是地方会给董承【毒】,而不会给他其他任何有价值的卡牌,从而达成这个技能的AI。


        IP属地:湖北13楼2022-10-11 10:46
        回复
          那么技能content之内的AI差不多都是这些类似的,我们来看看技能content之外的AI。这些主要影响AI“是否发动技能”,我们先从简单的被动技能来。
          何为被动技能,简单说就是技能里带"trigger"的技能,trigger就是被动技能触发的时机。被动技能并不一定都要写AI,比如锁定技,因为是必须发动,所以AI去考虑是否发动,技能里带forced:true的就是如此。另外,有些技能里有direct:true的,AI也是会直接默认发动的。
          其实,你不写被动技能触发条件的AI,AI都会默认“使用技能”,那么,我们如何让AI在适当的时候“不使用技能”呢
          答案就是check:function(event,player){xxxxxxx},记住这个格式,xxxxx必须返回true或者false,返回false时AI不发动技能。
          check:function(event,player){
          return get.attitude(player,event.player)>2;
          },
          比如上面这个是赵昂【忠节】的AI,因为忠节是个有益技能,所以不能让AI无脑发动,技能AI里就是返回使用者对目标的友好程度大于2才选择发动。有的人可能会问为什么不是大于0,是为了避免主忠对已经跳过反的内奸使用,大于2才是“真队友”


          IP属地:湖北17楼2022-10-12 09:50
          收起回复
            那么,我们来看看无名杀AI编写的难点——主动技能的AI该如何写:
            无名杀主动技能的AI格式是ai:{xxx:xxxx,yyy:yyyy},这种key:value的格式,也就是说,主动技能的ai本身就是一个对象,这个对象包含了很多key,通过key的value来控制各种效果,学主动技的AI,也就是学各种key的用法,这么说是不是好理解一点了呢
            比如某一个主动技的ai这么写:
            ai:{
            expose:0.3,
            threaten:8.8,
            order:7,
            result:{
            player:1,
            },
            }
            来让我们逐个看看这些key里有些什么好东西来控制这个技能
            expose即身份暴露度,使用这个技能会给使用者加上0.3的身份暴露值(当暴露值为1时意味着所有ai完全明确你的身份),什么技能需要加这个key呢?比如晋贾充的“凶竖”就是必须得加的,因为凶竖是一个攻击技能,但他不会通过卡牌造成伤害,所以单独只发动这个技能,AI无法识别到技能使用者其实是你的对立面,达不到实际的效果(实际上别人对你使用凶竖,必定应该是你的对立面)
            threaten即嘲讽值,嘲讽值越高的人越会成为AI优先攻击的对象,比如技能“英姿”就有这么个标签,通常你觉得你的技能很厉害,而被打又不会对对面造成什么负面影响时,可以给自己的技能加这个标签,模拟现实中技能厉害但没什么防御的武将很容易挨揍的情况。当然threaten还有些其他的用途,因为threaten高一定程度代表拥有这个技能的武将“较为厉害”,所以“放权”之类的技能选择目标时也会参考目标的threaten值优先放权。
            上面两个标签虽然有用,但是并不影响技能的实际使用,就算你不写也不会有大问题,但是下面两个标签就直接决定你技能能不能正确释放了。
            order这个技能释放的时机,简单点说,值越高越优先放,order:7的话,基本属于AI装完装备就要开始使用技能了,如果order是10基本上一到可以用的时机就会立即先放技能,而order为1的话就是可以用技能的最后时机去用这个技能了,这个order标签是必填的,否则技能无法正常释放。
            result,这个标签影响AI是否使用技能,里面又有player和target两个子标签。技能不需要选择目标时,只需要写player标签,返回值大于0,AI就会在order规定的时机发动技能,返回值小于等于0就不会发动技能。如果技能需要选择目标就用target标签,target返回正数选择队友发动,返回负数选择敌方发动。


            IP属地:湖北21楼2022-10-13 16:14
            收起回复