Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -------------------------------
- -- This file is part of AzzyAI 1.55
- -- If you want to use these functions in your own AI
- -- it is reccomended that you use the seperately available
- -- version, which does not utilize AAI-specific systems.
- -- Written by Dr. Azzy of iRO Chaos
- AUVersion="1.550"
- -------------------------------
- --[[
- USAGE NOTES
- HPPercent(id)
- SPPercent(id)
- Returns the current hp or sp of id as a percentage. This only works on things which the player can see the hp/sp of, obviously.
- Closer(id,x,y)
- Returns coordinants of a location 1 cell closer to actor (id)
- ClosestR(id1,id2,range)
- Returns coordinants of the cell within <range> cells of <id2> that is closest to <id1>.
- Intended for targeting of ranged skills.
- BetterMoveToOwner(mercid,range)
- Moves to the closest sell withing range cells of the owner.
- IsNotKS(id)
- Returns 1 if attacking monster (id) would be a KS, 0 otherwise.
- IsFriend(id)
- Returns 1 if (id) is the owner or a friend.
- @@@@@@@@@@@@@@@@@@@@@@@@@
- @@@ Monster Functions @@@
- @@@@@@@@@@@@@@@@@@@@@@@@@
- GetMobCount(id,range,[id2])
- Returns the number of monsters within range cells of the actor id, and the number of said monsters which are currently targeting id. If id2 is specified, monsters which are targeting id2 will also be included in the second value returned.
- Useful for deciding whether to use anti-mob skills.
- ex:
- local mobcount,aggrocount = GetMobCount(MyID,1,GetV(V_OWNER,MyID))
- GetBestBrandishTarget(id)
- Returns the id of the best monster adjacent to the mercenary to use brandish spear on (that is, the target that will result in the most monsters being hit).
- Assumes level 1 brandish area.
- ex:
- SkillObject(MyID,MySkillLevel,ML_BRANDISH,GetBestBrandishTarget(MyID))
- @@@@@@@@@@@@@@@@@@@@@@@
- @@@ Skill Functions @@@
- @@@@@@@@@@@@@@@@@@@@@@@
- GetAtkSkill(id)
- Returns a list containing skill id, skill level of the mercenary's single target offencive skill. Crash is not returned in this list, because the damage output spamming crash is lower than the damage output from using normal attacks.
- ex:
- local skill,level= GetAtkSkill(MyID)
- GetMobSkill(merctype)
- As GetAtkSkill() only for antimob skills
- ex
- local skill,level = GetMobSkill(MyID)
- GetQuickenSkill(id)
- Returns a list containing the ID of the weapon quicken skill posessed by the mercenary and the skill level
- ex
- local skill,level = GetQuickenSkill(MyID)
- GetGuardSkill(id)
- As GetQuickenSkill() only returns the ID of the guard or parry skill posessed by the mercenary.
- GetSacrificeSkill(id)
- As GetQuickenSkill() only returns the ID and other perameters for the Sacrifice (aka Devotion) skill posessed by the mercenary.
- GetProvokeSkill(id)
- As GetQuiceknSkill() only returns the ID and other perameters for the Provoke skill posessed by the mercenary.
- GetPushbackSkill(id)
- As GetMobSkill() only returns the ID and other perameters for the pushback skill (arrow repel or skid trap) posessed by the mercenary
- --]]--
- --#########################
- --### Tactics Functions ###
- --#########################
- function GetTact(t,m)
- local x
- if m==nil then
- TraceAI("GetTact: Error - nil target")
- logappend("AAI_ERROR","GetTact: Error - nil target")
- end
- if t==nil then
- TraceAI("GetTact: Error - nil tactic target:"..m)
- logappend("AAI_ERROR","request for tactic type nil target:"..m)
- end
- if (IsPlayer(m)==1) then
- if (PVPmode~=0) then
- TraceAI("GetTact: Returning pvp tactic")
- return GetPVPTact(t,m)
- else
- TraceAI("GetTact: not pvp mode returning 0")
- return 0
- end
- end
- local e = 0
- if (IsHomun(MyID)==0) then
- if (MobID[m]==nil) then
- e=GetClass(m)
- else
- e=MobID[m]
- end
- else
- e=GetV(V_HOMUNTYPE,m)
- end
- temp=GetMyTact(e)
- if (temp==nil) then
- if (e >= 1324 and e <= 1363) or (e >= 1938 and e <=1946) then
- temp=GetMyTact(13)
- TraceAI("GetTact: No tactic "..t.." for "..e.."actor: "..m.." but it's a treasure chest.")
- end
- if temp==nil then
- temp=GetMyTact(0)
- --TraceAI("GetTact: No tactic "..t.." for "..e.."actor: "..m.." using default instead")
- end
- end
- if (temp[t]==nil) then
- temp=GetMyTact(0)
- TraceAI("GetTact: Undefined tactic "..t.." for "..e.."actor: "..m.." using default instead")
- end
- x=temp[t]
- if (x==nil) then
- logappend("AAI_ERROR","Default tactic "..t.." is undefined - Please review and correct tactics file or restore default tactics file")
- return 0
- else
- if t==TACT_SP and x==-1 then
- x = AttackSkillReserveSP
- elseif t==TACT_CHASE then
- --TraceAI("TactChase called"..GetV(V_SP,MyID).." "..ChaseSPPauseSP.." "..GetTick().." "..math.max(LastMovedTime,LastSPTime).." "..(5000-ChaseSPPauseTime))
- if GetV(V_SP,MyID) < ChaseSPPauseSP and (GetTick() - math.max(LastMovedTime,LastSPTime)) > (5000-ChaseSPPauseTime) then
- if ((ChaseSPPause==1 and x~=CHASE_ALWAYS) or x==CHASE_CLEVER) then
- TraceAI("Cleverchase activated: "..m.." ("..e..") ".." LastTick "..math.max(LastMovedTime,LastSPTime))
- return 1
- end
- end
- if x==CHASE_ALWAYS then
- return 0
- elseif x==CHASE_NEVER then
- return 1
- else
- return DoNotChase
- end
- end
- return x
- end
- end
- function GetMyTact(m)
- return MyTact[m]
- end
- function GetPVPTact(t,m)
- local x
- local class
- local e = ENEMY
- if IsMonster(m)==0 then
- TraceAI("pvp tact lookup on ally")
- e= ALLY
- end
- if (MyPVPTact[m]~=nil) then
- e = m
- elseif (MyFriends[m]~=nil) then
- e = MyFriends[m]
- end
- if IsHomun(MyID)==1 then
- class=GetV(V_HOMUNTYPE,m)
- end
- if MyPVPTact[m]~=nil then
- x=MyPVPTact[m][t]
- elseif e~=ALLY and class~=nil then
- if MyPVPTact[class] ~=nil then
- x=MyPVPTact[class][t]
- end
- elseif MyFriends[e]==nil then
- x=MyPVPTact[e][t]
- end
- if x==nil then
- x=MyPVPTact[0][t]
- end
- if (x==nil) then
- TraceAI("ERROR: Default PVP tactic "..t.." is undefined!")
- logappend("AAI_ERROR","Default PVP tactic "..t.." is undefined! Please correct your PVP tactics file")
- return 0
- else
- TraceAI("pvp TL on P "..m.."IsMonster "..IsMonster(m).." type "..e.." for tactic "..t.." returning "..x)
- return x
- end
- end
- function GetClass(m)
- if (m < MagicNumber) then
- return 10
- elseif (IsActive[m]==0 and AutoDetectPlant==1) then
- return 11
- else
- return 0
- end
- end
- function IsRescueTarget(id)
- local tactrescue=GetTact(TACT_RESCUE,id)
- local target=GetV(V_TARGET,id)
- local owner=GetV(V_OWNER,MyID)
- if target==owner then
- local hp = HPPercent(owner)
- if RescueOwnerLowHP > hp then
- TraceAI("RescueOwnerLowHP -> rescue owner from "..id)
- return 1
- elseif RescueOwnerLowHP < 0 and -1*RescueOwnerLowHP < hp then
- TraceAI("RescueOwnerLowHP -> rescue of owner canceled "..id)
- return 0
- end
- end
- if tactrescue==RESCUE_NEVER then
- return 0
- else
- TraceAI("tactrescue not never "..tactrescue.." id "..id)
- if tactrescue==RESCUE_RETAINER then
- if MyFriends[target]==2 then
- return 1
- end
- elseif tactrescue==RESCUE_FRIEND then
- if MyFriends[target]==1 then
- return 1
- end
- elseif tactrescue==RESCUE_ALL then
- if IsFriendOrSelf(target)==1 and target ~=MyID then
- return 1
- end
- elseif tactrescue==RESCUE_OWNER then
- if target==GetV(V_OWNER,MyID) then
- return 1
- end
- elseif tactrescue==RESCUE_SELF then
- if target==MyID then
- return 1
- end
- end
- end
- return 0
- end
- function GetTargetClass(id)
- -- 0 = no target, 1 = self 2= friend, -1 = other monster -2 = other player
- if id == MyID then
- return 1
- elseif id == 0 then
- return 0
- elseif (id > MagicNumber2) then
- if IsFriendOrSelf(id)==1 then
- return 2
- else
- return -2
- end
- elseif IsMonster(id)==1 then
- return -1
- else
- return 0
- end
- end
- --########################
- --### Friend Functions ###
- --########################
- function IsFriend(id)
- if (id==GetV(V_OWNER,MyID)) then
- return 1
- elseif (id~= MyID) then
- friendclass=MyFriends[id]
- if (friendclass==FRIEND or friendclass==RETAINER) then
- return 1
- end
- end
- return 0
- end
- function IsPVPFriend(id)
- if (id==GetV(V_OWNER,MyID)) then
- return 1
- elseif (id~= MyID) then
- friendclass=MyFriends[id]
- if (friendclass==FRIEND or friendclass==RETAINER or friendclass==NEUTRAL or friendclass==ALLY or friendclass==NEUTRAL) then
- return 1
- end
- end
- return 0
- end
- function IsFriendOrSelf(id)
- if (id==GetV(V_OWNER,MyID) or id == MyID) then
- return 1
- else
- if (MyFriends[id]~=nil) then
- return 1
- end
- end
- return 0
- end
- function IsPlayer(id)
- if (id>MagicNumber2) then
- return 1
- else
- return 0
- end
- end
- function UpdateFriends()
- FriendsFile = io.open("AI/USER_AI/A_Friends.lua", "w")
- if FriendsFile~=nil then
- FriendsFile:write (STRING_A_FRIENDS_HEAD)
- for k,v in pairs(MyFriends) do
- if (v==FRIEND or (v==PKFRIEND and PainkillerFriendsSave == 1)) then
- FriendsFile:write ("MyFriends["..k.."]="..v.." -- \n")
- end
- end
- FriendsFile:close()
- else
- TraceAI("Failed to open A_Friends.lua for writing!")
- logappend("AAI_ERROR","Failed to open A_Friends.lua for writing!")
- end
- end
- --########################
- --### Monster functions###
- --########################
- function GetAggroCount(target)
- local aggrocount=0
- if target ==nil then
- for k,v in pairs(Targets) do
- if v[2] > 0 then -- it's aggressive
- distance = GetDistanceA(GetV(V_OWNER,MyID),k)
- if (distance <= GetMoveBounds()) then
- aggrocount=aggrocount+1*GetTact(TACT_WEIGHT,k)
- end
- end
- end
- else
- for k,v in pairs(Targets) do
- if GetV(V_TARGET,k)==target then
- aggrocount=aggrocount+1*GetTact(TACT_WEIGHT,k)
- end
- end
- end
- return aggrocount
- end
- function GetMobCount(skill,level,target,aggro)
- local mobcount=0
- if skill==0 or level==0 then
- return 0
- end
- local skillaoe=SkillAOEInfo[skill][1][level]
- local x,y=GetV(V_POSITION,MyID)
- if skillaoe==nil then
- if skill == ML_BRANDISH then
- for k,v in pairs (Targets) do
- if GetV(V_MOTION,k)~=MOTION_DEAD then
- if (GetDistanceA(myid,k)<=1 and GetDistanceA(target,k) <=1 and (v[2]>0 or aggro~=0)) then
- mobcount=mobcount+1*GetTact(TACT_WEIGHT,k)
- elseif (GetDistanceA(myid,k) ==2 and GetDistance3(myid,k) < 2.5 and GetDistance3(target,k) < 2.5 and (v[2]>0 or aggro~=0)) then -- sides, 2 cells to either side of target/merc
- mobcount=mobcount+1*GetTact(TACT_WEIGHT,k)
- end
- end
- end
- elseif skill== MA_SHARPSHOOTING then
- mx,my=GetV(V_POSITION,target)
- dx=math.abs(x-mx)
- dy=math.abs(y-my)
- if ((dx==0) or (dx==1 and dy>1) or (dx==2 and dy>6) or (dx==3 and dy>9) or (dx==4 and dy>11)) then
- if my>y then
- mobcount=GetFASTargetCount(MyID,0,1,aggro)
- elseif my<y then
- mobcount=GetFASTargetCount(MyID,0,-1,aggro)
- end
- elseif ((dy==0) or (dy==1 and dx>1) or (dy==2 and dx>6) or (dy==3 and dx>9) or (dy==4 and dx>11)) then
- if mx>x then
- mobcount=GetFASTargetCount(MyID,1,0,aggro)
- elseif mx<x then
- mobcount=GetFASTargetCount(MyID,-1,0,aggro)
- end
- -- diagonals
- elseif mx>x then
- if my>y then
- mobcount=GetFASTargetCount(MyID,1,1,aggro)
- else
- mobcount=GetFASTargetCount(MyID,-1,1,aggro)
- end
- elseif my>y then
- mobcount=GetFASTargetCount(MyID,1,-1,aggro)
- else
- mobcount=GetFASTargetCount(MyID,-1,-1,aggro)
- end
- end
- else -- we have a wellbehaved skill
- if GetSkillInfo(skill,7)==0 then
- target=MyID
- end
- range=(skillaoe-1)/2
- local logstring=""
- for k,v in pairs(Targets) do
- local tbas=GetTact(TACT_BASIC,k)
- local dist = GetDistanceAR(target,k)
- logstring=logstring.."|"..k.."v[2]"..v[2].."t"..GetV(V_TARGET,k).."m"..GetV(V_MOTION,k).."aggro"..aggro
- if dist <= range and (v[2]>0 or aggro~=0) and tbas~=0 then
- mobcount=mobcount+1*GetTact(TACT_WEIGHT,k)
- logstring=logstring.."add:"..GetTact(TACT_WEIGHT,k).."new:"..mobcount
- end
- end
- logappend("AAI_MOBCOUNT","Mobcount on well-behaved skill "..FormatSkill(skill,level).." range "..range.." logstring: "..logstring.." result: "..mobcount)
- end
- return mobcount
- end
- function GetBestAoETarget(myid,skill,level)
- local mcount=0
- local result=-1
- for k,v in pairs(Targets) do
- if mcount < GetMobCount(skill,level,k,1) then
- result=k
- mcount=GetMobCount(skill,level,k,1)
- end
- end
- return result
- end
- function GetBestAoECoord(myid,skill,level)
- local mcount =0
- local resultx = -1
- local resulty = -1
- local range=GetSkillInfo(skill,2,level)
- local aoesize=(SkillAOEInfo[skill][1][level]-1)/2
- local myx
- local myy
- myx,myy=GetV(V_POSITION,myid)
- local ox,oy=GetV(V_POSITION,GetV(V_OWNER,MyID))
- grid={}
- for xx=ox-20,ox+20 do
- grid[xx]={}
- --for xx=oy-20,oy+20 do
- -- grid[xx][yy]=0
- --end
- end
- for k,v in pairs(Targets) do
- local tbas = GetTact(TACT_BASIC,k)
- x,y=GetV(V_POSITION,k)
- if x < ox+20 and x > ox-20 and y < oy+20 and y > oy-20 and tbas~=0 then
- if grid[x][y]==nil then
- grid[x][y]=GetTact(TACT_WEIGHT,k)
- else
- grid[x][y]=grid[x][y]+GetTact(TACT_WEIGHT,k)
- end
- end
- end
- for xx=myx-range,myx+range do
- for yy=myy-range,myy+range do
- local thiscount=0
- for xxx=xx-aoesize,xx+aoesize do
- if grid[xxx]~=nil then
- for yyy=yy-aoesize,yy+aoesize do
- if grid[xxx][yyy] ~=nil then
- thiscount=thiscount+grid[xxx][yyy]
- end
- end
- end
- end
- if thiscount>mcount then
- mcount=thiscount
- resultx,resulty=xx,yy
- end
- end
- end
- return resultx,resulty
- end
- function GetBestBrandishTarget(myid)
- local mobs =0
- local maxmobs = 0
- local besttarget= -1
- for k,v in pairs(Targets) do
- if (GetDistanceA(myid,k) <=1) then --Is a target in range to brandish
- mobs = 0
- for kk,vv in pairs (Targets) do
- local tbas=GetTact(TACT_BASIC,kk)
- if tbas ~= 0 then
- if (GetDistanceA(myid,kk)<=1 and GetDistanceA(k,kk) <=1) then
- mobs=mobs+1
- elseif (GetDistanceA(myid,kk) ==2 and GetDistance3(myid,kk) < 2.5 and GetDistance3(k,kk) < 2.5)then -- sides, 2 cells to either side of target/merc
- mobs=mobs+1
- end
- end
- end
- if (mobs > maxmobs) then
- maxmobs = mobs
- besttarget = v
- end
- end
- end
- return besttarget
- end
- function GetBestFASTarget(myid)
- local options = GetFASOptions(myid)
- local mincount=0
- local target=-1
- for x,v in pairs(options) do
- for y,v2 in pairs(v) do
- --TraceAI("GetBestFAST "..x.." "..y.." "..v2)
- if v2~=0 then
- count=GetFASTargetCount(myid,x,y)
- if count > mincount then
- mincount = count
- target = v2
- end
- end
- end
- end
- return target,mincount
- end
- function GetFASDirection(myid,target)
- local x,y=GetV(V_POSITION,myid)
- if GetDistanceA(myid,target) < 15 then
- local mx,my=GetV(V_POSITION,target)
- local dx=math.abs(x-mx)
- local dy=math.abs(y-my)
- if ((dx==0) or (dx==1 and dy>1) or (dx==2 and dy>6) or (dx==3 and dy>9) or (dx==4 and dy>11)) then
- if my>=y then
- return 0,1 --n
- elseif my<y then
- return 0,-1 --s
- end
- elseif ((dy==0) or (dy==1 and dx>1) or (dy==2 and dx>6) or (dy==3 and dx>9) or (dy==4 and dx>11)) then
- if mx>x then
- return 1,0 --e
- elseif mx<x then
- return-1,0 --w
- end
- -- diagonals
- elseif mx>x then
- if my>=y then
- return 1,1 --ne
- else
- return 1,-1 --se
- end
- elseif my>=y then
- return -1,1 --nw
- else
- return -1,-1 --sw
- end
- end
- end
- function GetFASOptions(myid)
- local x,y=GetV(V_POSITION,myid)
- noption=0
- eoption=0
- soption=0
- woption=0
- neoption=0
- nwoption=0
- seoption=0
- swoption=0
- for k,v in pairs(Monsters) do
- TraceAI("FAS loop id: "..k)
- if GetDistanceA(myid,k) < 15 then
- mx,my=GetV(V_POSITION,k)
- dx=math.abs(x-mx)
- dy=math.abs(y-my)
- if ((dx==0) or (dx==1 and dy>1) or (dx==2 and dy>6) or (dx==3 and dy>9) or (dx==4 and dy>11)) then
- if my>y then
- noption=k
- elseif my<y then
- soption=k
- end
- elseif ((dy==0) or (dy==1 and dx>1) or (dy==2 and dx>6) or (dy==3 and dx>9) or (dy==4 and dx>11)) then
- if mx>x then
- eoption=k
- elseif mx<x then
- woption=k
- end
- -- diagonals
- elseif mx>x then
- if my>=y then
- neoption=k
- else
- seoption=k
- end
- elseif my>=y then
- nwoption=k
- else
- swoption=k
- end
- end
- if (noption~=0 and soption~=0 and eoption~=0 and woption~=0 and neoption~=0 and seoption~=0 and swoption~=0 and nwoption~=0) then
- TraceAI("All Options Avail - break")
- break
- end
- end
- result={[-1]={[-1]=swoption,[0]=woption,[1]=nwoption},[0]={[-1]=soption,[0]=0,[1]=noption},[1]={[-1]=seoption,[0]=eoption,[1]=neoption}}
- TraceAI("Returning FAS Options: "..swoption.."-"..woption.."-"..nwoption.." "..soption.."--"..noption.." "..seoption.."-"..eoption.."-"..neoption)
- return result
- end
- function GetFASTargetCount(myid,directionx,directiony,aggro)
- local x,y=GetV(V_POSITION,myid)
- local s=directionx+directiony
- TraceAI("GFASTC: "..s)
- count=0
- if s==1 or s==-1 then -- straight
- if directiony==0 then --Horizontal
- ymin=y-1
- ymax=y+1
- if directionx==1 then --East
- xmin=x
- xmax=x+14
- else
- xmin=x-14
- xmax=x
- end
- else --Vertical
- xmin=x-1
- xmax=x+1
- if directiony==1 then -- north
- ymin=y
- ymax=y+14
- else
- ymin=y-14
- ymax=y
- end
- end
- for k,v in pairs(Targets) do
- mx,my=GetV(V_POSITION,k)
- --logappend("AAI_mobcount","straight monster:"..xmin.."-"..xmax..","..ymin.."-"..ymax.." "..mx..","..my)
- if GetTact(TACT_BASIC,k)~=0 and mx>=xmin and xmax>=mx and my>=ymin and ymax>=my then
- count=count+1
- end
- end
- --logappend("AAI_mobcount","straight:"..xmin.."-"..xmax..","..ymin.."-"..ymax.." count"..count)
- return count
- else --Diagonal
- count = 0
- for k,v in pairs(Targets) do
- if GetTact(TACT_BASIC,k)~=0 and IsNotKS(MyID,k)==1 then
- mx,my=GetV(V_POSITION,k)
- if directionx==1 then --east
- if (mx+1>=x and x+14>=mx) then -- has prayer of hitting
- if mx==x-1 then
- if my==y+directiony then
- count=count+1
- end
- elseif mx==x then
- if (my==y or my==y+directiony or my==y+2*directiony) then
- count=count+1
- end
- elseif mx==x+14 then
- if my==y+12*directiony then
- count=count+1
- end
- elseif mx==x+13 then
- if (my==y+11*directiony or my==y+10*directiony or my==y+12*directiony) then
- count=count+1
- end
- else --not a special case
- if directiony==1 then
- miny=y-2+(mx-x)
- maxy=miny+5
- else
- maxy=y+2-(mx-x)
- miny=maxy-5
- end
- if my>=miny and maxy>=my then
- count=count+1
- end
- end
- end
- else --west
- if mx-1<=x and x-14<=mx then -- has prayer of hitting
- if mx==x+1 then
- if my==y+directiony then
- count=count+1
- end
- elseif mx==x then
- if (my==y or my==y+directiony or my==y+2*directiony) then
- count=count+1
- end
- elseif mx==x-14 then
- if my==y+12*directiony then
- count=count+1
- end
- elseif mx==x-13 then
- if (my==y+11*directiony or my==y+10*directiony or my==y+12*directiony) then
- count=count+1
- end
- else --not a special case
- if directiony==1 then
- miny=y-2+(x-mx)
- maxy=miny+5
- else
- maxy=y+2-(x-mx)
- miny=maxy-5
- end
- if my>=miny and maxy>=my then
- count=count+1
- end
- end
- end
- end
- end
- end
- --logappend("AAI_mobcount","diagonal:"..count)
- end
- return count
- end
- function IsHiddenOnScreen(myid) --Currently disabled - assume there is never hidden on screen.
- return 1
- end
- function IsHomun(myid)
- if (GetV(V_HOMUNTYPE,myid)~=nil) then
- return 1
- end
- return 0
- end
- function GetMerType(myid)
- local merctype=GetV(V_MERTYPE,myid)
- TraceAI("Merc is homun?"..IsHomun(myid))
- if (merctype~=1) then
- return merctype
- elseif merctype > 30 then
- logappend("AAI_ERROR","Invalid merctype reported"..merctype)
- return merctype
- else
- mhp=GetV(V_MAXHP,myid)
- msp=GetV(V_MAXSP,myid)
- if (mhp > 250 and mhp < 333 and msp >= 200 and 250 >= msp ) then -- it's an archer 1
- return ARCHER01
- elseif (mhp == 7513 and msp == 201) then
- TraceAI("Newly summoned Pengineer")
- return PENGINEER
- elseif (mhp >= 4000 and 5000 >= mhp and msp >= 50 and msp < 65 ) then -- looks like a kitty!
- TraceAI("Wild Rose")
- return WILDROSE
- elseif (mhp >= 7513 and 8500 >= mhp and msp >= 201 and msp < 250 ) then
- TraceAI("Pengineer")
- return PENGINEER
- elseif (mhp >= 7200 and 7512 >= mhp and msp >= 200 and msp < 250 ) then -- looks like a dopple!
- TraceAI("Dopple Merc")
- return DOPPLEMERC
- elseif (mhp >= 10000 and 13000 >= mhp and msp >= 220 and msp < 300 ) then -- looks like alice!
- TraceAI("Alice")
- return ALICE
- elseif (mhp >= 6100 and 7200 >= mhp and msp >= 180 and msp < 250 ) then -- looks like a mimic!
- TraceAI("Mimic")
- return MIMIC
- elseif (mhp >= 7500 and 9500 >= mhp and msp >= 180 and msp < 220 ) then -- looks like a disguise!
- TraceAI("Disguise")
- return DISGUISE
- elseif (mhp >= 7000 and 8500 >= mhp and msp >= 250 and msp < 320 ) then -- looks like a male GM mercenary!
- TraceAI("GM Mercenary")
- return GMMALE
- elseif (mhp > 12300 and 14500 >= mhp and msp >= 450 and msp < 600 ) then -- Nice stats, must be one of them overpowerd isis mercs
- TraceAI("ISIS Mercenary")
- return ISIS
- else
- TraceAI("Unknown merc type. Contact the developer ASAP.")
- return UNKNOWNMER
- end
- end
- end
- function IsNotKS(myid,target)
- --TraceAI("Checking for KS:"..target)
- local targettarget=GetV(V_TARGET,target)
- local motion=GetV(V_MOTION,target)
- local tactks=GetTact(TACT_KS,target)
- if (target==MyEnemy and BypassKSProtect==1) then --If owner has told homun to attack explicity, let it.
- return 1
- end
- if target==nil then
- TraceAI("IsNotKS")
- end
- if (IsPlayer(target)==1) then
- --TraceAI("PVP - not KS")
- return 1
- elseif (IsFriend(targettarget)==1 or targettarget==myid) then
- --TraceAI("Not KS - "..target.." fighting friend: "..targettarget)
- return 1
- elseif ((tactks==KS_POLITE or DoNotAttackMoving ==1) and motion==MOTION_MOVE) then
- return 0
- elseif (tactks==KS_ALWAYS) then
- --TraceAI("It's an FFA monster, not a KS")
- return 1
- elseif targettarget > 0 and IsMonster(targettarget)~=1 and Actors[targettarget]==1 then
- --TraceAI("Is KS - "..target.." attacking player "..targettarget.." motion "..motion)
- return 0
- else
- --TraceAI("Not Targeted - seeing if anyone is targeting it")
- local actors = GetActors()
- for i,v in ipairs(actors) do
- if (IsMonster(v)~=1 and IsFriendOrSelf(v)==0) then
- if (GetV(V_TARGET,v) == target and (v > 100000 or KSMercHomun ~=1)) then
- --TraceAI("Is KS - "..target.." is targeted by "..v)
- return 0
- end
- end
- end
- --TraceAI("Not KS - "..target.." is not targeted by any other player.")
- return 1
- end
- end
- function GetKSReason(myid,target)
- --TraceAI("Checking for KS:"..target)
- local targettarget=GetV(V_TARGET,target)
- local motion=GetV(V_MOTION,target)
- local tactks=GetTact(TACT_KS,target)
- if (target==MyEnemy and BypassKSProtect==1) then --If owner has told homun to attack explicity, let it.
- return "KS Protect bypassed"
- end
- if target==nil then
- TraceAI("IsNotKS")
- end
- if (IsPlayer(target)==1) then
- --TraceAI("PVP - not KS")
- return "PVP, not KS"
- elseif ((tactks==KS_POLITE or DoNotAttackMoving ==1) and motion==MOTION_MOVE) then
- return "KS polite aka DoNotAttackMoving"
- elseif (IsFriend(targettarget)==1 or targettarget==myid) then
- --TraceAI("Not KS - "..target.." fighting friend: "..targettarget)
- return "Not KS - enemy attacking "..targettarget
- elseif (tactks==KS_ALWAYS) then
- --TraceAI("It's an FFA monster, not a KS")
- return "FFA monster"
- elseif targettarget > 0 and IsMonster(targettarget)~=1 and Actors[targettarget]==1 then
- --TraceAI("Is KS - "..target.." attacking player "..targettarget.." motion "..motion)
- if MyFriends[targettarget]~=nil then
- return "KS - enemy is attacking "..targettarget.." MyFriends: "..MyFriends[targettarget]
- else
- return "KS - enemy is attacking "..targettarget
- end
- else
- --TraceAI("Not Targeted - seeing if anyone is targeting it")
- local actors = GetActors()
- for i,v in ipairs(actors) do
- if (IsMonster(v)~=1 and IsFriendOrSelf(v)==0) then
- if (GetV(V_TARGET,v) == target and (v > 100000 or KSMercHomun ~=1)) then
- --TraceAI("Is KS - "..target.." is targeted by "..v)
- if MyFriends[v]~=nil then
- return "KS - enemy attacked by "..v.." MyFriends: "..MyFriends[v]
- else
- return "KS - enemy attacked by "..v
- end
- end
- end
- end
- --TraceAI("Not KS - "..target.." is not targeted by any other player.")
- return "not KS, not targeted by anything"
- end
- end
- --########################
- --### HP/SP % functions###
- --########################
- function HPPercent(id)
- local maxHP=GetV(V_MAXHP,id)
- local curHP=GetV(V_HP,id)
- percHP=100*curHP/maxHP
- return percHP
- end
- function SPPercent(id)
- local maxSP=GetV(V_MAXSP,id)
- local curSP=GetV(V_SP,id)
- percSP=100*curSP/maxSP
- return percSP
- end
- --########################
- --### Spacial functions###
- --########################
- OldMove=Move
- function Move(myid,x,y)
- local ox,oy = GetV(V_POSITION,myid)
- local dis = GetDistance(ox,oy,x,y)
- local dis2owner=GetDistanceAPR(GetV(V_OWNER,myid),x,y)
- local newx,newy=x,y
- if dis2owner > 14 then
- logappend("AAI_ERROR","Attempt to move to location "..x..","..y.." which is "..dis2owner.." cells from owner, call disregarded")
- return
- elseif dis > 15 then
- factor = 15/dis
- local dx,dy = x-ox,y-oy
- if math.random(2)==1 then
- dx=math.ceil(factor*dx)
- else
- dx=math.floor(factor*dx)
- end
- if math.random(2)==1 then
- dy=math.ceil(factor*dy)
- else
- dy=math.floor(factor*dy)
- end
- if _VERSION=="Lua 5.1" then
- while TakenCells[(x+dx).."_"..(y+dy)] do
- factor=factor-0.08
- if math.random(2)==1 then
- dx=math.ceil(factor*(x-ox))
- else
- dx=math.floor(factor*(x-ox))
- end
- if math.random(2)==1 then
- dy=math.ceil(factor*(y-oy))
- else
- dy=math.floor(factor*(y-oy))
- end
- end
- end
- if x==MyDestX and y==MyDestY then
- newx=ox+dx
- newy=oy+dy
- MyDestX,MyDestY=newx,newy
- TraceAI("MOVE: Attempt to move more than 15 cells, destination + MyDest adjusted: "..x..","..y.." "..dis.." "..factor.."new: "..newx..","..newy)
- else
- newx=ox+dx
- newy=oy+dy
- TraceAI("MOVE: Attempt to move more than 15 cells, destination adjusted: "..x..","..y.." "..dis.." "..factor.."new: "..newx..","..newy)
- end
- end
- if (LagReduction) then
- modtwROMoveX,modtwROMoveY=x,y
- return
- else
- return OldMove(myid,newx,newy)
- end
- end
- OldSkillObject=SkillObject
- function SkillObject(myid,lvl,skill,target)
- if skill==8041 or skill==8043 or skill==8020 or skill==8025 then
- logappend("AAI_ERROR","Attempted to use skill "..SkillInfo[skill][1].." improperly. Check for corrupt H_SkillInfo or badly behaved addon")
- else
- if (LagReduction) then
- modtwROSkillObjectID=skill
- modtwROSkillObjectLV=lvl
- modtwROSkillObjectTarg=target
- else
- return OldSkillObject(myid,lvl,skill,target)
- end
- end
- end
- OldAttack=Attack
- function Attack(myid,target)
- if SuperPassive==1 then
- TraceAI("Notice: Attack() called while in SuperPassive. MyEnemy "..MyEnemy.." MyState "..MyState)
- end
- if (LagReduction) then
- modtwROAttackTarget=target
- else
- return OldAttack(myid,target)
- end
- end
- OldSkillGround=SkillGround
- function SkillGround(myid,lvl,skill,x,y)
- if (LagReduction) then
- modtwROSkillGroundX=x
- modtwROSkillGroundY=y
- modtwROSkillGroundID=skill
- modtwROSkillGroundLV=lvl
- else
- return OldSkillGround(myid,lvl,skill,x,y)
- end
- end
- function GetDistance (x1,y1,x2,y2)
- return math.floor(math.sqrt((x1-x2)^2+(y1-y2)^2))
- end
- function GetDistance2 (id1, id2)
- local x1, y1 = GetV (V_POSITION,id1)
- local x2, y2 = GetV (V_POSITION,id2)
- if (x1 == -1 or x2 == -1) then
- return -1
- end
- return GetDistance (x1,y1,x2,y2)
- end
- function GetDistanceA (id1, id2)
- local x1, y1 = GetV (V_POSITION,id1)
- local x2, y2 = GetV (V_POSITION,id2)
- if (x1 == -1 or x2 == -1) then
- return 999
- end
- return GetDistance (x1,y1,x2,y2)
- end
- function GetDistanceAP (id1, x2,y2)
- local x1, y1 = GetV (V_POSITION,id1)
- if (x1 == -1 or x2 == -1) then
- return 999
- end
- return GetDistance (x1,y1,x2,y2)
- end
- function GetDistanceAPR (id1, x2,y2)
- local x1, y1 = GetV (V_POSITION,id1)
- if (x1 == -1 or x2 == -1) then
- return 999
- end
- local x=x1-x2
- local y=y1-y2
- return math.max(math.abs(x),math.abs(y))
- end
- function GetDistanceRect(id1,id2)
- local x1, y1 = GetV (V_POSITION,id1)
- local x2, y2 = GetV (V_POSITION,id2)
- if (x1 == -1 or x2 == -1) then
- return 999
- end
- local x=x1-x2
- local y=y1-y2
- return math.max(math.abs(x),math.abs(y))
- end
- function GetDistance3(id1,id2)
- local x1, y1 = GetV (V_POSITION,id1)
- local x2, y2 = GetV (V_POSITION,id2)
- if (x1 == -1 or x2 == -1) then
- return -1
- end
- return math.sqrt((x1-x2)^2+(y1-y2)^2)
- end
- function GetAggroDist()
- if OwnerPosX[10]==OwnerPosX[1] and OwnerPosY[10]==OwnerPosY[1] then
- return StationaryAggroDist
- else
- return MobileAggroDist
- end
- end
- function GetMoveBounds()
- if OwnerPosX[10]==OwnerPosX[1] and OwnerPosY[10]==OwnerPosY[1] then
- return StationaryMoveBounds
- else
- return MobileMoveBounds
- end
- end
- function IsToRight(id1,id2)
- local x1,y1=GetV(V_POSITION,id1)
- local x2,y2=GetV(V_POSITION,id2)
- if (x1+1==x2 and y1==y2) then
- return 1
- else
- return 0
- end
- end
- function GetDistanceP (x1,y1,x2,y2)
- if (x1 == -1 or x2 == -1) then
- return 999
- end
- return math.floor(math.sqrt((x1-x2)^2+(y1-y2)^2))
- end
- function GetDistanceA (id1, id2)
- local x1, y1 = GetV (V_POSITION,id1)
- local x2, y2 = GetV (V_POSITION,id2)
- if (x1 == -1 or x2 == -1) then
- return 999
- end
- return GetDistance (x1,y1,x2,y2)
- end
- function GetDistanceAP (id1, x2,y2)
- local x1, y1 = GetV (V_POSITION,id1)
- if (x1 == -1 or x2 == -1) then
- return 999
- end
- return GetDistance (x1,y1,x2,y2)
- end
- function GetDistancePR (x1,y1,x2,y2)
- if (x1 == -1 or x2 == -1) then
- return 999
- end
- return math.max(math.abs(x1-x2),math.abs(y1-y2))
- end
- function GetDistanceAR(id1,id2)
- local x1, y1 = GetV (V_POSITION,id1)
- local x2, y2 = GetV (V_POSITION,id2)
- if (x1 == -1 or x2 == -1) then
- return 999
- end
- return math.max(math.abs(x1-x2),math.abs(y1-y2))
- end
- function GetDistanceAPR (id1, x2,y2)
- local x1, y1 = GetV (V_POSITION,id1)
- if (x1 == -1 or x2 == -1) then
- return 999
- end
- return math.max(math.abs(x1-x2),math.abs(y1-y2))
- end
- function BetterMoveToOwner(myid,range)
- if (range==nil) then
- range=1
- end
- local x,y = GetV(V_POSITION,myid)
- local ox,oy = GetV(V_POSITION,GetV(V_OWNER,myid))
- local destx,desty=0,0
- if (x > ox+range) then
- destx=ox+range
- elseif (x < ox - range) then
- destx=ox-range
- else
- destx=x
- end
- if (y > oy+range) then
- desty=oy+range
- elseif (y < oy - range) then
- desty=oy-range
- else
- desty=y
- end
- MyDestX,MyDestY=destx,desty
- Move(myid,MyDestX,MyDestY)
- return
- end
- function BetterMoveToOwnerXY(myid,range)
- if (range==nil) then
- range=1
- end
- local x,y = GetV(V_POSITION,myid)
- local ox,oy = GetV(V_POSITION,GetV(V_OWNER,myid))
- local destx,desty=0,0
- if (x > ox+range) then
- destx=ox+range
- elseif (x < ox - range) then
- destx=ox-range
- else
- destx=x
- end
- if (y > oy+range) then
- desty=oy+range
- elseif (y < oy - range) then
- desty=oy-range
- else
- desty=y
- end
- return destx,desty
- end
- function BetterMoveToLoc(myid,range,ox,oy)
- if (range==nil) then
- range=1
- end
- local x,y = GetV(V_POSITION,myid)
- --local ox,oy = GetV(V_POSITION,GetV(V_OWNER,myid))
- local destx,desty=0,0
- if (x > ox+range) then
- destx=ox+range
- elseif (x < ox - range) then
- destx=ox-range
- else
- destx=x
- end
- if (y > oy+range) then
- desty=oy+range
- elseif (y < oy - range) then
- desty=oy-range
- else
- desty=y
- end
- MyDestX,MyDestY=destx,desty
- Move(myid,MyDestX,MyDestY)
- return
- end
- function BetterMoveToLocXY(myid,range,ox,oy)
- if (range==nil) then
- range=1
- end
- local x,y = GetV(V_POSITION,myid)
- --local ox,oy = GetV(V_POSITION,GetV(V_OWNER,myid))
- local destx,desty=0,0
- if (x > ox+range) then
- destx=ox+range
- elseif (x < ox - range) then
- destx=ox-range
- else
- destx=x
- end
- if (y > oy+range) then
- desty=oy+range
- elseif (y < oy - range) then
- desty=oy-range
- else
- desty=y
- end
- return destx,desty
- end
- function GetOwnerPosition (id)
- return GetV (V_POSITION,GetV(V_OWNER,id))
- end
- function GetDistanceFromOwner (id)
- local x1, y1 = GetOwnerPosition (id)
- local x2, y2 = GetV (V_POSITION,id)
- if (x1 == -1 or x2 == -1) then
- return -1
- end
- return GetDistance (x1,y1,x2,y2)
- end
- function IsOutOfSight (id1,id2)
- local x1,y1 = GetV (V_POSITION,id1)
- local x2,y2 = GetV (V_POSITION,id2)
- if (x1 == -1 or x2 == -1 or id1==-1 or id2==-1) then
- return true
- end
- local d = GetDistancePR(x1,y1,x2,y2)
- if d > 20 then
- return true
- else
- return false
- end
- end
- function IsInAttackSight (myid,target,skill,level)
- if (skill==nil) then
- skill=MySkill
- level=MySkillLevel
- elseif (level==nil) then
- logappend("AAI_ERROR","IsInAttackSight called with nil level but skill is not nil. State:"..MyState.." skill "..skill)
- end
- local x1,y1 = GetV (V_POSITION,myid)
- local x2,y2 = GetV (V_POSITION,target)
- if (x1 == -1 or x2 == -1) then
- return false
- end
- local d = GetDistance (x1,y1,x2,y2)
- local a = AttackRange(myid,skill,level)
- if a >= d then
- return true;
- else
- return false;
- end
- end
- function AttackRange(myid,skill,level)
- if (skill==nil or level== nil) then
- if skill==nil or level==nil then
- logappend("AAI_ERROR","AttackRange called with invalid arguments State:"..MyState.." MySkill "..MySkill.." MySkillLevel"..MySkillLevel.." skill: "..formatval(skill).." level: "..formatval(level))
- end
- skill=MySkill
- level=MySkillLevel
- end
- local a = 0
- if (skill == 0) then
- mertype=GetMerType(myid)
- if (mertype==nil) then
- mertype=-1
- end
- if (mertype == -1) then
- a = 1
- elseif (mertype > 10 and mertype < 21) then
- a = 2 --spear mercenary
- else
- a = GetV(V_ATTACKRANGE,myid)
- end
- --elseif (skill==MS_BOWLINGBASH) then
- -- a = 1
- else
- a = GetSkillInfo(skill,2,level)
- if a==nil then
- TraceAI("AttackRange() cannot get range for skill "..formatval(skill).." level "..formatval(level))
- end
- end
- if level == nil then
- logappend("AAI_ERROR","AttackRange called with nil level, skill = "..skill.." "..MyState)
- end
- TraceAI("Attack Sight - skill:"..skill.."level: "..level.." Range:"..a)
- return a
- end
- function Closer(id,ox,oy)
- local x,y=GetV(V_POSITION,id)
- local newx,newy=0,0
- if (ox==x) then
- newx=x
- elseif (ox > x) then
- newx=ox-1
- else
- newx=ox+1
- end
- if (oy==y) then
- newy=y
- elseif (oy > y) then
- newy=oy-1
- else
- newy=oy+1
- end
- return newx,newy
- end
- function GetStandPoint(myid,target,skill,level,alt)
- local r=AttackRange(myid,skill,level)
- if GetDistanceA(myid,target) <= r then
- logappend("AAI_ERROR","GetStandPoint called while within range")
- return GetV(V_POSITION,MyID)
- end
- local tx,ty=GetV(V_POSITION,target)
- local x,y=-1,-1
- if _VERSION=="Lua 5.1" and myid==MyID and (alt==nil or alt==0) then
- x,y=GetV(V_POSITION_APPLY_SKILLATTACKRANGE,target,skill,level)
- end
- if skill==0 or skill==nil or (tx==x and ty==y) or (tx < 1 or ty < 1) or math.floor(GetDistanceAP(target,x,y)) > r then -- Use normal closest call, since V_POSITION_APPLY_SKILLATTACKRANGE doesn't work for non-skills, or has given us clearly bogus standpoint for skill.
- x,y=Closest(myid,tx,ty,r,alt)
- end
- return AdjustStandPoint(x,y,tx,ty,r,alt)
- end
- function AdjustStandPoint (x,y,tx,ty,r,alt)
- if _VERSION=="Lua 5.1" then
- -- Now we need to make sure x and y are not on occupied cells, because of the changes to the client
- local i=0
- local bounds=GetMoveBounds()
- while (TakenCells[x.."_"..y] or GetDistanceAP(MyID,x,y) > bounds) do
- i=i+1
- if r==1 then
- if alt==nil or alt==0 then
- x,y=AdjustCW(x,y,tx,ty)
- elseif alt==1 then
- x,y=AdjustCCW(x,y,tx,ty)
- else --alt=2
- x,y=AdjustOpp(x,y,tx,ty)
- alt=0
- end
- if i > 7 then
- return -1,-1
- end
- else
- if alt==nil or alt==0 then
- x,y=AdjustCWr(x,y,tx,ty,r)
- elseif alt==1 then
- x,y=AdjustCCWr(x,y,tx,ty,r)
- else --alt=2
- x,y=x*-1,y*-1
- alt=0
- end
- if i > 7 then
- return -1,-1
- end
- end
- end
- end
- return x,y
- end
- function Closest(myid,ox,oy,range,alt)
- local x,y=GetV(V_POSITION,myid)
- local dx,dy=ox-x,oy-y
- local newx,newy=0,0
- local logstring="x,y"..x..","..y.." ox,oy"..ox..","..oy
- if range > 1 then
- logstring=logstring.."range > 1 "
- dist=math.sqrt(dx^2+dy^2)
- if (dist < range) then
- newx,newy=x,y
- logstring=logstring.."dist < range new"..newx..","..newy.." "
- else
- factor=range/dist
- xoff=(dx-absceil(dx*factor))
- yoff=(dy-absceil(dy*factor))
- newx,newy=x+xoff,y+yoff
- logstring=logstring.."dist > range new" ..newx..","..newy.." factor:"..factor.." "
- end
- -- This routine tries to find an adjacent cell to the closest cell that will be close enough - to address unwalkable cells near where retainer wants to walk (think: pebbles in thors)
- if (alt ~= nil) then
- logstring=logstring.."alt not nil"..alt.." "
- if (alt==1) then
- if (x > ox) then
- newx=newx-1
- elseif (x < ox) then
- newx=newx+1
- else
- alt=2
- end
- end
- if (alt==2) then
- if (y > oy) then
- newy=newy-1
- elseif (y < oy) then
- newy=newy+1
- else
- alt=3
- end
- end
- --if (alt==4) then -- This seems to cause more problems than it solves, set to 4 to prevent from running
- -- if (x > ox) then
- -- newx=newx-1
- -- newy=newy+1
- -- elseif (x < ox) then
- -- newx=newx+1
- -- newy=newy+1
- -- elseif (y > oy) then
- -- newy=newy-1
- -- newx=newx+1
- -- else
- -- newy=newy+1
- -- newx=newx+1
- -- end
- --end
- logstring=logstring.."end of alt sequence new"..newx..","..newy.." alt "..alt.." "
- end
- --xxx,yyy=GetV(V_POSITION,target)
- --TraceAI("alt is: "..GetDistance(xxx,yyy,newx,newy).." "..xxx..","..yyy.." "..newx..","..newy.."MyPos: "..x..","..y)
- else -- simplified, better closest point for melee.
- logstring=logstring.."range = 1 d"..dx..","..dy.." o"..ox..","..oy.." "
- if dx > 0 then
- newx=ox-1
- elseif dx < 0 then
- newx=ox+1
- else -- dx = 0
- newx=x
- end
- if dy > 0 then
- newy=oy-1
- elseif dy < 0 then
- newy=oy+1
- else -- dy = 0
- newy=y
- end
- logstring=logstring.."new"..newx..","..newy.." "
- if alt~=nil then
- if alt==1 then
- newx,newy=AdjustCW(newx,newy,ox,oy)
- logstring=logstring.."adjust cw"..newx..","..newy.." "
- else
- newx,newy=AdjustCCW(newx,newy,ox,oy)
- logstring=logstring.."adjust ccw"..newx..","..newy.." "
- end
- end
- end
- local logalt="nil"
- if alt~=nil then
- logalt=alt
- end
- if newx<=0 or newy<=0 then
- logappend("AAI_ERROR","Closest() Failure!"..newx.." , "..newy.." alt ="..logalt.." logstring="..logstring)
- end
- logappend("AAI_CLOSEST","Closest() returned "..newx.." , "..newy.." alt ="..logalt.." logstring="..logstring)
- return newx,newy
- end
- function AdjustCW(x,y,ox,oy)
- local newx,newy,dy,dx
- if x==ox then
- if y==oy then --stacked!? Unstack!
- newx,newy=ox+1,oy
- else
- dy=y-oy
- newx=x+absunit(dy)
- newy=y
- end
- elseif y==oy then
- dx=x-ox
- newy=y-absunit(dx)
- newx=x
- elseif y>oy then
- if x>ox then
- newy=y-1
- newx=x
- else
- newy=y
- newx=x+1
- end
- else -- y<oy
- if x>ox then
- newx=x-1
- newy=y
- else
- newx=x
- newy=y+1
- end
- end
- return newx,newy
- end
- function AdjustCCW(x,y,ox,oy)
- local newx,newy,dx,dy
- if x==ox then
- if y==oy then --stacked!? Unstack!
- newx,newy=ox-1,oy
- else
- dy=y-oy
- newx=x-absunit(dy)
- newy=y
- end
- elseif y==oy then
- dx=x-ox
- newy=y+absunit(dx)
- newx=x
- elseif y>oy then
- if x>ox then
- newy=y
- newx=x-1
- else
- newy=y-1
- newx=x
- end
- else -- y<oy
- if x>ox then
- newx=x
- newy=y+1
- else
- newx=x+1
- newy=y
- end
- end
- return newx,newy
- end
- function AdjustCWr(x,y,ox,oy,r)
- if r==1 then
- return AdjustCW(x,y,ox,oy)
- end
- local newx,newy,dy,dx
- dx,dy=x-ox,y-oy
- if math.abs(dx) == math.abs(dy) then --we're on a diagonal, this could be a problem, so let's get off it!
- if dx < 0 then
- if dy < 0 then
- newx=x+1
- newy=y
- else
- newx=x
- newy=y-1
- end
- elseif dx > 0 then
- if dy < 0 then
- newy=y+1
- newx=x
- else
- newx=x-1
- newy=y
- end
- else --stacked, which should NEVER HAPPEN but has somehow happened anyway
- newx=x+1
- newy=y+1
- logappend("AAI_ERROR","AdjustCWr called with x,y=ox,oy - this can't happen!")
- end
- else
- if math.abs(dx) < math.abs(dy) then --north or south quadrant
- if dy < 0 then -- south quadrant
- newx=x+1
- newy=y+1
- else --north
- newx=x-1
- newy=y-1
- end
- else --east or west quadrant
- if dx < 0 then --west
- newy=y-1
- newx=x+1
- else
- newx=x-1
- newy=y+1
- end
- end
- end
- if (newx-ox==0 and math.abs(newy-oy)==1) or (newy-oy==0 and math.abs(newx-ox)==1) then
- newx,newy=newx*2,newy*2
- end
- return newx,newy
- end
- function AdjustCCWr(x,y,ox,oy,r)
- if r==1 then
- return AdjustCCW(x,y,ox,oy)
- end
- local newx,newy,dy,dx
- dx,dy=x-ox,y-oy
- if math.abs(dx) == math.abs(dy) then --we're on a diagonal, this could be a problem, so let's get off it!
- if dx < 0 then
- if dy < 0 then
- newx=x
- newy=y+1
- else
- newx=x+1
- newy=y
- end
- elseif dx > 0 then
- if dy < 0 then
- newy=y
- newx=x-1
- else
- newx=x
- newy=y-1
- end
- else --stacked, which should NEVER HAPPEN but has somehow happened anyway
- newx=x-1
- newy=y-1
- logappend("AAI_ERROR","AdjustCWr called with x,y=ox,oy - this can't happen!")
- end
- else
- if math.abs(dx) < math.abs(dy) then --north or south quadrant
- if dy < 0 then -- south quadrant
- newx=x-1
- newy=y+1
- else --north
- newx=x+1
- newy=y-1
- end
- else --east or west quadrant
- if dx < 0 then --west
- newy=y+1
- newx=x+1
- else
- newx=x-1
- newy=y-1
- end
- end
- end
- if (newx-ox==0 and math.abs(newy-oy)==1) or (newy-oy==0 and math.abs(newx-ox)==1) then
- newx,newy=newx*2,newy*2
- end
- return newx,newy
- end
- function AdjustOpp(x,y,ox,oy)
- dx=ox-x
- dy=oy-y
- return x+2*dx,y+2*dy
- end
- function ClosestR(myid,target,range,alt)
- local ox,oy=GetV(V_POSITION,target)
- return Closest(myid,ox,oy,range,alt)
- end
- --############################### ## ##
- --### LUA 5.1 feature support ### ## ##
- --############################### ## ##
- function DiagonalDist(distance)
- return math.floor(math.sqrt(distance*distance))
- end
- function GetDanceCell(x,y,enemy)
- local enemyx,enemyy=GetV(V_POSITION,enemy)
- if IsInAttackSight(MyID,enemy) == false then --Why is this being called?!
- logappend("AAI_ERROR","GetDanceCell() called when enemy out of range!" )
- x,y=Closest(MyID,enemyx,enemyy,1)
- return x,y
- end
- t = math.random(2)
- if t == 1 then
- return AdjustCW(x,y,enemyx,enemyy)
- elseif t == 2 then
- return AdjustCCW(x,y,enemyx,enemyy)
- else
- return AdjustOpp(x,y,enemyx,enemyy)
- end
- end
- --[[ --disabled for a simpler dance alog, because you can't dance any ranged attacks at the moment, so optimize for range=1
- function GetDanceCell(x,y,enemy)
- distance = GetDistance2(MyID,enemy)
- ex,ey=GetV(V_POSITION,enemy)
- s=(((math.random(2)-1)*2)-1)
- t=(((math.random(2)-1)*2)-1)
- if (GetDistance(x-s,y+t,ex,ey) == distance) then
- return x-s,y+t
- elseif (GetDistance(x,y+t,ex,ey) == distance) then
- return x,y+t
- elseif (GetDistance(x+s,y+t,ex,ey) == distance) then
- return x+s,y+t
- elseif (GetDistance(x-s,y,ex,ey) == distance) then
- return x-s,y
- elseif (GetDistance(x+s,y,ex,ey) == distance) then
- return x+s,y
- elseif (GetDistance(x-s,y-t,ex,ey) == distance) then
- return x-s,y-t
- elseif (GetDistance(x,y-t,ex,ey) == distance) then
- return x,y-t
- else
- return x+s,y-t
- end
- end
- ]]--]]
- --#########################
- --### GetSkill functions###
- --#########################
- function GetSAtkSkill(myid)
- local skill = 0
- local level = 0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,myid)
- if htype > 47 then -- it's a Homun S
- if htype==EIRA and UseEiraEraseCutter==1 then
- skill=MH_ERASER_CUTTER
- if EiraEraseCutterLevel==nil then
- level=4
- else
- level=EiraEraseCutterLevel
- end
- elseif htype==BAYERI and UseBayeriStahlHorn==1 then
- skill=MH_STAHL_HORN
- if BayeriStahlHornLevel==nil then
- level=5
- else
- level=BayeriStahlHornLevel
- end
- elseif htype==SERA and UseSeraParalyze==1 then
- skill=MH_NEEDLE_OF_PARALYZE
- if SeraParalyzeLevel==nil then
- level=5
- else
- level=SeraParalyzeLevel
- end
- elseif htype==ELEANOR and UseEleanorSonicClaw==1 and ( EleanorMode==0 or EleanorDoNotSwitchMode==1 ) then
- skill=MH_SONIC_CRAW
- if EleanorSonicClawLevel==nil then
- level=5
- else
- level=EleanorSonicClawLevel
- end
- elseif htype==ELEANOR and UseEleanorTinderBreaker==1 and EleanorMode==1 then
- skill=MH_TINDER_BREAKER
- if EleanorTinderBreakerLevel==nil then
- level=5
- else
- level=EleanorTinderBreakerLevel
- end
- end
- end
- if level ~=0 then
- return skill,level
- end
- end
- return 0,0
- end
- function GetComboSkill(myid)
- local skill = 0
- local level = 0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,myid)
- if htype==ELEANOR then
- if EleanorMode==0 or EleanorDoNotSwitchMode==1 then
- if ComboSCTimeout > GetTick() and MySpheres >= AutoComboSpheres then
- skill=MH_SILVERVEIN_RUSH
- if EleanorSilverveinLevel==nil then
- level=5
- else
- level=EleanorSilverveinLevel
- end
- elseif ComboSVTimeout > GetTick() then
- skill=MH_MIDNIGHT_FRENZY
- if EleanorMidnightLevel==nil then
- level=5
- else
- level=EleanorMidnightLevel
- end
- end
- end
- end
- if level ~=0 then
- return skill,level
- end
- end
- return 0,0
- end
- function GetGrappleSkill(myid)
- local skill = 0
- local level = 0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,myid)
- if htype==ELEANOR and MySpheres >= AutoComboSpheres then
- if EleanorMode==1 or EleanorDoNotSwitchMode==1 then
- if ComboSCTimeout > GetTick() then
- if MySpheres >= AutoComboSpheres -1 then
- skill=MH_CBC
- if EleanorCBCLevel==nil then
- level=5
- else
- level=EleanorCBCLevel
- end
- end
- elseif ComboSVTimeout > GetTick() then
- if MySpheres >= AutoComboSpheres -1 then
- skill=MH_EQC
- if EleanorEQCLevel==nil then
- level=5
- else
- level=EleanorEQCLevel
- end
- end
- elseif MySpheres >= AutoComboSpheres then
- skill=MH_TINDER_BREAKER
- if EleanorTinderBreakerLevel==nil then
- level=5
- else
- level=EleanorTinderBreakerLevel
- end
- end
- end
- end
- if level ~=0 then
- return skill,level
- end
- end
- return 0,0
- end
- function GetAtkSkill(myid)
- local skill = 0
- local level = 0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,myid)
- if htype < 17 then
- homuntype=modulo(GetV(V_HOMUNTYPE,myid),4)
- else
- homuntype=modulo(OldHomunType,4)
- end
- if (homuntype==0) then -- It's a vani!
- skill=HVAN_CAPRICE
- if GetTick() < AutoSkillCooldown[skill] then
- level=0
- skill=0
- elseif (VanCapriceLevel==nil) then
- level=5
- else
- level=VanCapriceLevel
- end
- elseif (homuntype==3) then -- It's a filer!
- skill=HFLI_MOON
- if GetTick() < AutoSkillCooldown[skill] then
- level=0
- skill=0
- elseif (FilerMoonlightLevel==nil) then
- level=5
- else
- level=FilerMoonlightLevel
- end
- end
- if level ~=0 then
- return skill,level
- end
- else
- for i,v in ipairs(AtkSkillList) do
- level = SkillList[MercType][v]
- if level ~= nil then
- skill=v
- return skill,level
- end
- end
- end
- return 0,0
- end
- function GetPushbackSkill(myid)
- if (IsHomun(myid)==1) then
- return 0,0
- else
- for i,v in ipairs(PushSkillList) do
- level = SkillList[MercType][v]
- if level ~= nil then
- skill=v
- return skill,level
- end
- end
- end
- return 0,0
- end
- function GetDebuffSkill(myid)
- if (IsHomun(myid)==1) then
- if GetV(V_HOMUNTYPE,MyID)==EIRA and UseEiraSilentBreeze==1 then
- skill=MH_SILENT_BREEZE
- if EiraSilentBreezeLevel==nil then
- level=5
- else
- level=EiraSilentBreezeLevel
- end
- return skill,level
- elseif GetV(V_HOMUNTYPE,MyID)==DIETER and UseDieterVolcanicAsh==1 then
- skill=MH_VOLCANIC_ASH
- level=5
- local t = GetTick()
- if (AshTimeout[1] < t or AshTimeout[2] < t or AshTimeout[3] < t) then
- return skill,level
- else
- return 0,0
- end
- end
- else
- for i,v in ipairs(DebuffSkillList) do
- level = SkillList[MercType][v]
- if level ~= nil then
- skill=v
- return skill,level
- end
- end
- end
- return 0,0
- end
- function GetMinionSkill(myid)
- local level,skill=0,0
- if (IsHomun(myid)==1) then
- if GetV(V_HOMUNTYPE,MyID)==SERA and UseSeraCallLegion==1 then
- skill=MH_SUMMON_LEGION
- TraceAI("GetMinionSkill"..skill)
- if SeraCallLegionLevel == nil then
- level=5
- elseif SeraCallLegionLevel < 1 then
- skill,level=0,0
- elseif SeraCallLegionLevel > 5 then
- level=5
- else
- level=SeraCallLegionLevel
- end
- TraceAI("GetMinionSkill "..skill..level)
- if AutoSkillCooldown[skill]~=nil then
- if GetTick() < AutoSkillCooldown[skill] then -- in cooldown
- level=0
- skill=0
- end
- end
- return skill,level
- end
- end
- return 0,0
- end
- function GetProvokeSkill(myid)
- if (IsHomun(myid)==1) then
- return 0,0
- else
- level=SkillList[MercType][MER_PROVOKE]
- if level ~=nil then
- return MER_PROVOKE,level
- end
- end
- return 0,0
- end
- function GetSacrificeSkill(myid)
- level=SkillList[MercType][ML_DEVOTION]
- if level ~=nil then
- return ML_DEVOTION,level
- end
- return 0,0
- end
- function GetMobSkill(myid)
- local skill = 0
- local level = 0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,MyID)
- if htype <17 then
- skill=0
- else -- it's a homun s
- if htype==EIRA and UseEiraXenoSlasher==1 then
- skill=MH_XENO_SLASHER
- if EiraXenoSlasherLevel==nil then
- level=4
- else
- level=EiraXenoSlasherLevel
- end
- elseif htype==BAYERI and UseBayeriHailegeStar==1 then
- skill=MH_HEILIGE_STANGE
- if BayeriHailegeStarLevel==nil then
- level=5
- else
- level=BayeriHailegeStarLevel
- end
- elseif htype==SERA and UseSeraPoisonMist==1 and PoisonMistMode==0 then
- skill=MH_POISON_MIST
- if SeraPoisonMistLevel==nil then
- level=5
- else
- level=SeraPoisonMistLevel
- end
- elseif htype==DIETER and UseDieterLavaSlide==1 and LavaSlideMode==0 then
- skill=MH_LAVA_SLIDE
- if DieterLavaSlideLevel==nil then
- level=5
- else
- level=DieterLavaSlideLevel
- end
- end
- if AutoSkillCooldown[skill]~=nil then
- if GetTick() < AutoSkillCooldown[skill] then -- in cooldown
- level=0
- skill=0
- end
- end
- end
- return skill,level
- else -- SO MUCH EASIER WHEN LEVEL ISN'T SELECTABLE!!!!
- for i,v in ipairs(MobSkillList) do
- level = SkillList[MercType][v]
- if level ~= nil then
- skill=v
- return skill,level
- end
- end
- end
- return 0,0
- end
- function GetQuickenSkill(myid)
- local level = 0
- local skill = 0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,myid)
- if htype < 17 then
- homuntype=modulo(GetV(V_HOMUNTYPE,myid),4)
- else
- homuntype=modulo(OldHomunType,4)
- end
- if (homuntype==1) then -- It's a lif!
- skill=HLIF_CHANGE
- level=3
- elseif (homuntype==3) then -- It's a filer!
- skill=HFLI_FLEET
- if (FilirFlitLevel==nil) then
- level=5
- else
- level=FilirFlitLevel
- end
- elseif (homuntype==2) then --it's an amistr
- skill=HAMI_BLOODLUST
- level=3
- end
- else
- level=SkillList[MercType][MER_QUICKEN]
- if level ~=nil then
- skill=MER_QUICKEN
- end
- end
- if AutoSkillCooldown[skill]~=nil then
- if GetTick() < AutoSkillCooldown[skill] then -- in cooldown
- level=0
- skill=0
- end
- end
- return skill,level
- end
- function GetSOffensiveSkill(myid)
- local level = 0
- local skill = 0
- local skillopt = 0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,myid)
- if (htype==BAYERI and UseBayeriAngriffModus~=0) then
- skill=MH_ANGRIFFS_MODUS
- level = 5
- skillopt=UseBayeriAngriffModus
- elseif (htype==DIETER and UseDieterMagmaFlow~=0) then
- skill=MH_MAGMA_FLOW
- level = 5
- skillopt=UseDieterMagmaFlow
- end
- return skill,level,skillopt
- else
- level=SkillList[MercType][MER_BLESSING]
- if level~=nil then
- skill=MER_BLESSING
- else
- level=0
- end
- return skill,level,UseBlessingSelf
- end
- end
- function GetSDefensiveSkill(myid)
- local level = 0
- local skill = 0
- local skillopt=0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,myid)
- if (htype==BAYERI and UseBayeriGoldenPherze~=0) then
- skill=MH_GOLDENE_FERSE
- level = 5
- skillopt=UseBayeriGoldenPherze
- elseif (htype==DIETER and UseDieterGraniticArmor~=0) then
- skill=MH_GRANITIC_ARMOR
- level = 5
- skillopt=UseDieterGraniticArmor
- end
- return skill,level,skillopt
- else
- level=SkillList[MercType][MER_KYRIE]
- if level~=nil then
- skill=MER_KYRIE
- else
- level=0
- end
- return skill,level,UseKyrieSelf
- end
- return 0,0,0
- end
- function GetSOwnerBuffSkill(myid)
- local level = 0
- local skill = 0
- local skillopt = 0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,myid)
- if (htype==EIRA and UseEiraOveredBoost~=0) then
- skill=MH_OVERED_BOOST
- level = 5
- skillopt=UseEiraOveredBoost
- elseif (htype==DIETER and UseDieterPyroclastic~=0) then
- skill=MH_PYROCLASTIC
- level = 5
- skillopt=UseDieterPyroclastic
- end
- return skill,level,skillopt
- else
- level=SkillList[MercType][MER_INCAGI]
- if level~=nil then
- skill=MER_INCAGI
- else
- level=0
- end
- return skill,level,UseIncAgiSelf
- end
- return 0,0,0
- end
- function GetSightOrAoE(myid)
- local level = 0
- local skill = 0
- local skillopt = 0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,myid)
- if (htype==DIETER and UseDieterLavaSlide==1 and LavaSlideMode~=0) then
- skill=MH_LAVA_SLIDE
- level = 5
- skillopt=LavaSlideMode
- elseif (htype==SERA and PoisonMistMode~=0 and UseSeraPoisonMist==1) then
- skill=MH_POISON_MIST
- level = 5
- skillopt=PoisonMistMode
- end
- else
- if MercType==2 then
- skill=MER_SIGHT
- level=1
- skillopt=UseAutoSight
- end
- end
- if AutoSkillCooldown[skill]~=nil then
- if GetTick() < AutoSkillCooldown[skill] then -- in cooldown
- level=0
- skill=skill
- end
- end
- return skill,level,skillopt
- end
- function GetGuardSkill(myid)
- local level = 0
- local skill = 0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,myid)
- if htype < 17 then
- homuntype=modulo(GetV(V_HOMUNTYPE,myid),4)
- else
- homuntype=modulo(OldHomunType,4)
- end
- if (homuntype==1) then -- It's a lif!
- skill=HLIF_AVOID
- if (LifEscapeLevel==nil) then
- level=5
- else
- level=LifEscapeLevel
- end
- elseif (homuntype==2) then -- It's an amistr!
- skill=HAMI_DEFENCE
- if (AmiBulwarkLevel==nil) then
- level=5
- else
- level=AmiBulwarkLevel
- end
- elseif (homuntype==3) then -- It's an filir!
- skill=HFLI_SPEED
- if (FilirAccelLevel==nil) then
- level=5
- else
- level=FilirAccelLevel
- end
- end
- return skill,level
- else
- for i,v in ipairs(GuardSkillList) do
- level = SkillList[MercType][v]
- if level ~= nil then
- skill=v
- return skill,level
- end
- end
- end
- return 0,0
- end
- function GetOffensiveOwnerSkill(myid)
- local level = 0
- local skill = 0
- local skillopt = 0
- if (IsHomun(myid)==1) then
- return 0,0,0
- else
- level=SkillList[MercType][MER_BLESSING]
- if level~=nil then
- skill=MER_BLESSING
- else
- level=0
- end
- return skill,level,UseBlessingOwner
- end
- end
- function GetDefensiveOwnerSkill(myid)
- local level = 0
- local skill = 0
- local skillopt = 0
- if (IsHomun(myid)==1) then
- if GetV(V_HOMUNTYPE,MyID)==SERA and UseSeraPainkiller~=0 then
- level=5
- return MH_PAIN_KILLER,level,UseSeraPainkiller
- else
- return 0,0,0
- end
- else
- level=SkillList[MercType][MER_KYRIE]
- if level~=nil then
- skill=MER_KYRIE
- else
- level=0
- end
- return skill,level,UseKyrieOwner
- end
- end
- function GetOtherOwnerSkill(myid)
- local level = 0
- local skill = 0
- local skillopt = 0
- if (IsHomun(myid)==1) then
- return 0,0,0
- else
- level=SkillList[MercType][MER_INCAGI]
- if level~=nil then
- skill=MER_INCAGI
- else
- level=0
- end
- return skill,level,UseIncAgiOwner
- end
- end
- function GetHealingSkill(myid)
- local level = 0
- local skill = 0
- if (IsHomun(myid)==1) then
- htype=GetV(V_HOMUNTYPE,myid)
- if htype < 17 then --if it's not a homun S just run it through modulo.
- homuntype=modulo(GetV(V_HOMUNTYPE,myid),4)
- else --If it's a homun S, get the OldHomunType
- if homuntype == EIRA and HealOwnerBreeze == 1 then --Handling for Eira silent breeze
- skill=MH_SILENT_BREEZE
- if GetTick() < AutoSkillCooldown[skill] then
- level=0
- else
- level=5
- end
- return skill,level
- end
- homuntype=modulo(OldHomunType,4)
- end
- if (homuntype==1) then -- It's a lif
- skill=HLIF_HEAL
- if GetTick() < AutoSkillCooldown[skill] then
- level=0
- elseif (LifHealLevel==nil) then
- level=5
- else
- level=LifHealLevel
- end
- elseif homuntype==0 then -- It's a vani
- skill=HVAN_CHAOTIC
- if GetTick() < AutoSkillCooldown[skill] then
- level=0
- elseif (VaniChaoticLevel==nil) then
- level=3
- else
- level=VaniChaoticLevel
- end
- end
- else
- --currently no merc healing skills
- end
- return skill,level
- end
- function GetSnipeSkill(myid)
- return GetAtkSkill(myid)
- end
- function GetTargetedSkills(myid)
- s,l=GetAtkSkill(myid)
- Mainatk={MAIN_ATK,s,l}
- s,l=GetSAtkSkill(myid)
- Satk={S_ATK,s,l}
- s,l=GetComboSkill(myid)
- ComboAtk={COMBO_ATK,s,l}
- s,l=GetGrappleSkill(myid)
- GrappleAtk={GRAPPLE_ATK,s,l}
- s,l=GetMobSkill(myid)
- Mobatk={MOB_ATK,s,l}
- s,l=GetDebuffSkill(myid)
- Debuffatk={DEBUFF_ATK,s,l}
- s,l=GetMinionSkill(myid)
- Minionatk={MINION_ATK,s,l}
- result={Mainatk,Satk,ComboAtk,GrappleAtk,Mobatk,Debuffatk,Minionatk}
- return result
- end
- function GetSkillInfo(skill,info,level)
- if skill~=nil and info~=nil then
- if SkillInfo[skill]~=nil then
- local t=SkillInfo[skill][info]
- if t~=nil then
- if level ==nil and type(t)=="table" then
- logappend("AAI_ERROR","Attempted to call GetSkillInfo() with only 2 arguments "..skill.." "..info)
- if type(t)~="table" and t~=nil then
- return t
- else
- return -1
- end
- elseif type(t)~="table" then
- return t
- elseif SkillInfo[skill][info][level]~=nil then
- return SkillInfo[skill][info][level]
- else
- logappend("AAI_ERROR","GetSkillInfo(): No skill info type "..info.." found for this level "..FormatSkill(skill,level))
- if info==2 then
- local r=0
- if (_VERSION=="Lua 5.1") then
- r=GetV(V_SKILLATTACKRANGE_LEVEL,MyID,skill,level)
- else
- r=GetV(V_SKILLATTACKRANGE,MyID,skill)
- end
- logappend("AAI_ERROR","GetSkillInfo(): Range for unknown skill requested, returning builtin value"..r.." "..skill)
- return r
- elseif SkillInfo[skill][info][1]~= nil then
- return SkillInfo[skill][info][1]
- else
- return 0
- end
- end
- else
- logappend("AAI_ERROR","GetSkillInfo(): No skill info type "..info.." found for this skill "..FormatSkill(skill,level).." called by ")
- if info==2 then
- logappend("AAI_ERROR","GetSkillInfo(): Range for unknown skill requested, returning builtin value"..GetV(V_SKILLATTACKRANGE,MyID,skill))
- return GetV(V_SKILLATTACKRANGE,MyID,skill)
- elseif info==7 then
- return 1
- else
- return 0
- end
- end
- else
- logappend("AAI_ERROR","GetSkillInfo(): No skill info found for this skill "..FormatSkill(skill,level).." info type requested "..info)
- if info==2 then
- logappend("AAI_ERROR","GetSkillInfo(): Range for unknown skill requested, returning builtin value"..GetV(V_SKILLATTACKRANGE,MyID,skill))
- return GetV(V_SKILLATTACKRANGE,MyID,skill)
- elseif info==7 then
- return 1
- else
- return 0
- end
- end
- else
- if skill==nil then
- skill="nil"
- end
- if level==nil then
- level="nil"
- end
- if info==nil then
- info="nil"
- end
- logappend("AAI_ERROR","GetSkillInfo(): Invalid arguments - skill="..skill.." level="..level.." info="..info)
- return 0
- end
- end
- --#######################
- --### Other Functions ###
- --#######################
- function KiteOK(myid)
- mertype=GetV(V_MERTYPE,myid)
- if (mertype==nil) then
- homuntype=modulo(GetV(V_HOMUNTYPE,myid),4)
- if ((homuntype==0 or homuntype==3 )and DoNotChase==1) then
- return 1
- else
- return 0
- end
- elseif (mertype < 11) then
- return 1
- else
- return 0
- end
- end
- function DoSkill(skill,level,target,mode,targx,targy)
- TraceAI("doskill called skill:"..skill.."level:"..level.."target"..target)
- if skill==0 or level==0 or skill==nil or level==nil then
- logappend("AAI_ERROR","doskill called skill:"..skill.."level:"..level.."target"..target.."mode"..mode.."state "..MyState.."pstate "..MyPState)
- return 0
- end
- targetmode=GetSkillInfo(skill,7)
- if skill==HFLI_SBR44 and AllowSBR44~=1 then
- logappend("AAI_ERROR","Attempt to use SBR 44 blocked. If you really want to use this, set AllowSBR44 = 1 in H_Extra")
- elseif targetmode==0 then
- SkillObject(MyID,level,skill,MyID)
- elseif targetmode==1 then
- SkillObject(MyID,level,skill,target)
- elseif targetmode==2 then
- if targx == nil then
- x,y=GetV(V_POSITION,target)
- SkillGround(MyID,level,skill,x,y)
- else
- SkillGround(MyID,level,skill,targx,targy)
- end
- end
- if mode~=nil then
- if mode > 0 then
- CastSkillMode=mode
- CastSkill=skill
- CastSkillLevel=level
- CastSkillTime=GetTick()
- CastSkillState=0
- logappend("AAI_SKILLFAIL", "Mode set "..mode.." skill "..skill.." level "..level)
- else --mode is negative, call the plugin mode handler.
- DoSkillHandleMode(skill,level,target,mode,targx,targy)
- logappend("AAI_SKILLFAIL", "Mode set "..mode.." skill "..skill.." level "..level)
- end
- end
- local t=GetTick();
- delay=AutoSkillDelay + GetSkillInfo(skill,4,level)+GetSkillInfo(skill,5,level)*CastTimeRatio
- AutoSkillCastTimeout=delay+t
- if AutoSkillCooldown[skill]~=nil then
- AutoSkillCooldown[skill]=t+GetSkillInfo(skill,9,level)+delay
- elseif (skill==MH_VOLCANIC_ASH) then --handle the three ash timeouts
- if (AshTimeout[1] < t) then
- AshTimeout[1]=t+GetSkillInfo(skill,9,level)+delay
- elseif (AshTimeout[2] < t) then
- AshTimeout[2]=t+GetSkillInfo(skill,9,level)+delay
- else
- AshTimeout[3]=t+GetSkillInfo(skill,9,level)+delay
- end
- end
- delay = delay + GetSkillInfo(skill,6,level)
- AutoSkillTimeout=t+delay
- if AutoSkillCooldown[skill]~=nil then
- TraceAI("DoSkill: "..skill.." level:"..level.." target:"..target.." mode:"..targetmode.." delay "..delay.." cooldown: "..AutoSkillCooldown[skill]-GetTick())
- else
- TraceAI("DoSkill: "..skill.." level:"..level.." target:"..target.." mode:"..targetmode.." delay "..delay)
- end
- if skill==MH_MIDNIGHT_FRENZY then
- MySpheres = math.max(0,MySpheres - 2)
- ComboSVTimeout=0
- UpdateTimeoutFile()
- elseif skill==MH_SILVERVEIN_RUSH then
- ComboSVTimeout=GetTick()+2000
- ComboSCTimeout=0
- MySpheres = math.max(0,MySpheres - 1)
- UpdateTimeoutFile()
- elseif skill==MH_SONIC_CRAW then
- ComboSCTimeout=GetTick()+2000
- ComboSVTimeout=0
- elseif skill==MH_TINDER_BREAKER then
- ComboSCTimeout=GetTick()+2000
- ComboSVTimeout=0
- MySpheres = math.max(0,MySpheres - 1)
- elseif skill==MH_CBC then
- ComboSVTimeout=GetTick()+2000
- ComboSCTimeout=0
- MySpheres = math.max(0,MySpheres - 1)
- elseif skill==MH_EQC then
- ComboSVTimeout=0
- ComboSCTimeout=0
- --No sphere use?
- else --Combo wasn't used, so kill the timeouts
- ComboSCTimeout=0
- ComboSVTimeout=0
- end
- TraceAI("DoSkill: "..skill.." level:"..level.." target:"..target.." mode:"..targetmode.." delay "..delay)
- logappend("AAI_SKILLFAIL", "DoSkill: "..skill.." level:"..level.." target:"..target.." mode:"..targetmode.." delay "..delay)
- return
- end
- function modtwroSend()
- if modtwROSkillGroundID~=0 then
- logappend("AAI_Lag","Calling skillground function")
- OldSkillGround(MyID,modtwROSkillGroundLV,modtwROSkillGroundID,modtwROSkillGroundX,modtwROSkillGroundY)
- LagReductionCD=LagReduction
- elseif modtwROSkillObjectID~=0 then
- logappend("AAI_Lag","Calling SkillObject function")
- OldSkillObject(MyID,modtwROSkillObjectLV,modtwROSkillObjectID,modtwROSkillObjectTarg)
- LagReductionCD=LagReduction
- else
- if modtwRODidMove==0 then
- if modtwROMoveX~=0 then
- logappend("AAI_Lag","Calling Move function, didmove=0")
- OldMove(MyID,modtwROMoveX,modtwROMoveY)
- LagReductionCD=LagReduction
- modtwRODidMove=1
- modtwRODidAttack=0
- end
- else
- modtwRODidMove=0
- end
- if modtwRODidAttack==0 then
- if modtwROAttackTarget~=0 then
- logappend("AAI_Lag","Calling attack function, didattack=0")
- OldAttack(MyID,modtwROAttackTarget)
- LagReductionCD=LagReduction
- modtwRODidAttack=1
- end
- else
- modtwRODidAttack=0
- end
- end
- modtwROSkillGroundLV,modtwROSkillGroundID,modtwROSkillGroundX,modtwROSkillGroundY,modtwROSkillObjectLV,modtwROSkillObjectID,modtwROSkillObjectTarg,modtwROAttackTarget=0,0,0,0,0,0,0,0
- modtwROAttackTarget,modtwROMoveX,modtwROMoveY=0,0,0
- end
- -- I SHOULDNT HAVE TO CODE THIS!
- function modulo(a,b)
- return a-math.floor(a/b)*b
- end
- -- OR THIS!
- function len(listin)
- local length=0
- for k,v in pairs(listin) do
- length = length + 1
- end
- return length
- end
- function absceil(x)
- if x>0 then
- return math.ceil(x)
- else
- return math.floor(x)
- end
- end
- function absunit(x)
- if x==0 then
- return 0
- elseif x > 0 then
- return 1
- else -- x < 0
- return -1
- end
- end
- -- Logging functions:
- function FormatSkill(skill,level)
- if skill==nil then
- return "nil skill"
- end
- local output
- local name
- if SkillInfo[skill]==nil then
- name=skill
- elseif SkillInfo[skill][1]==nil then
- name=skill
- else
- name=SkillInfo[skill][1]
- end
- output = name.." ("..skill..")"
- if level == nil then
- return output
- else
- return output.." level "..level
- end
- end
- function FormatMotion(motion)
- if motion==0 then
- return "Standing ("..motion..")"
- elseif motion==1 then
- return "Moving ("..motion..")"
- elseif motion==2 or motion==9 then
- return "Attacking ("..motion..")"
- elseif motion==3 then
- return "Dead ("..motion..")"
- elseif motion==4 then
- return "Flinching ("..motion..")"
- elseif motion==5 then
- return "Bending over ("..motion..")"
- elseif motion==6 then
- return "Sitting ("..motion..")"
- elseif motion==7 then
- return "Using skill ("..motion..")"
- elseif motion==8 then
- return "Casting ("..motion..")"
- else
- return motion
- end
- end
- function formatval (val)
- if val == nil then
- return "nil"
- elseif type(val)=="string" then
- return "'"..val.."'"
- elseif type(val)=="function" then
- return "function"
- end
- return val
- end
- function logappend (filename,message)
- if LogEnable[filename]==1 then
- TraceAI("Logging "..filename.." - "..message)
- outfile = io.open("./"..filename..".log", "a")
- outfile:seek("end")
- if filename=="AAI_SKILLFAIL" then
- outfile:write(os.date("%c").." ("..GetTick()..") "..TypeString..MyState.."\t"..message.."\n")
- else
- outfile:write(os.date("%c").." "..TypeString..MyState.."\t"..message.."\n")
- end
- outfile:close()
- end
- end
- function formatmypos(steps)
- if steps>10 then
- logappend("AAI_ERROR","Invalid number of steps called for formatmypos() "..steps)
- steps=10
- elseif steps <1 then
- logappend("AAI_ERROR","Invalid number of steps called for formatmypos() "..steps)
- steps=1
- end
- local outstring=""
- for v=1,steps,1 do
- outstring=outstring.."("..MyPosX[v]..","..MyPosY[v]..")"
- if v~=step then
- outstring=outstring..","
- end
- end
- return outstring
- end
- function formatpos(x,y)
- return x..","..y
- end
- --------------------------------------------
- -- List utility
- --------------------------------------------
- List = {}
- function List.new ()
- return { first = 0, last = -1}
- end
- function List.pushleft (list, value)
- local first = list.first-1
- list.first = first
- list[first] = value;
- end
- function List.pushright (list, value)
- local last = list.last + 1
- list.last = last
- list[last] = value
- end
- function List.popleft (list)
- local first = list.first
- if first > list.last then
- return nil
- end
- local value = list[first]
- list[first] = nil -- to allow garbage collection
- list.first = first+1
- return value
- end
- function List.popright (list)
- local last = list.last
- if list.first > last then
- return nil
- end
- local value = list[last]
- list[last] = nil
- list.last = last-1
- return value
- end
- function List.clear (list)
- for i,v in ipairs(list) do
- list[i] = nil
- end
- --[[
- if List.size(list) == 0 then
- return
- end
- local first = list.first
- local last = list.last
- for i=first, last do
- list[i] = nil
- end
- --]]
- list.first = 0
- list.last = -1
- end
- function List.size (list)
- local size = list.last - list.first + 1
- return size
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement