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
接楼上
我们要卡的是移动非英雄单位,也要写函数判断是否英雄:英雄是否正在移动
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.
【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