乌龟服吧 关注:23,665贴子:296,412

乌龟服奶防骑练级单刷【一键宏】代码详解和思路分析

只看楼主收藏回复

前言:去年年底我加入了乌龟服,并起了两个骑士号,在这几个月的升级过程中,我逐渐总结出一套便利实用的一键宏。
在讲宏之前,先说一下我使用的天赋是30/21/0,神圣系点满神佑打击拥有6秒CD的神圣震击,防护系点出神圣之盾确保有足够的生存能力。
在乌龟服骑士练级毫无疑问用防骑是最有效率的。但防护系在点出神圣之盾后,就已经有了足够的生存和群怪能力。再继续深造防护虽然可以带来更多的仇恨能力,但对练级缺没太多帮助,因此防护21点足够用了。
剩下的天赋则全部投入到神圣系,以便进一步强化生存能力。尤其是倒数第二行的神佑打击,这个曾被大家嘲笑为“微操大师”的天赋,它对骑士练级和单刷有巨大的帮助。同时,为了对应“微操大师”的复杂操作,一套合理宏是非常必要的,这也是本贴的重点。
这个天赋的操作要点是通过近战的智慧圣印+格挡回蓝获得足够多的法力,然后通过神佑打击保持神圣震击的6秒CD,尽可能多地使用瞬发治疗,从而不间断近战攻击。
这些思路来自于上一个帖子《奶骑微操大师这个天赋该怎么用?》http://tieba.baidu.com/p/9386854208


