• QQ21031394

    工作时间

    周一至周五:9:30-18:30

    周末及节日:根据情况调休

  • 手机版二维码

    随时手机查素材

  • 扫描二维码

    加入官方QQ群

站长推荐
怪诞生 二级会员
  • 未知地域
  • 227发帖数
  • 23主题数
  • 1关注数
  • 9粉丝

[演示和教程] AI脚本初级教程

[复制链接]
怪诞生 发表于 2020-3-7 18:41:17 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
提莫作坊QQ群:提莫作坊www.tbwlm.cn

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
什么是jass AI?】jass AI是用纯jass编写的AI程序,可以用新建文本文档写或jass工具编写.真三AI以及DOTA AI也是由AI脚本编写.
AI脚本使用方法】:
①运行地图编辑器
②打开你最爱的对战地图,将它以另外一个名字保存(最好放在另外一个文件夹里面)
③按F12(或者点Modules(模块)菜单,然后选择Import manager(输入管理器))
④在Import manager(输入管理器)中选择File ->Import file (文件 -> 输入文件)
⑤选择刚刚建立好的**.ai.文件
⑥鼠标右击已经导入的文件,选择Modify file properties(修改文件属性)
⑦将文件的后缀名改为.ai

✄۞◥▤▧▨▥▩▥▤▨▧▦▤▧▨▥▩▥▤▨▧▦▤▧▨▥▩▥▤▨▧▦▤▧▨▥▩▥▤▨▧▦▤▧▨▥▩▥▤▨✄۞

代码放置】:在文本文档中AI程序代码应如下放置
j/
globals
    // 这个放全局变量
endglobals
function blabla takes blabla returns blabla
    // 自定义函数
endfunction
function main takes nothing returns nothing
    //主程序在这
Endfunction/j
游客,本付费内容需要支付 100枚蓝钻 才能浏览支付


1.导航2.基础对战AI入门
3. RPG AI4.防守AI
5.AI函数全解释6.rpg函数集合

点评

搬运过来楼层直达的超链接都不做一下。电梯我帮你做好了。  发表于 2020-3-7 22:51
你的楼层导航链接呢。搬运也搬运好点啊- -。  发表于 2020-3-7 18:50
楼主热帖
免责条款:本站仅提供学习的平台,所有资料均来自于网络,版权归原创者所有!本站不提供任何保证,并不承担任何法律责任,如果对您的版权或者利益造成损害,请提供相应的资质证明,我们将于3个工作日内予以删除。

本网站所收集的部分公开资料来源于互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。本站部分作品是由网友自主投稿和发布、编辑整理上传,对此类作品本站仅提供交流平台,不为其版权负责。如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时修改或删除。

本网站所提供的信息,只供参考之用。本网站不保证信息的准确性、有效性、及时性和完整性。本网站及其雇员一概毋须以任何方式就任何信息传递或传送的失误、不准确或错误,对用户或任何其他人士负任何直接或间接责任。在法律允许的范围内,本网站在此声明,不承担用户或任何人士就使用或未能使用本网站所提供的信息或任何链接所引致的任何直接、间接、附带、从属、特殊、惩罚性或惩戒性的损害赔偿。

精彩评论15

 楼主| 怪诞生 发表于 2020-3-7 18:42:17 | 显示全部楼层
本帖最后由 怪诞生 于 2020-3-7 20:07 编辑

✪【2.基础对战AI入门】✪2.基础对战AI入门我们先来学习一下我做的最简单对战AI,毕竟是最基础的,新建文本文档,
在空白处我们可以先写
接下来我们先学会写main

j/function main takes nothing returns nothing  
    call InitAI()  //开始AI
    call CreateCaptains()  //创建攻击组
    call Sleep(0.1) //停止0.1秒
    call StartThread(function WorkerAssignment)  //开始线程function WorkerAssignment
    call StartThread(function AttackAssignment)  //开始线程function AttackAssignment
    call PlayGame()  //开始游戏
endfunction  /j
main程序是最重要的了,所有的函数都从这里开始.
call InitAI()作用是初始化并且使你的战役地图里具有AI功能
call Sleep(0.1)是停止0.1秒 具体用法:带入实数,AI作用器停止X秒
call StartThread(function WorkerAssignment)是开始线程function WorkerAssignment
具体用法:带入function {实际上线程是一个函数不断判断里面的条件是否成立,然后执行相应
的动作,线程中有if语句来判断。玩家最多创建5个线程。}
这两个线程在我设计的。
线程function WorkerAssignment表示农民的建造
线程function AttackAssignment表示单位攻击的线程
call PlayGame()开始游戏,使用这个可以结束main,使AI玩家开始发展
在mian程序中我们也可以加入以下函数,如果不设置的话表示默认flase

j/function main takes nothing returns nothing
    call SetCampaignAI(  ) //战役AI初始化
    call SetDefendPlayer( ture ) //保护用户
    call SetRandomPaths(  ture )  //随机路线
    call SetTargetHeroes(  ture ) //优先攻击英雄
    call SetPeonsRepair(  ture )  //自动修理建筑
    call SetHeroesFlee(  ture )   //英雄逃跑
    call SetHeroesBuyItems(  ture )//英雄买物品
    call SetUnitsFlee(  ture ) //单位逃跑
    call SetGroupsFlee( ture )//单位组逃跑
    call SetWatchMegaTargets( true )//没有怜悯
    call SetIgnoreInjured( true )//忽视伤害
    call SetHeroesTakeItems( false )//捡物品
    call SetSlowChopping( false )//慢速采矿
    call SetCaptainChanges( false )//允许基地变换
    call SetSmartArtillery( false )//聪明炮兵
endfunctionj/j
为了方便,教程一开始的mian我没写上,需要的根据地图情况就加上。下面作具体解释
上面的函数带入ture或false,表示是否开启这个功能.
call SetDefendPlayer(  )  AI会试图保护那些遭受攻击的盟友用户玩家
call SetRandomPaths( )   增加AI选择目的地的随机性
call SetTargetHeroes(  ) AI在战斗中设置较高的优先权攻击英雄
call SetPeonsRepair(  )  农民会自动修理需要修理的建筑
call SetHeroesFlee(  )  英雄在受伤严重或遭受攻击时会试图逃跑
call SetHeroesBuyItems( ) 英雄会在商店里购买有用的物品(一般是补血的)
call SetUnitsFlee( ) 非英雄单位在受伤严重或遭受攻击时会试图逃跑.
call SetGroupsFlee(  ) 在对己方不利的情况下,队伍会放弃战斗从战场逃离
call SetWatchMegaTargets(  ) AI会抓住敌人较弱或处于劣势的时候进攻
call SetIgnoreInjured( ) 在集结部队进攻时,忽略生命值低于50%的单位
call SetHeroesTakeItems(  ) 英雄在路上拾取物品
call SetSlowChopping( ) AI的黄金采集数量一次只有1
call SetSmartArtillery(  ) 攻城单位会尽可能的攻击敌人基地
写完了main了,我们就要写在main中创建的线程了
我们先看线程function WorkerAssignment(农民采矿、建造、生产线程)

j/function WorkerAssignment takes nothing returns nothing  
    loop  //开始进入循环
       ……
       call Sleep( 2 )  //停止2秒
    endloop  
endfunction /j
以上就是线程的基本面貌,以上线程实际上是每两秒就做线程内动作.
call Sleep(  )中带入实数设置循环秒数,是必不可少的,少了就会使魔兽出错!
因为这是在不断地执行语句.接下来我们来实现农民的工作分配
首先来认识一下几个函数

j/
//清空资源单位任务分配
native ClearHarvestAI       takes nothing                               returns nothing
//获得AI玩家的已完成的该类型单位个数
native GetUnitCountDone     takes integer unitid                        returns integer
//设置(增加)采集金矿单位<地点,人数>,HarvestGold(0,1),0表示在主基地
native HarvestGold          takes integer town, integer peons           returns nothing
//设置(增加)采集树木单位<地点,人数>,HarvestWood(0,1),0表示在主基地
native HarvestWood          takes integer town, integer peons           returns nothing
/j
还有其他得到的单位数量的函数对比
j/
//获得AI玩家的该类型单位个数,包括建造中单位
native GetUnitCount         takes integer unitid                        returns integer
//获得某玩家的该类型单位个数
native GetPlayerUnitTypeCount takes player p, integer unitid            returns integer
//获得AI玩家的已完成的该类型单位个数
native GetUnitCountDone     takes integer unitid                        returns integer
//获得AI玩家该类型单位在指定基地的个数(dn指是否只获取已完成的单位)
native GetTownUnitCount     takes integer id, integer tn, boolean dn    returns intege
/j
认识完上面的函数,那么些农民的工作分配就很简单了,下面关键靠理解
j/ j/function WorkerAssignment takes nothing returns nothing
       local integer wg  //设置整数wg,记录采矿农民数量
       local integer ww  //设置整数ww,记录伐木农民数量
       loop      //开始永恒循环
       call ClearHarvestAI()  //清空资源单位任务分配
       set wg=GetUnitCountDone('nmpe')  //设置wg为总的农民的数量
       if (wg<6) then  //如果农民的数量小于6
           if(wg<2) then  //如果农民的数量小于2
                call HarvestGold(0,wg)   //告诉电脑用wg个农民采集金矿           
           else        //如果农民的数量大于2
              call HarvestGold(0,wg-1)  
              call HarvestWood(0,1)    //留一个人伐木,其余全部分去采矿
           endif  
       else   //如果农民的数量大于6
           set ww=wg-5  //设置伐木弄明是总农民数量-5
           set wg=5  //设置采矿农民数量为5
           call HarvestGold(0,wg)  
           call HarvestWood(0,ww)  //实际上是5人采矿,其余全部伐木
       endif
       call Sleep( 2 )  
       endloop  
