local attackdamage = {} --how far away the character can attack from local attackrange = 100 --how much damage the attacks do attackdamage[1] = 10 attackdamage[2] = 15 --store the animation frames here --allows multiple animations for the same action, it will pick 1 randomly --so idle[1] and idle[2] are different animations etc --idle[1][1] is the start frame of the first idle animation --idle[2][1] is the start frame of the second idle animation --idle[1][2] is the end frame of the first idle animation --attack[1][3] is the frame to apply damage after local idle = {} idle[1] = {} idle[1][1] = 12 idle[1][2] = 69 local walk = {} walk[1] = {} walk[1][1] = 270 walk[1][2] = 302 local run = {} run[1] = {} run[1][1] = 426 run[1][2] = 449 local stepright = {} stepright[1] = {} stepright[1][1] = 351 stepright[1][2] = 380 stepright[2] = {} stepright[2][1] = 351 stepright[2][2] = 364 local stepleft = {} stepleft[1] = {} stepleft[1][1] = 386 stepleft[1][2] = 416 stepleft[2] = {} stepleft[2][1] = 386 stepleft[2][2] = 403 local attack = {} attack[1] = {} attack[1][1] = 808 attack[1][2] = 867 attack[1][3] = 837 attack[2] = {} attack[2][1] = 875 attack[2][2] = 925 attack[2][3] = 898 local duck = {} duck[1] = {} duck[1][1] = 928 duck[1][2] = 995 ai_bot_state = {} local pathindex = {} local pathpoint = {} local pathdirection = {} local destx = {} local desty = {} local destz = {} local anim = {} local hitplayer = {} local dodgedrecently = {} local movemod = {} U = U or require "scriptbank\\utillib" function ai_zombie_priest_init(e) SetPreExitValue(e,0) CharacterControlManual(e) --CharacterControlLimbo(e) local AIObjNo = g_Entity[e]['obj'] AISetEntityControl(AIObjNo,AI_MANUAL) SetCharacterSoundSet(e) ai_bot_oldhealth[e] = g_Entity[e]['health'] ai_bot_state[e] = "idle" end function ai_zombie_priest_main(e) local ent = g_Entity[e] local state = ai_bot_state[e] local AIObjNo = ent.obj if state == "idle" then pathindex[e], pathpoint[e], pathdirection[e] = FindPath(e) if pathindex[e] > -1 then ai_bot_state[e] = "patrol" else ai_bot_state[e] = "idling" end destx[e] = ent.x desty[e] = ent.y destz[e] = ent.z movemod[e] = 1 dodgedrecently[e] = 60 elseif state == "idling" then if ent.animating ~= 1 then ModulateSpeed(e,1) anim[e] = math.random(1,#idle) SetAnimationFrames(idle[anim[e]][1],idle[anim[e]][2]) PlayAnimation(e) g_Entity[e]['animating'] = 1 end if DectectPlayer(e) == 1 then ai_bot_state[e] = "alerted" end elseif state == "patrol" then destx[e], desty[e], destz[e] = FollowPath(e) if ent.animating ~= 2 then ModulateSpeed(e,1) anim[e] = math.random(1,#walk) SetAnimationFrames(walk[anim[e]][1],walk[anim[e]][2]) LoopAnimation(e) g_Entity[e]['animating'] = 2 end if DectectPlayer(e) == 1 then ai_bot_state[e] = "alerted" end elseif state == "alerted" then PlayCharacterSound(e,"onAlert") ai_bot_state[e] = "move to attack" elseif state == "move to attack" then destx[e] = g_PlayerPosX desty[e] = g_PlayerPosY destz[e] = g_PlayerPosZ if ent.animating ~= 3 then ModulateSpeed(e,1.4) anim[e] = math.random(1,#run) SetAnimationFrames(run[anim[e]][1],run[anim[e]][2]) LoopAnimation(e) g_Entity[e]['animating'] = 3 end dodgedrecently[e] = dodgedrecently[e] - 1 local rnd = 0 if U.PlayerLookingAtObj(AIObjNo, AIGetEntityViewRange(AIObjNo), 0) == true then if math.random(0,60) == 60 or ent.health < ai_bot_oldhealth[e] or dodgedrecently[e] < 1 then rnd = math.random(-6,#stepleft) if rnd > 0 then anim[e] = math.random(1,#stepleft) ModulateSpeed(e,1.5) SetAnimationFrames(stepleft[anim[e]][1],stepleft[anim[e]][2]) local x1,y1,z1 = GetEntityPosAng(e) local ay = g_PlayerAngY+180 local ox,oy,oz = U.Rotate3D(-AIGetEntitySpeed(AIObjNo),0,AIGetEntitySpeed(AIObjNo)/4, 0,math.rad(ay),0) destx[e] = x1+ox desty[e] = y1+oy destz[e] = z1+oz movemod[e] = 2 else rnd = math.random(-4,#stepright) if rnd > 0 then ModulateSpeed(e,1.5) anim[e] = math.random(1,#stepright) SetAnimationFrames(stepright[anim[e]][1],stepright[anim[e]][2]) local x1,y1,z1 = GetEntityPosAng(e) local ay = g_PlayerAngY+180 local ox,oy,oz = U.Rotate3D(AIGetEntitySpeed(AIObjNo),0,AIGetEntitySpeed(AIObjNo)/4, 0,math.rad(ay),0) destx[e] = x1+ox desty[e] = y1+oy destz[e] = z1+oz movemod[e] = 2 else rnd = math.random(-1,#duck) if rnd > 0 then ModulateSpeed(e,2.5) anim[e] = math.random(1,#duck) SetAnimationFrames(duck[anim[e]][1],duck[anim[e]][2]) local x1,y1,z1 = GetEntityPosAng(e) local ay = g_PlayerAngY+180 local ox,oy,oz = U.Rotate3D(0,0,AIGetEntitySpeed(AIObjNo)/4,0,math.rad(ay),0) destx[e] = x1+ox desty[e] = y1+oy destz[e] = z1+oz movemod[e] = 0.1 end end end if rnd > 0 then dodgedrecently[e] = 60 PlayAnimation(e) g_Entity[e]['animating'] = 5 ai_bot_state[e] = "dodging" end end end if GetPlayerDistance(e) < attackrange and ent.plrvisible == 1 and rnd < 1 then ai_bot_state[e] = "attack" end elseif state == "dodging" then if ent.animating == 0 then movemod[e] = 1 ai_bot_state[e] = "move to attack" end elseif state == "attack" then destx[e] = ent.x desty[e] = ent.y destz[e] = ent.z hitplayer[e] = false if ent.animating ~= 4 then ModulateSpeed(e,1) anim[e] = math.random(1,#attack) SetAnimationFrames(attack[anim[e]][1],attack[anim[e]][2]) PlayAnimation(e) g_Entity[e]['animating'] = 4 end ai_bot_state[e] = "attacking" elseif state == "attacking" then if ent.animating == 0 then ai_bot_state[e] = "idle" elseif GetAnimationFrame(e) >= attack[anim[e]][3] and not hitplayer[e] then HurtPlayer(e, attackdamage[anim[e]]) hitplayer[e] = true end end --triple damage for a headshot if string.find(string.lower(ent.limbhit), "head") ~= nil then SetEntityHealth(e,ent.health-(ai_bot_oldhealth[e]-ent.health)*2) ResetLimbHit(e) end AIEntityGoToPosition(AIObjNo, destx[e], desty[e], destz[e]) local movespeed = AIGetEntitySpeed(AIObjNo) if state == "idling" then elseif state ~= "attacking" then if state ~= "dodging" then RotateToPointSlowly(e, destx[e], destz[e], movespeed / 20) else RotateToPointSlowly(e, destx[e], destz[e], movespeed / 250) end SetRotation(e,0,AIGetEntityAngleY(AIObjNo),0) MoveForward(e,movespeed * movemod[e]) else RotateToPlayer(e) end AISetEntityPosition(AIObjNo,GetEntityPositionX(e),GetEntityPositionY(e),GetEntityPositionZ(e)) if ent.health < ai_bot_oldhealth[e] then ai_bot_oldhealth[e] = ent.health end --PromptLocal(e,state.." : ".."health = "..ent.health.." pos = "..destx[e].." , "..destz[e].." , anim frame = "..GetAnimationFrame(e)) end function ai_zombie_priest_preexit(e) SetPreExitValue(e,1) PlayCharacterSound(e,"onDeath") SetPreExitValue(e,2) end function ai_zombie_priest_exit(e) CollisionOff(e) end function DectectPlayer(e) local playerdist = GetPlayerDistance(e) local AIObjNo = g_Entity[e]['obj'] if (playerdist < AIGetEntityViewRange(AIObjNo) and g_Entity[e]['plrvisible'] == 1) or AIGetEntityHeardSound(AIObjNo) == 1 or playerdist < AIGetEntityViewRange(AIObjNo) * 0.25 then return 1 else return 0 end end function FindPath(e) local pi = -1 local pp = 0 local pClosest = 999999 for pa = 1, AIGetTotalPaths(), 1 do for po = 1 , AIGetPathCountPoints(pa), 1 do local pDX = g_Entity[e]['x'] - AIPathGetPointX(pa,po) local pDZ = g_Entity[e]['z'] - AIPathGetPointZ(pa,po) local pDist = pDX*pDX+pDZ*pDZ if pDist < pClosest and pDist < 6000 then pClosest = pDist pi = pa pp = po end end -- po end -- pa local pd = math.random(0,1) return pi, pp, pd end function FollowPath(e) local px = AIPathGetPointX(pathindex[e],pathpoint[e]) local pz = AIPathGetPointZ(pathindex[e],pathpoint[e]) local tDistX = g_Entity[e]['x'] - px local tDistZ = g_Entity[e]['z'] - pz local DistFromPath = tDistX*tDistX+tDistZ*tDistZ if DistFromPath < 4000 then if pathdirection[e] == 1 then pathpoint[e] = pathpoint[e] + 1 local maxp = AIGetPathCountPoints(pathindex[e]) if pathpoint[e] > maxp then pathpoint[e] = maxp - 1 pathdirection[e] = 0 end else pathpoint[e] = pathpoint[e] - 1 if pathpoint[e] < 1 then pathpoint[e] = 2 pathdirection[e] = 1 end end px = AIPathGetPointX(pathindex[e],pathpoint[e]) pz = AIPathGetPointZ(pathindex[e],pathpoint[e]) end local py = GetTerrainHeight(px,pz) return px,py,pz end function RotateToPoint(e,x,z) if g_Entity[e] ~= nil and x > 0 and z > 0 then local destx = x - g_Entity[e]['x'] local destz = z - g_Entity[e]['z'] local angle = math.atan2(destx,destz) angle = angle * (180.0 / math.pi) if angle < 0 then angle = 360 + angle elseif angle > 360 then angle = angle - 360 end SetRotation(e,0,angle,0) return angle end end function RotateToPointSlowly(e,x,z,v) if g_Entity[e] ~= nil and x > 0 and z > 0 then if v == nil then v = 1 end local destx = x - g_Entity[e]['x'] local destz = z - g_Entity[e]['z'] local angleneeded = math.atan2(destx,destz) angleneeded = angleneeded * (180.0 / math.pi) if angleneeded < 0 then angleneeded = 360 + angleneeded elseif angleneeded > 360 then angleneeded = angleneeded - 360 end local current_angy = g_Entity[e]['angley'] while current_angy < 0 or current_angy > 360 do if current_angy <= 0 then current_angy = 360 + current_angy elseif current_angy > 360 then current_angy = current_angy - 360 end end local L = angleneeded - v local R = angleneeded + v if L <= 0 then L = 360 + L elseif L > 360 then L = L - 360 end if R <= 0 then R = 360 + R elseif R > 360 then R = R - 360 end --if not already facing the target direction (+/- the rotation speed) if current_angy < L or current_angy > R then --do it in 2 halfs so we can account for 0/360 wrap if current_angy > 180 then if angleneeded > current_angy - 180 and angleneeded < current_angy then current_angy = current_angy - v else current_angy = current_angy + v end else if angleneeded < current_angy + 180 and angleneeded > current_angy then current_angy = current_angy + v else current_angy = current_angy - v end end SetRotation(e,0,current_angy,0) return current_angy end end end