IP属地:山东1楼2025-03-13 09:47回复
    【1、奶防骑练级的加点思路】
    奶防骑的天赋有两种类型:
    防御型:30/21/0,这种偏防御型,在拥有了奶骑基本治疗能力的同时,具有较高的生存能力。
    治疗型:37/14/0,这种侧重于治疗,拥有了奶骑的完全治疗能力,并具有一定的生存能力。
    .
    天赋加点顺序:
    10~16级:先向神圣系投入7点,把第二层的[精神集中]点出来。这个天赋可以确保你在被多个怪物围攻的情况下,把圣光术读出来。在20级之前建议使用双手武器和力量祝福以增加DPS。在点出[精神集中]天赋后,不再需要专注光环,后续以惩罚光环为主。
    17~30级:向防护系投入14点,把第三层的[庇护祝福]和[盾牌专精]点出来。在此阶段武器应过渡到单手+盾牌,并开始使用庇护祝福。
    31~53级:向神圣系投入23点,完成[神佑打击]天赋,以便得到6秒CD的神圣震击。在40级后习得光明祝福后,可按需切换庇护或光明祝福。
    接下来的天赋会出现分支:
    如果选择“防御型”,剩余7点天赋应投入到防护系,直至满级时点出第五层的[神圣之盾],大幅提升生存能力,并拥有更多的反伤能力。
    如果选择“治疗型”,剩余7点天赋将继续投入到神圣系,依次是:1点终极天赋[晨辉]、1点[神恩术]补完神圣震击的暴击量、2点[启发]补完暴击回蓝效果,最后3点可以是[神圣强化],也可以继续投入到防护系增加生存能力。
    .
    值得注意的是,神圣系并不需要[强化专注光环],因为大部分治疗都是瞬发的神圣震击,偶尔读条圣光术也有[神圣制裁]BUFF将圣光术缩短到1.5秒。如果真的不得以要顶着群怪读2.5秒的圣光术,不如直接无敌加血更靠谱。


    IP属地:山东2楼2025-03-13 09:49
    回复
      有了战斗思路,那么如何才能将这些复杂的操作用一键宏来实现呢?
      在开始写代码之前,肯定要先设计流程图,当我们大致了解了战斗思路后,就可以继续下文的一键宏编写了。


      IP属地:山东3楼2025-03-13 09:51
      回复
        【2、一键战斗治疗宏的详解】
        在使用这些宏之前,你需要确保安装了“SuperMacro”插件(中文名是“超级宏”)。
        另外,ClassicMacros、Roid Macros和IsBuffActive这三款不是必需的,本文也没有用到。
        在开始之前,我们先简单回顾一下SuperMacro超级宏的使用方法。当你点击小地图旁边的超级宏按钮或是使用/macro命令后,会发现宏编写界面与WOW传统的宏不再一样,而是被分为左右两部分。左边的仍然兼容原版WOW的256字的宏命令,而右边则是多出来一块“扩展LUA代码”,并允许你编写长达7000字的脚本代码。虽然它还有更高级的用法,但这些就足够我们用的了。


        IP属地:山东4楼2025-03-13 09:57
        收起回复
          【首先】,我们创建一个新的宏,并在超级宏的左侧,输入以下内容:
          /script ReadyAttack()
          /script SmartTaunt()
          /script GetHurtPlayer()
          /script SmartHeal()
          /script SmartAttack()
          --------------------------------
          以上宏包含了5条函数的调用,它们的含义为:
          1.准备攻击
          2.智能嘲讽
          3.查找受伤的队友
          4.智能治疗
          5.智能攻击
          .
          【然后】,我们在超级宏的右侧框中,输入LUA代码,该代码可在下方网盘下载“一键治疗宏【输入到右侧的扩展LUA代码中】.txt”。
          这里的代码是对上述5个函数的方法实现,请从网盘的txt文件复制,别直接复制以下几楼回帖的代码,因为帖子为了排版美观使用了全角空格作为缩进符,并且包含了大量注释可能会影响使用。
          网盘下载代码 https://pan.baidu.com/s/1AjFtX5Ggpdf6PQ8TAYKY2g?pwd=twow
          .
          下面将分5个楼层来分别详解这5个函数。


          IP属地:山东5楼2025-03-13 10:01
          回复
            --以下是【准备攻击】函数的解释
            function ReadyAttack()
             --如果坦克不是玩家自己,那么协助坦克,也就是选中坦克当前的目标。
             --注:Tank是个全局变量,该变量的赋值,将在下文的“设置坦克宏”中详解。
             if Tank~="player" then
              AssistUnit(Tank)
             --否则的话,如果没有选中活着的敌对目标,那么就选中离你最近的敌对目标。
             elseif not UnitExists("target") or UnitIsDead("target") or UnitIsFriend("player","target") then
              TargetNearestEnemy()
             end
             --如果没在攻击,就开始攻击。
             if not PlayerFrame.inCombat then
              cast("攻击")
             end
             --如果既没有智慧圣印也没有光明圣印,则施放智慧圣印。
             --注:有时为了避免与其他骑士的智慧审判冲突,可能需要挂光明圣印。
             if not buffed("智慧圣印") and not buffed("光明圣印") then
              cast("智慧圣印")
             end
            end


            IP属地:山东6楼2025-03-13 10:03
            回复
              --以下是【智能嘲讽】函数的解释
              function SmartTaunt()
               --如果玩家是坦克,将会进一步判断是否需要嘲讽;如果玩家不是坦克,本函数将不会有任何效果。
               if Tank=="player" then
                local ttName=GetUnitName("targettarget")
                --如果目标的目标不为空,且不是玩家自己,那么就嘲讽。
                if ttName~=nil and ttName~=GetUnitName("player") then
                 cast("清算之手")
                end
               end
              end


              IP属地:山东7楼2025-03-13 10:03
              回复
                --以下是【查找受伤队友】函数的解释
                function GetHurtPlayer()
                 --i,p,h这些是局部变量,仅在本函数中有效。
                 local i,p,h
                 --hp是全局变量,它记录着小队中受伤最严重玩家的生命百分比。例如:1表示满血,0.5表示半血,0表示死亡。我们假定该玩家是满血的,因此初始赋值为1。
                 hp=1
                 --hurtP是全局变量,它记录着小队中受伤最严重玩家的标识,例如:party1表示队友1,partypet1表示队友1的宠物,player表示玩家自己。我们假定该玩家是自己,因此初始赋值为player。
                 hurtP="player"
                 --对9个单位进行遍历检查,0表示玩家自己,1~4表示4个队友,5~8表示潜在的队友宠物。如果不在乎队友宠物的死活,可以修改移除5~8这一部分。
                 for i=0,8 do
                  p="party"..i
                  if i==0 then p="player";end;
                  if i==5 then p="partypet1";end;
                  if i==6 then p="partypet2";end;
                  if i==7 then p="partypet3";end;
                  if i==8 then p="partypet4";end;
                  --如果这个遍历的迭代,在玩家的视野范围内,且它还没有死亡……
                  if UnitIsVisible(p) and not UnitIsDead(p) then
                   --计算该迭代的生命百分比
                   h=UnitHealth(p)/UnitHealthMax(p)
                   --如果该迭代的生命百分比小于受伤最严重的生命百分比
                   if hp>h then
                    --那么该迭代的生命百分比将成为受伤最严重的生命百分比
                    hp=h
                    --同时该迭代也将成为受伤最严重的小队成员
                    hurtP=p
                   end
                  end
                 end
                end


                IP属地:山东8楼2025-03-13 10:04
                回复
                  --以下是【智能治疗】函数的解释
                  function SmartHeal()
                   --如果小队中受伤最严重的玩家生命百分比高于75%,那么无需治疗,本函数直接退出。
                   --注:hp是全局变量,它的值来自于上一个函数“查找受伤玩家”。
                   if hp>0.75 then
                    return
                   end
                   --计算玩家当前的法力百分比。
                   mp=UnitMana("player")/UnitManaMax("player")
                   --如果神圣震击已就绪,那么对受伤最严重的小队成员施放震击。
                   if SpellReady("神圣震击") then
                    --HealInCombat(单位标识, 技能名称)是一个自定义的函数,它在尽可能不打断攻击的情况下为指定单位治疗,下文有详解。
                    --注:hurtP是全局变量,它的值来自于上一个函数“查找受伤玩家”函数。
                    HealInCombat(hurtP,"神圣震击")
                   else
                    --如果十字军打击已就绪,就用十字军打击。注:走到这里说明有人需要治疗,但是神圣震击尚未冷却,因此这里打一个十字军,让神圣震击立即冷却完毕。
                    if SpellReady("十字军打击") then
                     cast("十字军打击")
                    end
                    --假如上面的十字军打出来了,就没下面什么事了;但若十字军也没冷却,脚本还将继续……
                    --如果受伤单位生命低于10%,且玩家法力低于30%,且圣疗术已就绪,且受伤单位是坦克或自己,那么使用圣疗术。
                    --注:这个条件有点多,首先10%表示该单位生命濒危,这是使用圣疗的前提。
                    --30%表示奶骑自己的蓝也不多了,使用圣疗会付出清空法力的代价,所以只有在法力本来就不多的情况下,才值用圣疗。
                    --这个单位必须是坦克或者玩家自己,才值得付出圣疗,其他人不配。
                    if hp<0.1 and mp<0.3 and SpellReady("圣疗术") and (hurtP==Tank or hurtP="player")then
                     HealInCombat(hurtP,"圣疗术")
                    --如果受伤单位生命低于35%,此时震击和十字军都未冷却,现在最好的办法就是直接读一个大圣光抬血。
                    elseif hp<0.35 then
                     HealInCombat(hurtP,"圣光术")
                    --如果受伤单位生命低于60%,需要治疗,但又不是很急迫,就用一个小圣光或圣闪来填充。
                    elseif hp<0.6 then
                     --神圣制裁BUFF是奶骑第二层的天赋,审判后可减少1秒圣光读条,如果有这个BUFF,此时圣光和圣闪都是1.5秒读条,所以优选圣光治疗量会更高一些,但不应使用最高等级的圣光术,这很可能会过量。
                     if buffed("神圣制裁") then
                      HealInCombat(hurtP,"圣光术(等级 6)")
                     else
                      HealInCombat(hurtP,"圣光闪现")
                     end
                    end
                    --在神圣震击和十字军都未冷却的情况下,这里实际上还有60%~75%生命区间没有处理,因为这个区间并不危险,再等一两个GCD,如果仍未低于60%,那么就能等到十字军和神圣震击了;如果该单位生命持续下降,将可能会触发圣光抬血。
                   end
                  end
                  --以下是【战斗中治疗】函数的解释
                  function HealInCombat(pp,healingSpell)
                   --如果玩家处于攻击状态
                   if PlayerFrame.inCombat then
                    --施放指定的治疗法术
                    cast(healingSpell)
                    --由于攻击状态的玩家,此时目标是敌人,治疗法术一定会处于鼠标指针待指定的状态,即SpellIsTargeting。
                    if SpellIsTargeting() then
                     --此时将法术施放到指定的单位身上,这里的单位是传参过来的受伤最严重的单位
                     SpellTargetUnit(pp)
                    end
                   else
                    --如果不在战斗状态,则是先将目标切换到受伤单位,施放治疗法术后,再切换回上一个目标。
                    TargetUnit(pp)
                    cast(healingSpell)
                    TargetLastTarget()
                   end
                  end


                  IP属地:山东9楼2025-03-13 10:06
                  回复
                    --以下是【智能攻击】函数的解释
                    function SmartAttack()
                     --优先使用神打或十字军打击,这两个技能共CD,所以只需要判断其中一个的冷却即可。
                     if SpellReady("神圣打击") then
                      --在打击技能就绪的情况下,如果震击也就绪了,就使用神打提供一次近战群疗,否则使用十字军以便重置震击。
                      --你也许注意到了,在前文智能治疗函数中,已经判断过一次震击是否冷却、是否需要十字军打击来重置CD。这两个功能虽然相同,但却都是必需的。在智能治疗函数中大十字军的目的是:如果不在治疗压力太大的情况下尽快打出十字军重置震击,那么可能会一直用小圣光或圣闪填充,读条会导致无法攻击回蓝。而此处打十字军的目的是:趁着现在输出阶段毫无治疗压力,尽早把震击CD重置了,等到待会需要治疗的时候就立即有震击可用了。
                      if SpellReady("神圣震击") then
                       cast("神圣打击")
                      else
                       cast("十字军打击")
                      end
                     --如果目标血量低于斩杀线,则考虑使用愤怒之锤。
                     elseif SpellReady("愤怒之锤") and UnitHealth("target")/UnitHealthMax("target")<0.2 then
                      cast("愤怒之锤")
                     --如果审判就绪,且目标生命值高于4000血,则考虑使用审判。
                     --剩余血量太低的目标是没有审判价值的,毕竟审判后还要重新挂圣印,需要消耗两个GCD。你也不想刚审判完它就被人秒杀了,白白浪费两个GCD吧。4000血量可以根据等级情况按需调整。
                     elseif SpellReady("审判") and UnitHealth("target")>4000 then
                      --这里需要考虑玩家不一定挂的是智慧圣印,有时也会有光明圣印的需求。
                      if buffed("智慧圣印") and not buffed("智慧审判","target") then
                       cast("审判")
                      elseif buffed("光明圣印") and not buffed("光明审判","target") then
                       cast("审判")
                      end
                     end
                    end


                    IP属地:山东10楼2025-03-13 10:06
                    回复
                      另外,奉献和神圣之盾并没有加入一键治疗宏中,而是需要单独做一个宏绑到另一个按键。因为这两个技能的使用场景需要综合多种因素考虑,比如:
                      - 组队作为治疗时,是不需要奉献和神圣之盾的,但在没有治疗压力的情况下,可以考虑在CD空闲期间插入一些奉献加速杀怪。
                      - 在单人打怪时,如果拉了两个以上的怪,则建议使用奉献和神圣之盾。
                      - 组队作为坦克时,也需要频繁地使用这俩技能。
                      .
                      以下是这两个技能合并在一个宏里的参考。
                      /script if SpellReady("奉献") then cast("奉献");else cast("神圣之盾");end


                      IP属地:山东11楼2025-03-13 10:09
                      回复
                        还记得前文提到的全局变量“Tank”吗?这个值将通过下面的宏进行赋值。
                        使用方法是,选择一个小队成员,然后按这个宏即可将其设置为坦克。
                        这个小队成员可以是自己,也可以是队友的宠物,有时会需要猎人的宠物当坦。
                        每当小队成员有人加入或退出时,最好重新点一次这个宏,成员的变化可能会导致单位标识也跟着变化,比如party1退队了,那么原本的party2就变成了party1,以此类推。
                        .
                        该宏的编写方法是,在超级宏的左侧,输入以下宏指令:
                        /script SetTank()
                        /script SendChatMessage(Tank,"party") --这一句的作用是将Tank值打印出来,使你确认Tank的值是否符合你的预期,一般情况下这一句可以删掉。
                        在超级宏的右侧,输入以下LUA代码:
                        function SetTank()
                         --假定坦克是玩家自己
                         Tank="player"
                        local i,p
                         --对5个玩家和4个宠物进行遍历……
                         for i=1,8 do
                          p="party"..i
                          if i==5 then p="partypet1";end;
                          if i==6 then p="partypet2";end;
                          if i==7 then p="partypet3";end;
                          if i==8 then p="partypet4";end;
                        --如果某成员的名称与玩家目标一致,那么该单位的标识将赋值到Tank变量中。
                          if GetUnitName(p)==GetUnitName("target") then
                           Tank=p
                           break
                          end
                         end
                        --如果坦克是玩家自己,那么使用正义之怒。如果是单人玩,开不开正义之怒其实无所谓。但如果组队了,除非有人明确站出来当坦,否则玩家尽可能的承担坦的角色。毕竟奶防骑的一部分输出是靠挨揍反伤的,比如庇护祝福、惩罚光环、神圣之盾。此外,成功的格挡还能恢复2%的法力。
                         if Tank=="player" then
                          cast("正义之怒")
                         else
                          --这个函数可以取消正义之怒BUFF
                          CancelRighteousFury()
                         end
                        end
                        --以下是【取消正义之怒】函数的解释。虽然网上有/cancelaura、/buffremove类似的宏,但在乌龟服里这些都不管用,也许是我缺少某种插件导致的。无论如何,下面这个函数可以解决这个问题,相信类似这种取消BUFF插件的低层代码大概也是这么实现的。
                        function CancelRighteousFury()
                         --遍历玩家身上的16个BUFF,如果BUFF过多,可以考虑增大该数值
                         for i=0,16 do
                          --获取当前迭代的BUFF名称
                          buffName=GetPlayerBuffTexture(i)
                          if (buffName==nil) then
                           break
                          end
                          --如果BUFF名是SealOfFury(正义之怒),则取消这个位置的BUFF
                          if (string.find(buffName,"SealOfFury")~=nil) then
                           --注意CancelPlayerBuff()这个函数中的位置,与玩家身上BUFF的实际位置没有必然关系,这个位置没法直接获得,只能通过遍历+对比的方式得知。
                           CancelPlayerBuff(i)
                           break
                          end
                         end
                        end


                        IP属地:山东12楼2025-03-13 10:12
                        回复
                          6 顶一个


                          IP属地:北京来自Android客户端13楼2025-03-13 10:15
                          回复
                            666


                            IP属地:湖北来自iPhone客户端14楼2025-03-13 10:42
                            回复
                              有段时间,我觉得玩宏比玩职业本身有意思多了


                              IP属地:浙江来自Android客户端15楼2025-03-13 10:42
                              收起回复