endfunction /j
农民分配好了,那我们就开始建造吧!
j/
native SetBuildUnit takes integer qty, integer unitid returns nothing
//指令AI玩家制造(所有类型的建造,包括升级)qty - 数量unitid - 单位类型
//比如call SetBuildUnit(1,'nnfm')建造一个珊瑚礁,nnfm是珊瑚礁的代码
/j
掌握了以上函数就可以写了:
GetPlayerState得到玩家属性
PLAYER_STATE_RESOURCE_FOOD_CAP玩家食物总数
PLAYER_STATE_RESOURCE_FOOD_USED玩家使用了的食物总数
PLAYER_STATE_FOOD_CAP_CEILING玩家最大食物上限
学好基础知识很重要!

j/        call InitBuildArray()  //初始化建造
        if (GetPlayerState(ai_player, PLAYER_STATE_RESOURCE_FOOD_CAP)>=GetPlayerState(ai_player, PLAYER_STATE_FOOD_CAP_CEILING)) then  
           //如果玩家的人口大于最大人口
        else  //如果玩家的人口小于最大人口
            if ((GetPlayerState(ai_player, PLAYER_STATE_RESOURCE_FOOD_CAP)-GetPlayerState(ai_player, PLAYER_STATE_RESOURCE_FOOD_USED))<5) then  
                call SetBuildUnit(GetUnitCount('nnfm')+1,'nnfm')   //食物紧张,建造珊瑚礁
            endif  
        endif  
        if (GetUnitCount('nmpe')<10) then   //如果农民数量少于10
            call SetBuildUnit(10,'nmpe')  //建造10个农民
        endif  
        if (GetUnitCount('nnsg')<3) then  //如果产卵地数量小于3      
        call SetBuildUnit(GetUnitCount('nnsg')+1,'nnsg')  //建造3个 产卵地
        endif  
        if ((GetUnitCountDone('nnsg')>0) and (GetPlayerState(ai_player, PLAYER_STATE_RESOURCE_FOOD_USED)<=GetPlayerState(ai_player, PLAYER_STATE_FOOD_CAP_CEILING)-3)) then  
           call SetBuildUnit(30,'nsnp')  //爆毒龙
/j
以上的代码要插入原来的线程.
接下来我们来写下线程function AttackAssignment(单位攻击的线程)
先来认识下攻击用到的函数

j/
//初始化进攻组
function InitAssaultGroup takes nothing returns nothing
//增加单位记录进攻击组
function SetAssaultGroup takes integer qty, integer max, integer unitid returns nothing
//qty是单位数量,max是单位等级,unitid是单位ID
native GetEnemyExpansion    takes nothing                               returns unit
//获取敌人扩张点(分基地)
native StartGetEnemyBase    takes nothing                               returns nothing
//开始寻找敌人基地
native WaitGetEnemyBase     takes nothing                               returns boolean
//是否正在寻找敌人基地
进攻组的指令
function InitAssaultGroup takes nothing returns nothing
//进攻组的指令,初始化进攻组
/j
接下来看看应用:
j/function AttackAssignment takes nothing returns nothing  
    local unit target  
    call StaggerSleep( 0, 2 )  //睡眠功能
    loop  
       if (GetUnitCountDone('nsnp')>=3) then  //毒龙的数量大于或等于3
      call InitAssaultGroup()  //进攻组的指令,初始化进攻组
     call SetAssaultGroup(GetUnitCountDone('nsnp'),GetUnitCountDone('nsnp'), 'nsnp' )  //增加毒龙进攻击组
     set target = GetEnemyExpansion()  //设置target是敌人的分基地
       if (target == null) then  //如果敌人没有分基地  
        call StartGetEnemyBase( )  ////开始寻找敌人主基地
        loop  
               exitwhen (not WaitGetEnemyBase())  //直到找到敌人主基地
               call SuicideSleep(1)  //睡眠功能
        endloop  
       call Sleep( 1.0 )  //休眠一秒
    endloop  
endfunction  
/j
函数扩展:以下函数也可以运用到其中
j/
//增加单位进攻击组
native AddAssault           takes integer qty, integer id               returns boolean
//增加单位进防守组
native AddDefenders         takes integer qty, integer id               returns boolean
//获取中立敌对营地<最小总等级,最大总等级,是否包括飞行单位>
native GetCreepCamp         takes integer min, integer max, boolean flyers_ok returns unit
//开始寻找敌人基地
native StartGetEnemyBase    takes nothing                               returns nothing
//是否正在寻找敌人基地
native WaitGetEnemyBase     takes nothing                               returns boolean
//获取敌人基地
native GetEnemyBase         takes nothing                               returns unit
//获取下一个扩张点有威胁的单位
native GetExpansionFoe      takes nothing                               returns unit
//获取敌人扩张点(分基地)
native GetEnemyExpansion    takes nothing                               returns unit
//获取可能的扩张点X坐标
native GetExpansionX        takes nothing                               returns integer
//获取可能的扩张点X坐标
native GetExpansionY        takes nothing                               returns integer
/j
这样子就可以完成寻找敌人基地了,下面我们出发攻击吧!
j/
//集结队伍,一定要使用,否则无法进行下一步攻击
function FormGroup takes integer seconds, boolean testReady returns nothing
//攻击组攻击单位,带 入 单 位 ,攻 击 移 动 直 到 杀 死 此 单 位 。
native AttackMoveKill       takes unit target                           returns nothing
//等待直至攻击组抵达目的地
function SleepUntilAtGoal takes nothing returns nothing
//等待直至攻击组结束战斗
function SleepInCombat takes nothing returns nothing
/j
应用于实例了:
j/
if (target != null) then  
        call FormGroup( 5, false)  //集结队伍,5是时间秒数,false指英雄是否准备好
        call AttackMoveKill(target)  //攻击组攻击单位,直到target被杀死
        call SleepUntilAtGoal()  //等待直至攻击组抵达目的地
        call SleepInCombat()  //等待直至攻击组结束战斗
    else  
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,1,"|cffff0000找不到敌人,放弃进攻...|r")  
    endif  
       endif  
/j
这样就完成了进攻,大功告成了,函数扩展下吧!
j/
//攻击组攻击单位
native AttackMoveKill       takes unit target                           returns nothing
//攻击组攻击地点
native AttackMoveXY         takes integer x, integer y                  returns nothing
//在<X坐标,Y坐标>空投单位
/j
看到这里,你已经会怎么让农民工作,生产和建造,以及部队怎样寻找敌人等等!
接下来我建议你学习下一步,去五楼看看所有AI函数的解释(已包含全)

 楼主| 怪诞生 发表于 2020-3-7 18:45:10 | 显示全部楼层
3.  RPG AI
RPG AI(例如真三AI等)

file:///G:/%E9%AD%94%E5%85%BD%E5%88%B6%E5%9B%BE2/wow8%E7%BD%91%E9%A1%B5%E6%96%87%E4%BB%B6&%E5%90%84%E7%A7%8D%E4%B8%8B%E8%BD%BD%E8%B5%84%E6%96%99&%E6%95%B4%E7%90%86%E8%80%85%E9%99%84%E5%8A%A0%E8%A1%A5%E5%85%85/AI%E7%9B%B8%E5%85%B3/_%EF%BC%89%E2%9E%B9AI%E8%84%9A%E6%9C%AC%E5%88%9D%E7%BA%A7%E6%95%99%E7%A8%8B%E2%96%85%E2%96%81%E2%96%81%E2%96%81BY%E2%96%81%E2%96%81%E2%96%81weituotian%E3%80%90%E6%9B%B4%E6%96%B0ing%E3%80%91%20-%20%E7%B3%BB%E7%BB%9F%20_%20%E5%92%B8%E9%B1%BC%E7%AA%9D/_%EF%BC%89%E2%9E%B9AI%E8%84%9A%E6%9C%AC%E5%88%9D%E7%BA%A7%E6%95%99%E7%A8%8B%E2%96%85%E2%96%81%E2%96%81%E2%96%81BY%E2%96%81%E2%96%81%E2%96%81weituotian%E3%80%90%E6%9B%B4%E6%96%B0ing%E3%80%91%20-%20%E7%B3%BB%E7%BB%9F%20_%20%E5%92%B8%E9%B1%BC%E7%AA%9D_files/10070616044833145a710df7e5.png
测试图可以做到以下功能,还不完善!
RPG AI的英雄应该做到
1.英雄会去攻击敌人
2.红血时会回家
3.会购买物品,会捡物品(英雄自动到商店购买)
4.会学习技能
高级:
5.会补刀,进攻和撤退
6.会使用技能
7.会卡兵
8.会使用物品
接下来我们先开始制作初级的英雄的AI(像真三那样只控制一个英雄,不是lost temple 3c是控制多个英雄的)
j/globals  
    unit  aihero                //记录玩家的英雄
    ai_player                   //记录AI玩家
    boolean flee=false          //设置是否逃跑,一开始false表示不在,如果ture表示在
    boolean attack_enemy=false  //设置攻击状态,一开始false表示不在攻击,如果ture表示在攻击
    boolean buyitem=false       //设置是否在购买物品,一开始false表示不在,如果ture表示在
    boolean kabing=false        //设置是否在卡兵,一开始false表示不在,如果ture表示在
    boolean useskills=false     //设置是否在使用技能,一开始false表示不在,如果ture表示在
    boolean buxue=false         //判断英雄是否在补血
    real ratio=1                //radio是用于判断生命比的整数
    integer count=0             //记录游戏开始秒数  
    location start_loc          //玩家开始的地方
    group udg_g                 //用于记录AI玩家所有单位
endglobals
/j
先声明以上的全局变量就OK了,下面我会创建4个线程.我开始了很多个线程!这只是我实现的一种方法罢了,
仅作参考!以上的线程可以集中为一个线程,这里为了方便说明就分开来了.

j/function main takes nothing returns nothing
    set ai_player=Player(GetAiPlayer())  //用变量记录当前的AI玩家为       ai_player                                 
    call SetMeleeAI()                           //开始对战AI  
    call SetHeroesBuyItems(true)                //设置英雄自动买物品  
    call SetHeroesFlee(true)                    //设置英雄生命值少时自动逃跑  
    call SetHeroesTakeItems(true)               //设置英雄自动捡物品  
    call SetIgnoreInjured(true)                 //在集结部队进攻时,忽略生命值低于50%的单位   
    call SetRandomPaths(true)                   //增加AI的选择目的地的随机性      
    call CreateCaptains()                       //创建攻击组  
    call ShareEverythingWithTeamAI ()             //可以和AI分享物品等
    call StartThread(function attack_loop)      // 开始线程,运行(function attack_loop)  
    call StartThread(function check_hp)         // 开始线程,运行(function check_hp)
    call StartThread(function buy_item)         // 开始线程,运行(function buy_item)
    call StartThread(function attack)           // 开始线程,运行(function attack)
endfunction
/j
刚才有的函数是不是很熟悉,就是二楼中建立对战AI可以用到的。这里我只选用了英雄部分.
call ShareEverythingWithTeamAI可以和AI分享物品等在本图中可以用到.
还有一点是我开始了很多个线程!这只是我实现的一种方法罢了,仅作参考!你们可以从中
实现第一个功能1.英雄会去攻击敌人(英雄可以在原地图中创建,下面函数是得到AI玩家的英雄

j/
function setup_force takes nothing returns nothing  //选取英雄
     local unit u=null
     call GroupEnumUnitsOfPlayer(udg_g,ai_player,null)     //选取AI玩家的所有单位
     loop
            set u=FirstOfGroup(udg_g) //设置u是单位组的第一个单位
            exitwhen u==null          //当u为没有单位时
            if IsUnitType(u,UNIT_TYPE_HERO)==true then  //如果单位u是英雄
                set aihero=u            //设置aihero就是英雄了
            endif
            call GroupRemoveUnit(udg_g,u)            //移除单位u后,单位组内就没有u这个单位了
     endloop
endfunction
/j
开始攻击了吧,以下是攻击的线程
j/
function attack_loop takes nothing returns nothing
     local integer cmd
     call WaitForSignal() // <== 等到地图发出一个命令
     set cmd = WaitForSignal() //  得到命令被承认,让AI起作用
     if cmd == 0 then
     call setup_force//调用刚才上面的函数,选取英雄
     loop //开始进入循环
        loop
            call Sleep(1)                                //停止1秒                              
            exitwhen ((not buyitem and not flee)and not useskills) and ((not kabing and radio=<0.3) and ( GetUnitCurrentOrder(aihero) == OrderId("stop"))   //当不在购买物品的时候,血少逃跑的时候和卡兵的时候,单位停止的时候退出循环
        endloop
        call IssueNeutralPointOrder( Player(0), GetTriggerUnit(), "attack", 2817.00, 2555.00 )//命令攻击到坐标2817.00, 2555.00
        call Sleep(1)
    endloop
endfunction
/j
以上的变量udg_g,ai_player已在全局变量声明部分声明了
这里用到跨脚本通讯,我们在原地图触发中使用AI-发送AI命令
其中发送的是两个数字,第一个数字是命令,第二个数字是命令数据
我规定命令数字0就是选择英雄了.
在以上函数中就能接受到触发来的命令,开始选择英雄
我们要明确英雄什么时候去攻击,购买物品的时候不能,血少,逃跑的时候不能
卡兵的时候都不能.还要判断英雄当前的命令是stop,即什么都不做!避免冲突.
radio是英雄的生命值百分比,坐标2817.00, 2555.00是地图中设置的敌人基地
如果敌人的基地是不确定的,我们可以在二楼教程中对战AI的寻找敌人的函数,还记得吗?
j/
native AddDefenders         takes integer qty, integer id               returns boolean
//获取中立敌对营地<最小总等级,最大总等级,是否包括飞行单位>
native GetCreepCamp         takes integer min, integer max, boolean flyers_ok returns unit
//开始寻找敌人基地
native StartGetEnemyBase    takes nothing                              returns nothing
//是否正在寻找敌人基地
native WaitGetEnemyBase     takes nothing                               returns boolean
//获取敌人基地
native GetEnemyBase         takes nothing                               returns unit
//获取下一个扩张点有威胁的单位
native GetExpansionFoe      takes nothing                               returns unit
//获取敌人扩张点(分基地)
native GetEnemyExpansion    takes nothing                               returns unit
//获取可能的扩张点X坐标
native GetExpansionX        takes nothing                               returns integer
//获取可能的扩张点X坐标
native GetExpansionY        takes nothing                               returns integer
/j
英雄会攻击了,没血了也要回来吧!
实现第2个功能.红血时会回家
我的思路是用一个线程去检测HP吧!此线程在main也提出过
我们会用到全局变量radio,表示英雄的生命百分比
我们知道,英雄的生命是最重要的,是攻击,购买物品,卡兵等等的前提
所以红血时,所有的一切都要被停止吧,而且要逃跑回家

j/
function check_hp takes nothing returns nothing
    local real r1=0
    local real r2=0
    loop
        call Sleep(1)                            //停止1秒
        set r1=GetUnitState(aihero,UNIT_STATE_LIFE)     //设置r1是英雄的现在生命值     
        set r2=GetUnitState(aihero,UNIT_STATE_MAX_LIFE)  //设置r2是英雄的最大生命值
        set ratio=r1/r2  
        if radio>0.3 then
            set flee=flase          //设置逃跑为flase
        else
            set flee=ture           //设置逃跑为false
            set buyitem=false       //设置购买物品为false
            set kabing=false        //设置卡兵为false   
            set attack_enemy        //设置攻击敌人为false   
            call IssuePointOrder( GetTriggerUnit(), "move", -2843.00, -3147.00 )  //命令英雄回家 ,-2843.00, -3147.00是地图中家的坐标                                    
        endif  
    endloop
endfunction
/j
英雄少血的时候就会回家了,这时不能暂停这个线程,等英雄回复血后还要出去战斗
我们还要考虑到英雄如果真的不幸死了。让英雄复活可以在地图的触发中设置.
英雄杀怪有钱赚了,我们让他去买些物品吧!
实现第3个功能.会购买物品,会捡物品(英雄自动到商店购买)
会捡物品在main中用
call SetHeroesTakeItems(true)
可以轻松实现.那么去买物品时,看看怎么判断一个英雄是否具有某样物品.
以下是简单的实现方法,实际上是判断每个物品栏是否有这个物品

j/
function isunithaveitem takes unit whichUnit integer itemId returns boolean
      local integer index=0
      loop
        set index=index+1
        if (UnitItemInSlot(whichUnit, index) != null) and (GetItemTypeId(UnitItemInSlot(whichUnit, index)) == itemId) then//判断是否有这样物品
            return ture //有就返回ture
        endif
        set index = index + 1
        exitwhen index >5
      endloop
      return false//没有就返回false
endfunction
/j
判断单位物品栏的物品数量
j/
function UnithaveitemCount takes unit whichUnit returns integer
    local integer index = 0
    local integer count = 0 //记录物品数量
    loop
        if (UnitItemInSlot(whichUnit, index) != null) then//如果第几个物品栏不为空
            set count = count + 1//记录物品数量+1
        endif
        set index = index + 1
        exitwhen index >5
    endloop
    return count
endfunction
/j
      
还要一定有足够的钱,而且血很多(死了怎么买?)而且
不在战斗,不在卡兵,不再逃跑,不在使用技能(如果在逃跑还去买东西,那就是被人杀死),在家里等等!
以下是实现买东西的线程,只是一个思路.这里只设置了购买医疗剂.
j/
function buyloop takes unit hero,unit Store,item whichitem returns nothing//监视英雄买东西
      set buyitem=ture //设置买东西为ture
      loop
         call IssueTargetOrderById( store, 852566, aihero() )   //852566是选择动作的ID ,命令中立商店选择英雄
         call IssueNeutralImmediateOrderById( ai_player, store, GetItemTypeId(whichitem)) //命令电脑玩家在中立商店购买医疗剂
         call IssuePointOrderByIdLoc( aihero, 851986, GetUnitLoc(store) )//英雄移动到中立商店
         call Sleep(1)
         exitwhen isunithaveitem( aihero,GetItemTypeId(whichitem))//英雄买到了退出循环
      endloop
      set buyitem=false//设置买东西为false
endfunction

function function buy_item takes nothing returns nothing
     loop
     if (not flee and not kabing)and (not attack_enemy and not useskills) then //如果flee为flase 和 kabing为false 和 attack_enemy为false
       if UnithaveitemCount(aihero)<6 then //如果英雄携带物品少于6
        if GetPlayerState(ai_player, PLAYER_STATE_RESOURCE_GOLD)>100 and not isunithaveitem( aihero,'hslv') then//如果玩家的金钱大于100和英雄没有医疗剂
            call buyloop(aihero,gg_unit_ngme_0003,'hslv')//调用上面监视英雄买东西的函数,参数英雄,商店,物品)
        endif
       endif
       else
          setbuyitem=false
     endif
     call sleep(5)
     endloop
endfunction
/j
你看到上面在线程中调用了某个函数也有loop,会执行完这个函数才回到线程。这是线程的优点
以上可以不断添加购买的物品,不过每一次的条件最好不同.否则会引起错乱.这样子就完成了购买物品的AI
接下来实现第4个功能.会学习技能
至于学习技能.我们完全可以在触发中设置.下面都是在触发中设置的.简略地提一下.
我们要先知道英雄的技能,所以为他们注册技能,以下技能学习只是一个方法.

j/
call RestoreHeroSkills('Hmkg','AHav','AHtb','AHbh','AHtc')
…………
/j
'Hmkg'是英雄代码,后面四个依次是技能.
接下来要用到两个gamecache的函数
j/
function SetHandleInt takes string subject,string name,integer value returns nothing
    if value==0 then
        call FlushStoredInteger(udg_GameCache,subject,name)//清除udg_GameCache中的subject,name下的整数
    else
        call StoreInteger(udg_GameCache,subject,name,value)//储存udg_GameCache中的subject,name下的整数为value
    endif
endfunction
function GetHandleInt takes string subject,string name returns integer
    return GetStoredInteger(udg_GameCache,subject,name)//得到已存储的英雄技能ID
endfunction
function RestoreHeroSkills takes integer a0,integer a1,integer a2,integer a3,integer a4 returns nothing
    call SetHandleInt("heroskills",I2S(a0)+"1",a1) //储存a1为英雄技能中的第1个
    call SetHandleInt("heroskills",I2S(a0)+"2",a2) //储存a1为英雄技能中的第2个
    call SetHandleInt("heroskills",I2S(a0)+"3",a3) //储存a1为英雄技能中的第3个
    call SetHandleInt("heroskills",I2S(a0)+"4",a4) //储存a1为英雄技能中的第4个
endfunction/j
储存完技能就让英雄学习下吧!
在地图触发中新建英雄升级事件,在使用自定义代码call AILearnSkills()
j/
function AILearnSkills takes unit u returns nothing
    local integer i=GetUnitTypeId(u)  //设置i是英雄Id
    local string  s=""                //设置字符串s是""
    set s=I2S(i) //设置s为英雄id转换过来
    call SelectHeroSkill(u,GetHandleInt("heroskills",s+"1"))//命令英雄学习第1个技能
    loop
        if GetHeroSkillPoints(u)>0 then//如果英雄还有技能点数
            call SelectHeroSkill(u,GetHandleInt("heroskills",s+"2"))//命令英雄学习第2个技能
        endif
        if GetHeroSkillPoints(u)>0 then//如果英雄还有技能点数
            call SelectHeroSkill(u,GetHandleInt("heroskills",s+"3"))//命令英雄学习第3个技能
        endif
        if GetHeroSkillPoints(u)>0 then//如果英雄还有技能点数
            call SelectHeroSkill(u,GetHandleInt("heroskills",s+"4"))//命令英雄学习第4个技能
        endif
        exitwhen GetHeroSkillPoints(u)==0//英雄没有技能点数退出
        call sleep(0.5)//停止0.5秒
    endloop
endfunction
/j
英雄学习技能在触发中完成比较好.
接下来实现第5个功能.补刀,这是比较难的部分.
我们创建一个线程来实现这个功能吧!
我们知道,如果英雄补刀可以算作一个攻击状态,那么为了不与其它线程
相冲突,我们可以设置在不买东西,不逃跑(逃跑时也判断血量少),
不卡兵,不使用技能的时候补刀吧!

j/
function attack takes unit u returns nothing
      loop
      if (not buyitem and not skills) and (not flee and not kabing) then
      //这里设置动作
      call Sleep(1)
      endloop
endfunction
/j
基本的我们实现了,那么下面给大家介绍一个补刀的函数,作点仔细的介绍.
j/
function GetWeakestUnit takes unit center,real range returns unit //得到一个单位组里最弱的单位
        local unit temp     //设置局部变量单位temp,用于记录单位组中存活的单位
        local unit weakest  //设置局部变量单位temp,用于记录单位组嫩生命值最少的单位
        local group g=CreateGroup() //建立一个单位组,用于记录全部单位
        local group group=CreateGroup()//建立一个单位组,这个单位组用于记录存活非英雄单位
        call  GroupEnumUnitsInRange(g,GetUnitX(center),GetUnitY(center),range,null)  //将英雄范围内的单位全送进单位组
        call  GroupRemoveUnit(g,center) //移除英雄自己出单位组,因为不可能自己杀自己吧
        loop //进入循环
            set  weakest=FirstOfGroup(g) //设置weakest是全部单位组内第一个单位
            exitwhen weakest==null //当weakest为没有单位时退出循环
            if GetUnitState(weakest,UNIT_STATE_LIFE)>0 and IsUnitType(weakest, UNIT_TYPE_HERO) == false then
                 GroupAddUnit(group, weakest) //如果weakest是存活非英雄单位,就进入单位组group
            endif
            call  GroupRemoveUnit(g,weakest) //移除weakest出单位组
        endloop
        loop
            set  temp=FirstOfGroup(group) //设置temp是group的第一个单位
            exitwhen temp == null //当temp为没有单位时退出
                if GetUnitState(weakest,UNIT_STATE_LIFE)>GetUnitState(temp,UNIT_STATE_LIFE) then
                    set weakest = temp//如果weakest得生命值大于temp就设置weakest为temp
                endif
            call GroupRemoveUnit(group,temp)//删除单位组移除单位temp出group
        endloop
                call DestroyGroup(g)     //删除单位组
                call DestroyGroup(group)     //删除单位组
                set temp = null          //设置temp为没有单位
                set g = null             //设置g为空单位组
        return weakest
endfunction
/j
unit center我们设置为英雄,real range可是设置在多少范围内,取实数.接下来还要写
两个函数:
function GetEnemyBingInRangeCount得到范围内敌人小兵的数量
function GetAllyBingInRangeCount得到范围内盟友小兵的数量
判断数量用于进攻和撤退.

j/
function IsAlive takes unit u returns boolean//用于判断单位是否存活
  return(GetWidgetLife(u)>.405)
endfunction
function GetEnemyBingInRangeCount takes unit Theunit,real Radius returns integer//得到范围内敌人小兵的数量
  local integer result=0
  local unit u = null
  local group g = CreateGroup()
  call  GroupEnumUnitsInRange(g,GetUnitX(Theunit),GetUnitY(Theunit),Radius,null)//选取范围内的单位进入单位组
  loop
    set u = FirstOfGroup(g) //设置u是单位组g内第一个单位
    exitwhen u == null //当u为没有单位时退出循环
    if(IsEnemyBing(u)and IsAlive(u))then
        set  result=result+1 //设置数量+1
      endif
    call GroupRemoveUnit(g, u )//移除u出单位组g
  endloop
  call DestroyGroup(g)
  set g = null
  return result
endfunction
function GetAllyBingInRangeCount takes unit Theunit,real Radius returns integer//得到范围内盟友小兵的数量
  local integer result=0
  local unit u = null
  local group g = CreateGroup()
  call  GroupEnumUnitsInRange(g,GetUnitX(Theunit),GetUnitY(Theunit),Radius,null)//选取范围内的单位进入单位组
  loop
    set u = FirstOfGroup(g)//设置u是单位组g内第一个单位
    exitwhen u == null //当u为没有单位时退出循环   
    if(IsAllyBing(u)and IsAlive(u))then
        set  result=result+1//设置数量+1
    endif
    call GroupRemoveUnit(g, u )//移除u出单位组g
  endloop
  call DestroyGroup(g)
  set g = null
  return result
endfunction
/j
看懂了以上的函数,我们就可以简单地实现进攻和撤退,补刀.
j/
function moverandom takes unit h returns nothing
      local real x = GetUnitX(h)
      local real y = GetUnitY(h)
      local rect i = Rect(x-250, y-250, x+250, y+250)
      IssuePointOrderByIdLoc( aihero, 851986, Location(GetRandomReal(GetRectMinX(i), GetRectMaxX(i)), GetRandomReal(GetRectMinY(i), GetRectMaxY(i))))
      //命令移动到矩形区域内随机点  
function attack takes nothing returns nothing
      local unit target
      loop
      if (not buyitem and not useskills) and (not flee and not kabing) then
         if GetEnemyBingInRangeCount(aihero,500)> 0 and GetAllyBingInRangeCount(aihero,500)<=0
           call IssuePointOrder( aihero, "move", -2843.00, -3147.00 )  //命令英雄回家 ,-2843.00, -3147.00是地图中家的坐标
      else
         set target=GetWeakestUnit(aihero,500)//设置target是单位组内最弱的单位
          if (target!=null) then
            set attack_enemy=ture //设置正在攻击
            call IssueTargetOrder(aihero,"attack",target)//命令英雄攻击target
            call Sleep(1)
            set attack_enemy=false//设置不在攻击了
            set target=null
          else
              call moverandom //如果target不存在,就命令他移动到随机点  
          endif
      endif
      call Sleep(1)
      endloop
endfunction
/j
终于完成了补刀线程,这是最简单的了.
6.会使用技能
有的技能电脑自己会使用,但那是魔兽本身设计的.如果有自己的技能,
我们可以判断情况,然后再用命令使英雄使用技能.真三AI.DOTA AI中
也是这样的!
为了防止英雄乱用技能,我们可以使用
j/
SetPlayerAbilityAvailable( ai_player, 'AHtc', false )//允许使用技能
SetPlayerAbilityAvailable( Player(0), 'AHtb', true )//禁止使用技能了
/j
这是一个让英雄不乱用技能的方法.就是禁用技能,以上函数是
禁止AI玩家使用风暴之锤(演示技能).优点是还可以保留CD.所以
我们还要判断技能是否在CD中再去使用.
以下是一种实现的方法,在main程序中加个函数用来记时间

j/
function main takes nothing returns nothing
      local timer t==CreateTimer()
      call  TimerStart (t,1,ture,function count)
      set t=null
endfunction
function count takes nothing returns nothing
set count=count+1
endfunction
/j
这样就可以计算脚本运行时间了,下面还要获得当前时间
j/
function Getcurrentime takes nothing returns integer
return count
endfunction
/j
有了以上的准备就可以开始做一个施放技能的函数了.
施放技能了一定不在逃跑,不卡兵等等,而且应该有英雄存在或者
魔法满了,免得浪费.那么可以在补刀时判断是否有英雄,再决定施放技能
英雄
这个是检测敌人英雄的函数,返回范围内的第一个英雄
j/
function GetEnemyHeroInRange takes takes unit Theunit,real Radius returns unit
  local integer result=0
  local unit u = null
  local group g = CreateGroup()
  call GroupEnumUnitsInRange(g,GetUnitX(Theunit),GetUnitY(Theunit),Radius,null)//选取范围内的单位进入单位组
  loop
    set u = FirstOfGroup(g)//设置u是单位组g内第一个单位
    exitwhen u == null // 如果u为没有单位就退出循环
    if((IsUnitEnemy(u,ai_player))and(IsUnitHero(u))and IsAlive(u))then//如果u是玩家的敌人,是英雄,且存活
        return Theunit //返回单位
    endif
    call GroupRemoveUnit(g, u )//移除u出单位组
  endloop
  call DestroyGroup(g)
  set g = null
  return null
endfunction
/j
那么我们接下来加入补刀部分那里
j/
function attack takes nothing returns nothing
      local unit target
      loop
      if (not buyitem and not useskills) and (not flee and not kabing) then
         if GetEnemyBingInRangeCount(aihero,500)> 0 and GetAllyBingInRangeCount(aihero,500)<=0
           call IssuePointOrder( GetTriggerUnit(), "move", -2843.00, -3147.00 )  //命令英雄回家 ,-2843.00, -3147.00是地图中家的坐标
      else
         set target=GetWeakestUnit(aihero,500)//设置target是单位组内最弱的单位
          if (target!=null) then
            set attack_enemy=ture //设置正在攻击
            call IssueTargetOrder(aihero,"attack",target)//命令英雄攻击target
            call Sleep(1)
            set attack_enemy=false//设置不在攻击了
            set target=null
          else
              call moverandom //如果target不存在,就命令他移动到随机点  
          endif
         set target=GetWeakestUnit(aihero,500)//设置target为范围内的英雄
          if GetEnemyHeroInRangeCount(aihero,500)!=0 then
              SetPlayerAbilityAvailable( Player(0), 'AHtb', true )//允许使用技能
              call IssueTargetOrderById(aihero, 852095, target )//命令使用技能风暴之锤
              SetPlayerAbilityAvailable( Player(0), 'AHtb', true )//禁止使用技能了
              set target=null
           endif
      endif
      call Sleep(1)
      endloop
endfunction
/j
以上添加后看起来很复杂,其实思路很清新,在补刀部分后面才判断英雄,当然也可以
放在其它地方,这是优先权的问题.
在英雄升级时,我们要允许技能,否则将学不到,那么在学习后就又禁止.可以在学习
技能部分添加.如:

j/
SetPlayerAbilityAvailable( Player(0), GetHandleInt("heroskills",s+"1"), true )//允许技能
call SelectHeroSkill(u,GetHandleInt("heroskills",s+"1"))//命令英雄学习技能
SetPlayerAbilityAvailable( Player(0), GetHandleInt("heroskills",s+"1"), false )//禁止技能
/j
7.卡兵
这里要运用到算法.算法我只是简单注释下.不求解了.学会用就OK了!
首先写两个函数
RangeToLoc到点的距离
RangeToUnit到单位的距离

j/
function RangeToLoc takes unit u,location Target returns real//到点的距离
  local real X=GetLocationX(Target)-GetUnitX(u)
  local real Y=GetLocationY(Target)-GetUnitY(u)
  return(SquareRoot(X*X+Y*Y))
endfunction
function RangeToUnit takes unit u,unit Target returns real//到单位的距离
  local real X=GetUnitX(Target)-GetUnitX(u)
  local real Y=GetUnitY(Target)-GetUnitY(u)
  return(SquareRoot(X*X+Y*Y))
endfunction
/j

 楼主| 怪诞生 发表于 2020-3-7 18:46:26 | 显示全部楼层
接楼上
我们要卡的是移动非英雄单位,也要写函数判断是否英雄:英雄是否正在移动
j/
function IsUnitHero takes unit u returns boolean//判断单位是否英雄,
  return((IsUnitType(u,UNIT_TYPE_HERO))and(IsUnitIllusion(u)==false))//判断单位是否英雄,是否镜像
endfunction
function IsNotHero takes unit u returns boolean//判断单位是否英雄
return(IsUnitHero(u)==false)
endfunction
function IsMoving takes unit u returns boolean//判断单位是否移动
  local integer Order=GetUnitCurrentOrder(u)
  return(Order==OrderId("move"))or(Order==OrderId("AImove"))or(Order==OrderId("blink"))or(Order==OrderId("patrol"))or(Order==OrderId("attack"))or(Order==OrderId("smart"))   
endfunction
/j
Order是命令,以上的"move","AImove"等都是移动的命令,这样一来就可以判断是否单位正在移动
卡兵最重要的是知道那个兵离基地最远,然后得到在它前面的点,在命令英雄移动过去

j/
function GetExtSoldierToBarrack takes unit Hero,点real Radius returns unit//得到单位离基地距离最长的单位
  local real R
  local real FR=0
  local unit u=null
  local unit ru=null
  local location Loc=GetUnitLoc(Hero)
  local player p=GetOwningPlayer(Hero)
  local group g=CreateGroup()
    call GroupEnumUnitsInRangeOfLoc(g,Loc,Radius,null)//选取点圆范围的所有单位
    call RemoveLocation(Loc)//清除点?
    set Loc=null
    loop
      set u = FirstOfGroup(g)
      exitwhen u == null
      if(IsMoving(u))and(IsNotHero(u))then                                  //用于判断单位是移动的非英雄单位
       set R=RangeToLoc(u,GetUnitLoc(gg_unit_hatw_0022)) //设置R为小兵到塔的距离
        if R>FR then
          set FR=R                      //设置小的FR为R,即FR现在为最大距离
          set ru=u                      //设置ru为最大距离的单位
        endif
      endif
      call GroupRemoveUnit(g,u)         //移除单位u
    endloop
    call DestroyGroup(g)
    set g=null
  return ru
endfunction
function SmartToLoc takes unit u,location loc returns nothing//命令英雄点击到点
call IssuePointOrderByIdLoc(u,851971,loc)
endfunction

function GetUnitFrontLoc takes unit Target,real Range returns location//得到单位前的点
  local real rad
    if(Target!=null)then
      set rad=Deg2Rad(GetUnitFacing(Target)) //getunitfacing是面向角度
      return(Location(Range*Cos(rad)+GetUnitX(Target),Range*Sin(rad)+GetUnitY(Target)))//location将坐标转换为点
    endif
  return null
endfunction
/j
掌握了以上函数就可以写卡兵的主函数了,首先卡兵应该是在去别人基地的路上
为了不与其它线程冲突,那么当他不买东西,不逃跑时,不使用技能时,而且不能
一直卡到别人基地,应该是遇到敌人就不应该卡了.按照这些思路,可以制作以下的
卡兵函数.
j/
function cccc takes nothing returns nothing
  local unit u=GetExtSoldierToBarrack(gg_unit_U00A_0006,600)
    call SmartToLoc(gg_unit_U00A_0006,GetUnitFrontLoc(u,190))//命令英雄点击到点
    call Sleep(0.25)                                                //卡一次停顿0.25秒
  set u=null
endfunction

//===========================================================================
function kabing takes nothing returns nothing
      local timer t==CreateTimer()
      call  timerstart(t,0.45,ture,function cccc) //每0.45卡一次兵
      loop
      if GetEnemyBingInRangeCount(aihero,300)>0 then
      call DestroyTimer(t)
      set t=null
      return //跳过剩余动作,可以跳过循环
      endif
      call Sleep(0.45)
      endloop
endfunction
/j
以上的函数就实现了英雄卡兵,那什么时候开始卡兵呢?我们可以插入第一个线程attack_loop中
j/
     loop //开始进入循环
        loop
            call Sleep(1)                                //停止1秒                              
            exitwhen ((not buyitem and not flee)and not useskills) and ((not kabing and radio=<0.3) and ( GetUnitCurrentOrder(aihero) == OrderId("stop"))   //当不在购买物品的时候,血少逃跑的时候和卡兵的时候,单位停止的时候,不使用技能时退出循环
        endloop
        call IssueNeutralPointOrder( Player(0), GetTriggerUnit(), "attack", 2817.00, 2555.00 )//命令攻击到坐标2817.00, 2555.00
        if GetAllyBingInRangeCount(aihero,500)>0 and  GetEnemyBingInRangeCount(aihero,500)<0 then
        call kabing()
        endif
        call Sleep(1)
    endloop
/j
GetAllyBingInRangeCount得到范围内盟友小兵的数量
GetEnemyBingInRangeCount得到范围内敌人小兵的数量
这个是补刀线程中用到的函数.这里也用到了.
8.会使用物品
我们以使用医疗剂为例子来实现这个功能!
我们可以把使用医疗剂归类到线程check_hp中
j/
function UnitHasBuff takes unit whichUnit, integer buffcode returns boolean
    return (GetUnitAbilityLevel(whichUnit, buffcode) > 0)
endfunction
/j
以上的这个函数可以判断单位是否有某种BUFF
实际是判断单位BUFF等级大于0就有这种BUFF.

j/
function GetItemOfTypeFromUnit takes unit whichUnit, integer itemId returns item
    local integer index = isunithaveitem(whichUnit, itemId)
    if (index == 0) then
        return null
    else
        return UnitItemInSlot(whichUnit, index - 1)
    endif
endfunction
/j
这个函数带入物品ID,返回英雄拥有某样物品
j/
function check_hp takes nothing returns nothing
    local real r1=0
    local real r2=0
    loop
        call Sleep(1)                            //停止1秒
        set r1=GetUnitState(aihero,UNIT_STATE_LIFE)     //设置r1是英雄的现在生命值     
        set r2=GetUnitState(aihero,UNIT_STATE_MAX_LIFE)  //设置r2是英雄的最大生命值
        set ratio=r1/r2  
        if radio>0.3 then
            set flee=flase          //设置逃跑为flase
        else
            if isunithaveitem( aihero,'hslv')then
               if  (UnitHasBuff(aihero, 'B000') == false) then //如果单位没有医疗剂的BUFF
                   call UnitUseItem( aihero, GetItemOfTypeFromUnit(aihero, 'BOOO') ) //命令英雄使用物品医疗剂
                   set buxue=ture
               else     
                 set buxue=ture     //设置补血为ture
                 loop
                 call sleep(1)
                 if  GetAllyBingInRangeCount(aihero,800)>0  or GetEnemyHeroInRange(aihero,800)!=null then//如果范围内有小兵或英雄就回家
                 call IssuePointOrder( GetTriggerUnit(), "move", -2843.00, -3147.00 )  //命令英雄回家 ,-2843.00, -3147.00是地图中家的坐标
                 endif
                 exitwhen UnitHasBuff(aihero, 'B000') == false
                 endloop
                 set buxue=false     //设置补血为false   
                endif
            else
            set flee=ture           //设置逃跑为false
            set buyitem=false       //设置购买物品为false
            set kabing=false        //设置卡兵为false   
            set attack_enemy        //设置攻击敌人为false   
            call IssuePointOrder( GetTriggerUnit(), "move", -2843.00, -3147.00 )  //命令英雄回家 ,-2843.00, -3147.00是地图中家的坐标  
            endif                                   
       endif  
    endloop
endfunction
/j
我们在if radio>0.3 then插入了使用补血的判断.
如果使用其它物品也可以在不同的线程中插入判断,判断越多就越精确
至此,RPG AI教程到此告一段落。
如果你明白了,可以到5楼学习更多的AI函数
[发帖际遇]: 怪诞生 乐于助人,奖励 26 枚 绿钻. 幸运榜 / 衰神榜
 楼主| 怪诞生 发表于 2020-3-7 18:47:26 | 显示全部楼层
5.AI函数全解释
j/
native DebugS               takes string str                            returns nothing
//显示文本带1个数字
native DebugFI              takes string str, integer val               returns nothing
//显示文本带1个单位ID
native DebugUnitID          takes string str, integer val               returns nothing
//按玩家显示文本
native DisplayText          takes integer p, string str                 returns nothing
//按玩家显示文本带1个数字
native DisplayTextI         takes integer p, string str, integer val    returns nothing
//按玩家显示文本带2个数字
native DisplayTextII        takes integer p, string str, integer v1, integer v2 returns nothing
//按玩家显示文本带3个数字
native DisplayTextIII       takes integer p, string str, integer v1, integer v2, integer v3 returns nothing
//AI脚本是否允许显示文本(没试出过返回true)
native DoAiScriptDebug      takes nothing                               returns boolean
//当前脚本控制的AI玩家
native GetAiPlayer          takes nothing                               returns integer
//英雄升级技能函数内获得升级的英雄类型
native GetHeroId            takes nothing                               returns integer
//英雄升级技能函数内获得英雄等级
native GetHeroLevelAI       takes nothing                               returns integer
//获得AI玩家的该类型单位个数,包括建造中单位
native GetUnitCount         takes integer unitid                        returns integer
//获得某玩家的该类型单位个数
native GetPlayerUnitTypeCount takes player p, integer unitid            returns integer
//获得AI玩家的已完成的该类型单位个数
native GetUnitCountDone     takes integer unitid                        returns integer
//获得AI玩家该类型单位在指定基地的个数(dn指是否只获取已完成的单位)
native GetTownUnitCount     takes integer id, integer tn, boolean dn    returns intege
//获取单位类型造价金钱
native GetUnitGoldCost      takes integer unitid                        returns integer
//获取单位类型造价木材
native GetUnitWoodCost      takes integer unitid                        returns integer
//获取单位类型建造时间(以秒为单位)
native GetUnitBuildTime     takes integer unitid                        returns integer
//获取AI玩家所拥有的金矿个数
native GetMinesOwned        takes nothing                               returns integer
//获得地图中未被采集保持满储金量的金矿数量
native GetGoldOwned         takes nothing                               returns integer
//获得编号最靠前的有金矿的基地编号
native TownWithMine         takes nothing                               returns integer
//基地有金矿可开采
native TownHasMine          takes integer townid                        returns boolean
//基地有城镇大厅
native TownHasHall          takes integer townid                        returns boolean
//获得AI玩家当前科技等级
native GetUpgradeLevel      takes integer id                            returns integer
//科技升级花费黄金
native GetUpgradeGoldCost   takes integer id                            returns integer
//科技升级花费木材
native GetUpgradeWoodCost   takes integer id                            returns integer
//获得下一个扩张点编号
native GetNextExpansion     takes nothing                               returns integer
//AI玩家当前目标单位?
native GetMegaTarget        takes nothing                               returns unit
//AI玩家正在建造的单位
native GetBuilding          takes player p                              returns unit
//获得敌人强度?
native GetEnemyPower        takes nothing                               returns integer
//设置联盟目标?
native SetAllianceTarget    takes unit id                               returns nothing
//获取联盟目标?
native GetAllianceTarget    takes nothing                               returns unit
//命令训练/建造单位(数量,单位类型,基地)
native SetProduce           takes integer qty, integer id, integer town returns boolean
//取消建造单位
native Unsummon             takes unit unitid                           returns nothing
//建造建筑<建筑工人,建筑类型>
native SetExpansion         takes unit peon, integer id                 returns boolean
//升级科技
native SetUpgrade           takes integer id                            returns boolean
//设置英雄升级技能函数
//函数要求返回整数-即是需要学习的技能ID
//函数内使用GetHeroId()获得升级的英雄类型
//使用GetHeroLevelAI()获得英雄等级
native SetHeroLevels        takes code func                             returns nothing
native SetNewHeroes         takes boolean state                         returns nothing
//购买地精飞艇
native PurchaseZeppelin     takes nothing                               returns nothing
//单位合体<数量,单位A,单位B,合体后的单位>
native MergeUnits           takes integer qty, integer a, integer b, integer make returns boolean
//单位变身<数量,变身后的单位>
native ConvertUnits         takes integer qty, integer id               returns boolean
//战役AI初始化?
native SetCampaignAI        takes nothing                               returns nothing
//对战AI初始化?
native SetMeleeAI           takes nothing                               returns nothing
//AI在战斗中设置较高的优先权攻击英雄
native SetTargetHeroes      takes boolean state                         returns nothing
//农民会自动修理需要修理的建筑
native SetPeonsRepair       takes boolean state                         returns nothing
//增加AI选择目的地的随机性
native SetRandomPaths       takes boolean state                         returns nothing
//AI会试图保护那些遭受攻击的盟友用户玩家
native SetDefendPlayer      takes boolean state                         returns nothing
//英雄在受伤严重或遭受攻击时会试图逃跑
native SetHeroesFlee        takes boolean state                         returns nothing
//英雄会在商店里购买有用的物品.
native SetHeroesBuyItems    takes boolean state                         returns nothing
//AI会抓住敌人较弱或处于劣势的时候进攻
native SetWatchMegaTargets  takes boolean state                         returns nothing
//在集结部队进攻时,忽略生命值低于50%的单位
native SetIgnoreInjured     takes boolean state                         returns nothing
//英雄拾取物品
native SetHeroesTakeItems   takes boolean state                         returns nothing
//非英雄单位在受伤严重或遭受攻击时会试图逃跑.
native SetUnitsFlee         takes boolean state                         returns nothing
//允许群组逃跑
native SetGroupsFlee        takes boolean state                         returns nothing
//AI的黄金采集数量一次只有1. 这会对AI造成严重的经济障碍
native SetSlowChopping      takes boolean state                         returns nothing
//允许基地变换
native SetCaptainChanges    takes boolean allow                         returns nothing
//攻城单位会尽可能的攻击敌人基地
native SetSmartArtillery    takes boolean state                         returns nothing
//设置AI会替换几次被杀的防卫者?
native SetReplacementCount  takes integer qty                           returns nothing
native GroupTimedLife       takes boolean allow                         returns nothing
//把受伤者送回主基或泉水
native RemoveInjuries       takes nothing                               returns nothing
native RemoveSiege          takes nothing                               returns nothing
//初始化攻击组
native InitAssault          takes nothing                               returns nothing
//增加单位进攻击组
native AddAssault           takes integer qty, integer id               returns boolean
//增加单位进防守组
native AddDefenders         takes integer qty, integer id               returns boolean
//获取中立敌对营地<最小总等级,最大总等级,是否包括飞行单位>
native GetCreepCamp         takes integer min, integer max, boolean flyers_ok returns unit
//开始寻找敌人基地
native StartGetEnemyBase    takes nothing                               returns nothing
//是否正在寻找敌人基地
native WaitGetEnemyBase     takes nothing                               returns boolean
//获取敌人基地
native GetEnemyBase         takes nothing                               returns unit
//下一个扩张点有威胁的单位?
native GetExpansionFoe      takes nothing                               returns unit
//获取敌人扩张点(分基地)
native GetEnemyExpansion    takes nothing                               returns unit
//获取可能的扩张点X坐标
native GetExpansionX        takes nothing                               returns integer
//获取可能的扩张点X坐标
native GetExpansionY        takes nothing                               returns integer
native SetStagePoint        takes real x, real y                        returns nothing
//攻击组攻击单位
native AttackMoveKill       takes unit target                           returns nothing
//攻击组攻击地点
native AttackMoveXY         takes integer x, integer y                  returns nothing
//在<X坐标,Y坐标>空投单位?
native LoadZepWave          takes integer x, integer y                  returns nothing
//玩家自杀?
native SuicidePlayer        takes player id, boolean check_full         returns boolean
//让玩家杀自己的单位?
native SuicidePlayerUnits   takes player id, boolean check_full         returns boolean
//组在战斗中<是否攻击组>
native CaptainInCombat      takes boolean attack_captain                returns boolean
//单位在基地中
native IsTowered            takes unit target                           returns boolean
//清空资源单位任务分配
native ClearHarvestAI       takes nothing                               returns nothing
//设置(增加)采集金矿单位<地点,人数>
native HarvestGold          takes integer town, integer peons           returns nothing
//设置(增加)采集树木单位<地点,人数>
native HarvestWood          takes integer town, integer peons           returns nothing
//寻找1个扩张工人?
native GetExpansionPeon     takes nothing                               returns unit
//停止聚集?
native StopGathering        takes nothing                               returns nothing
//增加防守岗位?
native AddGuardPost         takes integer id, real x, real y            returns nothing
//填满防守岗位?
native FillGuardPosts       takes nothing                               returns nothing
//返回防守岗位?
native ReturnGuardPosts     takes nothing                               returns nothing
//创建攻击组
native CreateCaptains       takes nothing                               returns nothing
//设置组在家的点<组,x坐标,y坐标>
//组的参数: ATTACK_CAPTAIN = 1; 攻击组 DEFENSE_CAPTAIN = 2; 防御组 BOTH_CAPTAINS = 3 攻击和防御组;
native SetCaptainHome       takes integer which, real x, real y         returns nothing
//命令攻击组复位?
native ResetCaptainLocs     takes nothing                               returns nothing
//转移基地?
native ShiftTownSpot        takes real x, real y                        returns nothing
//命令攻击组传送到点
native TeleportCaptain      takes real x, real y                        returns nothing
//撤销攻击组目标
native ClearCaptainTargets  takes nothing                               returns nothing
//攻击组攻击
native CaptainAttack        takes real x, real y                        returns nothing
//攻击组攻击玩家的部队?
native CaptainVsUnits       takes player id                             returns nothing
//攻击组攻击玩家?
native CaptainVsPlayer      takes player id                             returns nothing
//命令攻击组回家
native CaptainGoHome        takes nothing                               returns nothing
//攻击组在家
native CaptainIsHome        takes nothing                               returns boolean
//攻击组准备完毕
native CaptainIsFull        takes nothing                               returns boolean
//攻击组为空
native CaptainIsEmpty       takes nothing                               returns boolean
//攻击组当前人数
native CaptainGroupSize     takes nothing                               returns integer
//攻击组准备就绪
native CaptainReadiness     takes nothing                               returns integer
//攻击组撤退
native CaptainRetreating    takes nothing                               returns boolean
//攻击组生命级别,生命级别为所有攻击组单位的平均百分比血量,最高为100
native CaptainReadinessHP   takes nothing                               returns integer
//攻击组魔法级别,魔法级别为所有攻击组单位的平均百分比魔法值,最高为100
native CaptainReadinessMa   takes nothing                               returns integer
//攻击组到达目的地
native CaptainAtGoal        takes nothing                               returns boolean
//存在中立生物
native CreepsOnMap          takes nothing                               returns boolean
//让一群单位自杀?
native SuicideUnit          takes integer count, integer unitid         returns nothing
native SuicideUnitEx        takes integer ct, integer uid, integer pid  returns nothing
//开始新线程
native StartThread          takes code func                             returns nothing
//休眠
native Sleep                takes real seconds                          returns nothing
//单位存活
native UnitAlive            takes unit id                               returns boolean
//单位隐形
native UnitInvis            takes unit id                               returns boolean
//某一类型单位被攻击组忽略的人数?
native IgnoredUnits         takes integer unitid                        returns integer
//基地被攻击
native TownThreatened       takes nothing                               returns boolean
native DisablePathing       takes nothing                               returns nothing
//允许水上战斗?
native SetAmphibious        takes nothing                               returns nothing
//获得命令队列中的指令条数
//命令可以通过动作'AI - 发送AI命令'发送给AI玩家
native CommandsWaiting      takes nothing                               returns integer
//获得队列中最新一条指令
native GetLastCommand       takes nothing                               returns integer
//获得队列中最新一条指令的数据
native GetLastData          takes nothing                               returns integer
//将最新指令踢出队列
native PopLastCommand       takes nothing                               returns nothing
//对战难度等级
native MeleeDifficulty      takes nothing                               returns integer
//在对己方不利的情况下,队伍会放弃战斗从战场逃离
native SetGroupsFlee takes boolean state returns nothing/j
 楼主| 怪诞生 发表于 2020-3-7 18:47:51 | 显示全部楼层
6.rpg函数集合
【2楼教程中RPG AI函数的扩展.】
【1.远离一个单位一定距离】
j/
function LeaveUnit takes unit AiUnit,unit target,real length returns nothing
    local real a=GetUnitX(AiUnit)-GetUnitX(target)
    local real b=GetUnitY(AiUnit)-GetUnitY(target)
    local real c=SquareRoot(a*a+b*b)
    local real x=(length/c)*a+GetUnitX(AiUnit)
    local real y=(length/c)*b+GetUnitY(AiUnit)
    call  IssuePointOrder(AiUnit,"move",x,y)
endfunction
/j
   
【2.返回一个数组里最弱的单位】
j/
function GetWeakestUnit takes unit center,real range returns unit
        local unit temp
        local unit weakest
        local group g=CreateGroup()
        call  GroupEnumUnitsInRange(g,GetUnitX(center),GetUnitY(center),range,null)
        call  GroupRemoveUnit(g,center)
        loop
            set  weakest=FirstOfGroup(g)
            if weakest==null then
                call DestroyGroup(g)
                set temp = null
                set g = null
                return null
            endif
            call  GroupRemoveUnit(g,weakest)
            exitwhen IsUnitEnemy(weakest,GetOwningPlayer(center)) and GetUnitState(weakest,UNIT_STATE_LIFE)>0
        endloop
        
        loop
            set  temp=FirstOfGroup(g)
            exitwhen temp == null
            if IsUnitEnemy(temp,GetOwningPlayer(center)) and GetUnitState(temp,UNIT_STATE_LIFE)>0 then
                if GetUnitState(weakest,UNIT_STATE_LIFE)>GetUnitState(temp,UNIT_STATE_LIFE) then
                    set weakest = temp
                endif
            endif
            call GroupRemoveUnit(g,temp)
        endloop

        call DestroyGroup(g)
        set temp = null
        set g = null
        return weakest
endfunction
/j

【3.返回一个数组的最佳圆形施法中心】
j/
globals
    integer GroupNumber
    real    GroupCenterX
    real    GroupCenterY

    real    GroupFarthestDistance
    unit    GroupFarthestUnit
endglobals

function GetGroupCenterChild takes nothing returns nothing
    set GroupNumber=GroupNumber+1
    set GroupCenterX=GroupCenterX+GetUnitX(GetEnumUnit())
    set GroupCenterY=GroupCenterY+GetUnitY(GetEnumUnit())
endfunction

function    GetFarthestChild takes nothing returns nothing
    local real distance
    set   distance=DistanceXY(GetEnumUnit(),GroupCenterX,GroupCenterY)
    if(distance>GroupFarthestDistance) then
        set    GroupFarthestDistance=distance
        set    GroupFarthestUnit=GetEnumUnit()
    endif
endfunction
function GetFarthest takes group g returns real
    set     GroupNumber=0
    set     GroupCenterX=0
    set     GroupCenterY=0
    set     GroupFarthestDistance=0
    set     GroupFarthestUnit=null
    if  g==null then
        return 0
    endif
    call    ForGroup(g,function GetGroupCenterChild)
    set     GroupCenterX=GroupCenterX/GroupNumber
    set     GroupCenterY=GroupCenterY/GroupNumber
    call    ForGroup(g,function GetFarthestChild)
    return  GroupFarthestDistance
endfunction
function GroupGetBestCenter takes group g,real r returns location
    local   real    farthest
    if(g==null) then
        return null
    endif
    loop
        set farthest=GetFarthest(g)
        exitwhen farthest<=r
        call GroupRemoveUnit(g,GroupFarthestUnit)
    endloop
    return Location(GroupCenterX,GroupCenterY)
endfunction
/j

【4.取得单位身后的点】
j/
function GetUnitBackLoc takes unit TheTarget,real TheRange returns location
local real TheDir
    if (TheTarget!=null)and(GetUnitState(TheTarget,UNIT_STATE_LIFE)>0) then
       set TheDir=Deg2Rad(GetUnitFacing(TheTarget)+180)
       return (Location(TheRange*Cos(TheDir)+GetUnitX(TheTarget),TheRange*Sin(TheDir)+GetUnitY(TheTarget)))
    endif
    return null
endfunction

/j
【5.单位组前面的点】
j/
function GetUnitFrontLoc takes group whichGroup,real TheRange returns location
local real TheDir
local unit TheTarget
set TheTarget=FirstOfGroup(whichGroup)
    if (TheTarget!=null)and(IsAlive(TheTarget)) then
       set TheDir=Deg2Rad(GetUnitFacing(TheTarget))
       return (Location(TheRange*Cos(TheDir)+GetUnitX(TheTarget),TheRange*Sin(TheDir)+GetUnitY(TheTarget)))
    endif
    return null
endfunction
/j
创世神 发表于 2020-3-9 00:13:41 | 显示全部楼层

我看不错噢 谢谢楼主!天工社区越来越好!
亦真亦假皆为常世之梦
银宇沫 发表于 2020-3-9 11:58:55 | 显示全部楼层

楼主太厉害了!楼主,I*老*虎*U!我觉得天工社区真是个好地方!
czhjl520 发表于 2020-3-9 16:59:23 | 显示全部楼层

楼主太厉害了!楼主,I*老*虎*U!我觉得天工社区真是个好地方!
模型搬运工,专门把转到国外的模型转回来!
宁与国外不予国人?
b964550203 发表于 2020-3-9 18:40:32 | 显示全部楼层

其实我一直觉得楼主的品味不错!呵呵!天工社区太棒了!

强调下版规的规定,如有恶意灌水从重处罚:
=====发表主题规则=======
1.主题内容请一定要附带预览图片,谢谢;
2.搬运来的东西请尽量不要卖钱!;
3.发帖有任何疑问请联系QQ21031394;
=====发表回复规则=======
1.禁止直接复制标题内容的;
2.禁止纯数字或者纯字母的;
3.禁止乱打一通文不对题;
4.禁止屠版和刷分行为;
第一次扣分处理,第二次扣分+警告,警告三次禁言三天,绝不手软,情况严重的直接封号,请大家珍惜自己的账号!

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

猜你喜欢
天工维度唯一QQ群
786014245

欢迎进群交流,入群答案:编辑器

  • 官方在线客服

    QQ客服:小雪

    点击交谈

    QQ客服:砂糖

    点击交谈

    团队老大:荀公子

    商务合作
  • 上海市静安区共和新路4718号宏慧新汇园6号楼603室

  • 手机扫码查看手机版

    手机查找资源更方便

  • 扫一扫关注官方微信

    加入官方QQ群

Powered by 天天RPG&DZX3.4 ©2020-2021 Comsenz Inc.提百万设计( 沪ICP备18032615号-1 )营业执照