-- COMBATCORE Common Module -- anim0 : Idle -- anim1 : Move -- anim2 : Punch/Kick/Bite -- anim3 : Hurt -- anim4 : Reload -- anim5 : Punch/Kick/Bite Damage Frames -- anim6 : Dying -- anim7 : Stood to Duck -- anim8 : Duck Idle -- anim9 : Duck to Stood -- anim10 : Run/Dash -- anim11 : Roll to Duck -- anim12 : Fast Crouch Dash -- anim13 : idle sentry -- anim14 : relaxed move -- anim15 : strafe left -- anim16 : strafe right -- sound0 : Start moving A -- sound1 : Start strike -- sound2 : Start moving B -- sound3 : Get hurt A -- sound4 : Get hurt B local abs = math.abs local sin = math.sin local cos = math.cos local atan = math.atan2 local sqrt = math.sqrt local random = math.random local module_core = require "scriptbank\\ai\\module_core" local module_agro = require "scriptbank\\ai\\module_agro" local module_cameraoverride = require "scriptbank\\ai\\module_cameraoverride" local module_combateffects = require "scriptbank\\ai\\module_combateffects" local P = require "scriptbank\\physlib" local U = require "scriptbank\\utillib" ai_bot_newroty = {} local module_combatcore = {} local oldx,oldz = {},{} velox,veloz = {},{} local avoid_time = {} function module_combatcore.init( e, startstate, coverstate ) Include( "physlib.lua" ) Include( "utillib.lua" ) local Ent = g_Entity[ e ] CharacterControlManual( e ) AISetEntityControl( Ent.obj, AI_MANUAL ) ai_bot_oldhealth[ e ] = Ent.health ai_bot_coverindex[ e ] = coverstate ai_bot_state[ e ] = startstate ai_bot_substate[ e ] = 0 ai_bot_targetx[ e ] = nil ai_bot_pointtime[ e ] = -1 ai_bot_patroltime[ e ] = 0 ai_bot_targetx[ e ] = Ent.x ai_bot_targety[ e ] = Ent.y ai_bot_targetz[ e ] = Ent.z ai_bot_closeenoughx[ e ] = 0 ai_bot_closeenoughy[ e ] = 0 ai_bot_closeenoughz[ e ] = 0 ai_bot_gofast[ e ] = 0 ai_bot_sighting[ e ] = 0 oldx[ e ] = Ent.x oldz[ e ] = Ent.z velox[ e ] = 0 veloz[ e ] = 0 avoid_time[ e ] = 0 -- populate animation data if entity file does not provide it (except 5 and 6 which are melee) if GetEntityAnimationFound( e, 0 ) == 0 then SetEntityAnimation( e, 0, 100, 205 ) end if GetEntityAnimationFound( e, 1 ) == 0 then SetEntityAnimation( e, 1, 685, 707 ) end if GetEntityAnimationFound( e, 2 ) == 0 then SetEntityAnimation( e, 2, 5511, 5553 ) end if GetEntityAnimationFound( e, 3 ) == 0 then SetEntityAnimation( e, 3, 4812, 4850 ) end if GetEntityAnimationFound( e, 4 ) == 0 then SetEntityAnimation( e, 4, 515, 605 ) end if GetEntityAnimationFound( e, 7 ) == 0 then SetEntityAnimation( e, 7, 1630, 1646 ) end if GetEntityAnimationFound( e, 8 ) == 0 then SetEntityAnimation( e, 8, 1670, 1819 ) end if GetEntityAnimationFound( e, 9 ) == 0 then SetEntityAnimation( e, 9, 1646, 1663 ) end if GetEntityAnimationFound( e, 10 ) == 0 then SetEntityAnimation( e, 10, 795, 811 ) end if GetEntityAnimationFound( e, 11 ) == 0 then SetEntityAnimation( e, 11, 2160, 2218 ) end if GetEntityAnimationFound( e, 12 ) == 0 then SetEntityAnimation( e, 12, 2135, 2153 ) end if GetEntityAnimationFound( e, 13 ) == 0 then SetEntityAnimation( e, 13, 900, 999 ) end if GetEntityAnimationFound( e, 14 ) == 0 then SetEntityAnimation( e, 14, 1290, 1320 ) end if GetEntityAnimationFound( e, 15 ) == 0 then SetEntityAnimation( e, 15, 610, 640 ) end if GetEntityAnimationFound( e, 16 ) == 0 then SetEntityAnimation( e, 16, 645, 676 ) end end function module_combatcore.findcover( e, x, y, z ) local ppx, ppz = g_PlayerPosX, g_PlayerPosZ local CoverIndex = -1 local tdx, tdz = x - ppx, z - ppz local SqDistToPlayer = tdx * tdx + tdz * tdz for prefer = 1, 2 do local SqClosest = math.huge for ca = 1, AIGetTotalCover(), 1 do local cpX, cpZ = AICoverGetPointX( ca ), AICoverGetPointZ( ca ) local pDX, pDz = x - cpX, z - cpZ local SqDistToCover = pDX * pDX + pDZ * pDZ if SqDistToCover < SqClosest and SqDistToCover < SqDistToPlayer and SqDistToCover < 3000 * 3000 then -- also reject cover that is 'further away' from player than the enemy tdx, tdz = cpX - ppx, cpZ - ppz SqPlayerCoverDist = tdx * tdx + tdz * tdz if SqPlayerCoverDist <= SqDistToPlayer then -- reject cover if facing away from player direction tdx, tdz = ppx - cpX, ppz - cpZ local tPlayerCoverAngle = ( atan( tdx, tdz ) / 6.28 ) * 360 local tanglediff = tPlayerCoverAngle - AICoverGetAngle( ca ) if tanglediff < -180 then tanglediff = tanglediff + 360 end if tanglediff > 180 then tanglediff = tanglediff - 360 end if abs( tanglediff ) < 90 then local tchoosethis = false if prefer == 1 and ai_cover_slot[ ca ] == nil then tchoosethis = true end if prefer == 2 and ai_cover_slot[ ca ] ~= nil then tchoosethis = true end if tchoosethis then SqClosest = SqDistToCover CoverIndex = ca end end end end end if prefer == 1 and CoverIndex ~= -1 then return CoverIndex end end return CoverIndex end function module_combatcore.atcover( e ) local Ent = g_Entity[ e ] local CoverIndex = ai_bot_coverindex[ e ] if CoverIndex ~= -1 then tdx = AICoverGetPointX( CoverIndex ) - Ent.x tdz = AICoverGetPointZ( CoverIndex ) - Ent.z if tdx * tdx + tdz * tdz < 125 * 125 then return 1 end end return 0 end function module_combatcore.claimcover( e, slot ) ai_cover_slot[ slot ] = e ai_bot_coverindex[ e ] = slot end function module_combatcore.releasecover( e ) local slot = ai_bot_coverindex[ e ] if slot > 0 then ai_cover_slot[ slot ] = nil end ai_bot_coverindex[ e ] = -2 end function module_combatcore.findandassigncover( e, AIObjNo, PlayerDist ) local Ent = g_Entity[ e ] local tcoverassigned = 0 if ai_bot_coverindex[e] == -1 then local coverslot = module_combatcore.findcover( e, Ent.x, Ent.y, Ent.z ) if coverslot > 0 then module_combatcore.claimcover( e, coverslot ) ai_bot_targetx[ e ] = AICoverGetPointX( ai_bot_coverindex[ e ] ) ai_bot_targety[ e ] = g_PlayerPosY ai_bot_targetz[ e ] = AICoverGetPointZ( ai_bot_coverindex[ e ] ) tcoverassigned = 1 end end if ai_bot_coverindex[ e ] < 0 then module_combatcore.releasecover( e ) end if ai_bot_coverindex[ e ] == -2 and PlayerDist < AIGetEntityViewRange( AIObjNo ) then ai_bot_targetx[ e ] = g_PlayerPosX ai_bot_targety[ e ] = g_PlayerPosY ai_bot_targetz[ e ] = g_PlayerPosZ end return tcoverassigned end function module_combatcore.detectplayer( e, AIObjNo, PlayerDist, CanFire, detectstate ) local Ent = g_Entity[ e ] if ( PlayerDist < AIGetEntityViewRange( AIObjNo ) and ( Ent.plrvisible == 1 or ai_bot_coverindex[ e ] == -2 ) ) or Ent.activated == 2 then if Ent.activated == 2 then ai_bot_targetx[ e ] = g_PlayerPosX ai_bot_targety[ e ] = g_PlayerPosY ai_bot_targetz[ e ] = g_PlayerPosZ ai_bot_substate[ e ] = 0 SetActivated( e, 0 ) elseif module_combatcore.findandassigncover( e, AIObjNo, PlayerDist ) == 1 then AIEntityGoToPosition( AIObjNo, ai_bot_targetx[ e ], ai_bot_targety[ e ], ai_bot_targetz[ e ] ) ai_bot_state[ e ] = ai_state_startmove ai_bot_substate[ e ] = 0 end if ai_bot_targetx[ e ] ~= nil then if ai_bot_substate[ e ] == 0 then if module_combatcore.getcomfortdistance( e ) < 25 then RotateToPlayerSlowly( e, 1.0 ) else AIEntityGoToPosition( AIObjNo, ai_bot_targetx[ e ], ai_bot_targety[ e ], ai_bot_targetz[ e ] ) if AIGetEntityIsMoving( AIObjNo ) == 1 then ai_bot_state[ e ] = detectstate PlaySound( e, 0 + ( random( 0, 1 ) * 2 ) ) elseif Ent.plrvisible == 1 then RotateToPlayer( e ) if CanFire == 1 then module_combatcore.fireweapon( e ) end ai_bot_targetx[ e ] = g_PlayerPosX ai_bot_targety[ e ] = g_PlayerPosY ai_bot_targetz[ e ] = g_PlayerPosZ AIEntityGoToPosition( AIObjNo, ai_bot_targetx[ e ], ai_bot_targety[ e ], ai_bot_targetz[ e ] ) end end end end end end function module_combatcore.getcomfortdistance( e ) local dx = ai_bot_closeenoughx[e] - g_PlayerPosX local dy = ai_bot_closeenoughy[e] - g_PlayerPosY local dz = ai_bot_closeenoughz[e] - g_PlayerPosZ return sqrt( dx * dx + dy * dy + dz * dz ) end function module_combatcore.idle( e, AIObjNo, PlayerDist, CanFire, detectstate, combattype ) CharacterControlManual( e ) AISetEntityControl( AIObjNo, AI_MANUAL ) if ai_bot_state[ e ] == ai_state_startidle then ai_bot_state[ e ] = ai_state_idle if combattype == ai_combattype_regular then SetAnimation( 13 ) else SetAnimation( 0 ) end LoopAnimation( e ) SetAnimationSpeedModulation( e, 1.0 ) end if ai_bot_state[ e ] == ai_state_idle then module_combatcore.detectplayer( e, AIObjNo, PlayerDist, CanFire, detectstate ) module_combatcore.donotmove( e ) end if g_Entity[ e ].plrvisible == 0 and PlayerDist < 200 then ai_bot_state[ e ] = ai_state_idle SetAnimation( 0 ) CanFire = 0 module_combatcore.donotmove( e ) end end function module_combatcore.patrol( e, AIObjNo, PlayerDist, MoveType, CanFire, detectstate, stopstate, combattype ) local Ent = g_Entity[ e ] if ai_bot_pointtime[ e ] == -1 then ai_bot_pointtime[ e ] = 0 StartTimer( e ) end if ai_bot_state[ e ] == ai_state_findpatrolpath and ai_bot_pointtime[ e ] == 0 then local PathIndex = -1 local PointIndex = 2 local SqClosest = math.huge for pa = 1, AIGetTotalPaths() do for po = 1, AIGetPathCountPoints( pa ) do local pDX = Ent.x - AIPathGetPointX( pa, po ) local pDY = Ent.y - AIPathGetPointY( pa, po ) local pDZ = Ent.z - AIPathGetPointZ( pa, po ) SqDist = pDX * pDX + pDY * pDY + pDZ * pDZ if SqDist < SqClosest and SqDist < 200 * 200 then SqClosest = SqDist PathIndex = pa PointIndex = po end end -- po end -- pa ai_bot_pathindex[ e ] = PathIndex if PathIndex > -1 then ai_bot_state[ e ] = ai_state_startpatrol ai_bot_pointdirection[ e ] = 1 ai_bot_pointindex[ e ] = PointIndex ai_bot_pointmax[ e ] = AIGetPathCountPoints( PathIndex ) else ai_bot_state[e] = ai_state_startidle end end if ai_bot_state[ e ] == ai_state_startpatrol then if ai_bot_pathindex[ e ] ~= -1 then ai_bot_state[ e ] = ai_state_patrol ai_bot_pointtime[ e ] = g_Time + 100 AISetEntityMoveBoostPriority( AIObjNo ) SetAnimationSpeedModulation( e, 0.0 ) if combattype == ai_combattype_regular then SetAnimation( 14 ) else SetAnimation( 1 ) end LoopAnimation( e ) StartTimer( e ) else ai_bot_state[ e ] = ai_state_idle if combattype == ai_combattype_regular then SetAnimation( 13 ) else SetAnimation( 0 ) end LoopAnimation( e ) SetAnimationSpeedModulation( e, 1.0 ) end end if ai_bot_state[ e ] == ai_state_patrol then local patrolx = AIPathGetPointX( ai_bot_pathindex[ e ], ai_bot_pointindex[ e ] ) local patroly = AIPathGetPointY( ai_bot_pathindex[ e ], ai_bot_pointindex[ e ] ) local patrolz = AIPathGetPointZ( ai_bot_pathindex[ e ], ai_bot_pointindex[ e ] ) module_combatcore.moveandavoid( e, AIObjNo, PlayerDist, MoveType, patrolx, patroly, patrolz, stopstate ) if AIGetEntityIsMoving( AIObjNo ) == 1 then if GetAnimationSpeedModulation( e ) == 0.0 then SetAnimationSpeedModulation( e, 0.1 ) else local tWalkDelta = GetMovementDelta( e ) * 2.0 if tWalkDelta > 0.9 then tWalkDelta = 0.9 end SetAnimationSpeedModulation( e, 0.1 + tWalkDelta ) end end local tDistX = Ent.x - patrolx local tDistZ = Ent.z - patrolz local VertDist = abs( Ent.y - patroly ) local SqDistFromPath = tDistX * tDistX + tDistZ * tDistZ if SqDistFromPath < 25 * 25 and VertDist < 95 and g_Time > ai_bot_pointtime[ e ] then ai_bot_pointtime[ e ] = g_Time + 100 AISetEntityMoveBoostPriority( AIObjNo ) StartTimer( e ) if ai_bot_pointdirection[ e ] == 1 then ai_bot_pointindex[ e ] = ai_bot_pointindex[ e ] + 1 if ai_bot_pointindex[ e ] > ai_bot_pointmax[ e ] then ai_bot_pointindex[ e ] = ai_bot_pointmax[ e ] -1 ai_bot_pointdirection[ e ] = 0 end else ai_bot_pointindex[ e ] = ai_bot_pointindex[ e ] - 1 if ai_bot_pointindex[ e ] < 1 then ai_bot_pointindex[ e ] = 2 ai_bot_pointdirection[ e ] = 1 end end end module_combatcore.detectplayer( e, AIObjNo, PlayerDist, CanFire, detectstate ) end end function module_combatcore.hunt( e, AIObjNo, PlayerDist, MoveType, CanFire, stopstate ) local Ent = g_Entity[ e ] if ai_bot_state[ e ] == ai_state_startmove then ai_bot_state[ e ] = ai_state_move local Sqdist = 0 if ai_bot_targetx[ e ] ~= nil then tdX = Ent.x - ai_bot_targetx[ e ] tdZ = Ent.z - ai_bot_targetz[ e ] Sqdist = tdX * tdX + tdZ * tdZ end if Sqdist > 200 * 200 then ai_bot_gofast[ e ] = Timer() else ai_bot_gofast[ e ] = 0 end if ai_bot_gofast[ e ] > 0 then ModulateSpeed( e, 1.5 ) SetAnimation( 10 ) else ModulateSpeed( e, 1.0 ) SetAnimation( 1 ) end LoopAnimation( e ) SetAnimationSpeedModulation( e, 1.0 ) StartTimer( e ) end if ai_bot_state[ e ] == ai_state_move then if GetTimer( e ) > 500 then if ai_bot_coverindex[ e ] > 0 then if module_combatcore.atcover( e ) == 1 then if Ent.plrdist > 400 then local rays = module_combatcore.checkentityrays( e, 130, 0, Ent.obj, 57 ) if rays == 0 then if ai_bot_state[ e ] ~= ai_state_duck then ai_bot_state[ e ] = ai_state_duckstart end else --can't see over cover so try roll sideways? if ai_bot_state[ e ] ~= ai_state_rollstart and ai_bot_state[ e ] ~= ai_state_roll then ai_bot_state[ e ] = ai_state_rollstart module_combatcore.handleducking( e, AIObjNo, PlayerDist ) return end end else -- break from cover, player too close module_combatcore.releasecover( e ) end end end if ai_bot_coverindex[ e ] == -2 then if Ent.plrvisible == 1 and CanFire == 1 then ai_bot_state[ e ] = ai_state_startfireonspot end end if ai_bot_substate[ e ] == 0 then StartTimer( e ) end end if ai_bot_state[ e ] ~= ai_state_startfireonspot then if ai_bot_coverindex[ e ] == -2 then if Ent.plrvisible == 1 then ai_bot_targetx[ e ] = g_PlayerPosX ai_bot_targety[ e ] = g_PlayerPosY ai_bot_targetz[ e ] = g_PlayerPosZ end elseif ai_bot_coverindex[ e ] > 0 then ai_bot_targetx[ e ] = AICoverGetPointX( ai_bot_coverindex[ e ] ) ai_bot_targety[ e ] = g_PlayerPosY ai_bot_targetz[ e ] = AICoverGetPointZ( ai_bot_coverindex[ e ] ) end if ai_bot_targetx[ e ] ~= nil then module_combatcore.moveandavoid( e, AIObjNo, PlayerDist, MoveType, ai_bot_targetx[ e ], ai_bot_targety[ e ], ai_bot_targetz[ e ], stopstate ) if CanFire == 1 then module_combatcore.fireweapon( e ) end end if ai_bot_gofast[ e ] > 0 and Timer() > ai_bot_gofast[ e ] + 500 then if GetMovementDeltaManually( e, Ent.x, Ent.y, Ent.z ) < 1 then StopAnimation( e ) SetAnimationFrame( e, GetEntityAnimationStart( e, 1 ) ) SetAnimation( 1 ) LoopAnimation( e ) ModulateSpeed( e, 1.0 ) ai_bot_gofast[ e ] = 0 end end end end if Ent.plrvisible == 1 then ai_bot_hunttime[ e ] = Timer() else if ai_bot_hunttime[ e ] ~= nil then if ai_bot_hunttime[ e ] > 0 and Timer() > ai_bot_hunttime[ e ] + 5000 then if ai_bot_state[ e ] ~= ai_state_duck then ai_bot_state[ e ] = ai_state_startmove ai_bot_hunttime[ e ] = 0 SetActivated( e, 0 ) end end end if Ent.plrvisible == 0 and PlayerDist < 200 then ai_bot_state[ e ] = ai_state_idle SetAnimation( 0 ) CanFire = 0 module_combatcore.donotmove( e ) end end end function module_combatcore.handleducking( e, AIObjNo, PlayerDist ) local Ent = g_Entity[ e ] if ai_bot_state[ e ] == ai_state_crouchdashstart then ai_bot_state[e] = ai_state_crouchdash ai_bot_substate[ e ] = 0 StopAnimation( e ) SetAnimationFrame( e, GetEntityAnimationStart( e, 12 ) ) SetAnimation( 12 ) LoopAnimation( e ) ModulateSpeed( e, 1.25 ) SetAnimationSpeedModulation( e, 1.25 ) local randomevade = random( 45, 70 ) if random() > 0.5 then randomevade = -randomevade end SetRotation( e, 0, AIGetEntityAngleY( AIObjNo ) + randomevade, 0 ) StartTimer( e ) else if ai_bot_state[ e ] == ai_state_crouchdash then local tWalkDelta = GetMovementDeltaManually( e, Ent.x, Ent.y, Ent.z ) local tm = GetTimer( e ) if tm < 250 or ( tm < 2000 and PlayerDist > 200 and tWalkDelta > 1.0 ) then if tm < 1750 then MoveForward( e, AIGetEntitySpeed( AIObjNo ) ) AISetEntityPosition( AIObjNo, GetEntityPositionX( e ), GetEntityPositionY( e ), GetEntityPositionZ( e ) ) end if tm > 1250 then RotateToPlayerSlowly( e, 10.0 ) ModulateSpeed( e, 1.0 ) SetAnimationSpeedModulation( e, 1.0 ) end else ai_bot_state[ e ] = ai_state_checkforcover end end end module_combatcore.evasiveactions( e, AIObjNo, PlayerDist ) module_combatcore.strafeleft( e, 0.5 ) module_combatcore.straferight( e, 0.5 ) module_combatcore.fireweapon( e ) if ai_bot_state[ e ] == ai_state_rollstart then local randomevade = random( 65, 90 ) if random() > 0.5 then randomevade = -randomevade end local roty = AIGetEntityAngleY( AIObjNo ) + randomevade local dist = 130 local rays = module_combatcore.checkentityrays( e, dist, roty, Ent.obj, 20 ) if rays == 0 then SetRotation( e, 0, roty, 0 ) ai_bot_state[ e ] = ai_state_roll ai_bot_substate[ e ] = 0 SetAnimation( 11 ) PlayAnimation( e ) ModulateSpeed( e, 1.25 ) SetAnimationSpeedModulation( e, 1.25 ) else ai_bot_state[ e ] = ai_state_checkforcover end else if ai_bot_state[ e ] == ai_state_roll then local tFrame = GetAnimationFrame( e ) local tStart = GetEntityAnimationStart( e, 11 ) local tFinish = GetEntityAnimationFinish( e, 11 ) if tFrame > tStart + 1 and tFrame < tFinish - 20 then MoveForward( e, AIGetEntitySpeed( AIObjNo ) ) AISetEntityPosition( AIObjNo, GetEntityPositionX( e ), GetEntityPositionY( e ), GetEntityPositionZ( e ) ) else if tFrame >= tFinish - 20 then RotateToPlayerSlowly( e, 30.0 ) end MoveForward( e, 0.0 ) end if tFrame >= tFinish then ai_bot_state[ e ] = ai_state_checkforcover end end end if ai_bot_state[ e ] == ai_state_checkforcover then SetAnimationSpeedModulation( e, 1.0 ) ModulateSpeed( e, 1.0 ) StopAnimation( e ) if module_combatcore.findandassigncover( e, AIObjNo, PlayerDist ) == 1 then AIEntityGoToPosition( AIObjNo, ai_bot_targetx[ e ], ai_bot_targety[ e ], ai_bot_targetz[ e ] ) ai_bot_state[ e ] = ai_state_startmove ai_bot_substate[ e ] = 0 else ai_bot_state[ e ] = ai_state_duckstart end end if ai_bot_state[ e ] == ai_state_duckstart then ai_bot_state[ e ] = ai_state_duck ai_bot_substate[ e ] = 0 RotateToPlayer( e ) SetAnimation( 7 ) PlayAnimation( e ) SetAnimationSpeedModulation( e, 1.0 ) else if ai_bot_state[ e ] == ai_state_duck then if ai_bot_substate[ e ] == 0 then local tFrame = GetAnimationFrame( e ) local tFinish = GetEntityAnimationFinish( e, 7 ) if tFrame >= tFinish then ai_bot_substate[ e ] = 1 SetAnimation( 8 ) PlayAnimation( e ) end end -- while ducking if ai_bot_substate[ e ] == 1 then -- stay put MoveForward( e, 0.0 ) -- if see player, rotate slowly to shoot if Ent.plrvisible == 1 then RotateToPlayerSlowly( e, 30.0 ) module_combatcore.fireweapon( e ) end -- if player gets too close, end duck and cover if Ent.plrdist < 400 then ai_bot_state[ e ] = ai_state_unduckstart end -- if player at distance and in cover, pop head up and shoot at random if ai_bot_coverindex[ e ] > 0 and random( 1, 30 ) == 1 then ai_bot_state[ e ] = ai_state_unduckstart end end -- while ducking-popupshoot if ai_bot_substate[ e ] == 2 then StopAnimation( e ) SetAnimationFrame( e, GetEntityAnimationStart( e, 9 ) ) SetAnimation( 9 ) PlayAnimation( e ) ai_bot_substate[ e ] = 3 elseif ai_bot_substate[ e ] == 3 then RotateToPlayerSlowly( e, 20.0 ) module_combatcore.fireweapon( e ) local tFrame = GetAnimationFrame( e ) local tFinish = GetEntityAnimationFinish( e, 9 ) if tFrame >= tFinish then StopAnimation( e ) SetAnimationFrame( e, GetEntityAnimationStart( e, 7 ) ) SetAnimation( 7 ) PlayAnimation( e ) ai_bot_substate[ e ] = 4 end elseif ai_bot_substate[ e ] == 4 then RotateToPlayerSlowly( e, 20.0 ) module_combatcore.fireweapon( e ) local tFrame = GetAnimationFrame( e ) local tFinish = GetEntityAnimationFinish( e, 7 ) if tFrame >= tFinish then ai_bot_substate[ e ] = 1 StopAnimation( e ) SetAnimationFrame( e, GetEntityAnimationStart( e, 8 ) ) SetAnimation( 8 ) PlayAnimation( e ) end end end if ai_bot_state[ e ] == ai_state_unduckstart then ai_bot_state[ e ] = ai_state_unduck SetAnimation( 9 ) PlayAnimation( e ) elseif ai_bot_state[ e ] == ai_state_unduck then local tFrame = GetAnimationFrame( e ) local tFinish = GetEntityAnimationFinish( e, 9 ) if tFrame >= tFinish-1 and tFrame <= tFinish then ai_bot_state[ e ] = ai_state_startidle module_combatcore.releasecover( e ) ai_bot_substate[ e ] = 0 end end end end function module_combatcore.homein( e, AIObjNo, PlayerDist, MoveType, CanFire, stopstate ) if ai_bot_state[ e ] == ai_state_startmove then if module_combatcore.getcomfortdistance( e ) < 25 then -- no need to go to target, happy with close location determined by player position ai_bot_state[ e ] = stopstate else ai_bot_state[ e ] = ai_state_move SetAnimation( 1 ) LoopAnimation( e ) SetAnimationSpeedModulation( e, 1.0 ) end end if ai_bot_state[ e ] == ai_state_move then -- scan if another bot is crowding player local tbeingcrowded = false local ppx, ppy, ppz = g_PlayerPosX, g_PlayerPosY, g_PlayerPosZ for k, v in pairs( g_Entity ) do if e ~= k then local pDX, pDY, pDZ = v.x - ppx, v.y - ppy, v.z - ppz if pDX*pDX + pDY*pDY + pDZ*pDZ < 100 * 100 then tbeingcrowded = true break end end end if not tbeingcrowded then ai_bot_targetx[ e ] = ppx ai_bot_targety[ e ] = ppy ai_bot_targetz[ e ] = ppz else ai_bot_targetx[ e ] = ppx + sin(e) * 50.0 -- ????? ai_bot_targety[ e ] = ppy ai_bot_targetz[ e ] = ppz + cos(e) * 50.0 -- ????? end module_combatcore.moveandavoid( e, AIObjNo, PlayerDist, MoveType, ai_bot_targetx[ e ], ai_bot_targety[ e ], ai_bot_targetz[ e ], stopstate ) end end function module_combatcore.moveandavoid( e, AIObjNo, PlayerDist, MoveType, x, y, z, stopstate ) local Ent = g_Entity[ e ] local movementfrozen = module_combateffects.ismovementfrozen( e ) --work out this entity's velocity so we know which way it is heading (used to try move around behind it when avoiding) velox[ e ] = Ent.x - oldx[ e ] veloz[ e ] = Ent.z - oldz[ e ] oldx[ e ], oldz[ e ] = Ent.x, Ent.z if ai_bot_substate[ e ] == 0 then if PlayerDist < 100 then if module_core.countaiaroundplayer() > 1 then local tdX, tdZ = x - Ent.x, z - Ent.z local tDA = atan( tdX, tdZ ) x = x + ( sin( tDA ) * 50 ) z = z + ( cos( tDA ) * 50 ) end end AIEntityGoToPosition( AIObjNo, x, y, z ) SetRotationYSlowly( e, AIGetEntityAngleY( AIObjNo ), 10.0 ) if movementfrozen == 0 then local stopifclosetofinaldest = 0 if ai_bot_state[ e ] ~= ai_state_patrol then local ppx, ppy, ppz = g_PlayerPosX, g_PlayerPosY, g_PlayerPosZ stopifclosetofinaldest = ppy - ( Ent.y + 50 ) if stopifclosetofinaldest < 75 then local dx, dy = ppx - Ent.x, ppz - Ent.z stopifclosetofinaldest = sqrt( dx * dx + dz * dz ) if stopifclosetofinaldest < 35 then ai_bot_closeenoughx[ e ] = ppx ai_bot_closeenoughy[ e ] = ppy ai_bot_closeenoughz[ e ] = ppz AIEntityGoToPosition( AIObjNo, ai_bot_closeenoughx[ e ], ai_bot_closeenoughy[ e ], ai_bot_closeenoughz[ e ]) RotateToPlayer( e ) stopifclosetofinaldest = 1 else stopifclosetofinaldest = 0 end else stopifclosetofinaldest = 0 end end if AIGetEntityIsMoving( AIObjNo ) == 1 and stopifclosetofinaldest == 0 then ai_bot_closeenoughx[ e ] = 0 ai_bot_closeenoughy[ e ] = 0 ai_bot_closeenoughz[ e ] = 0 if MoveType == ai_movetype_useanim then MoveWithAnimation( e, 1 ) else local speedmod = 1 if ai_bot_state[ e ] == ai_state_patrol then speedmod = 0.5 end MoveForward( e, AIGetEntitySpeed( AIObjNo ) * speedmod ) end else MoveForward( e, 0.0 ) if GetTimer( e ) > 250 then ai_bot_state[ e ] = stopstate end end AISetEntityPosition( AIObjNo, GetEntityPositionX( e ), GetEntityPositionY( e ), GetEntityPositionZ( e ) ) end if Ent.avoid == 2 or ( Ent.avoid == 1 and stopstate ~= ai_state_startpatrol ) then ai_bot_substate[ e ] = random( 1, 2 ) local tAvoidAngle = 0 if ai_bot_substate[ e ] == 1 then tAvoidAngle = AIGetEntityAngleY( AIObjNo ) - 95 else tAvoidAngle = AIGetEntityAngleY( AIObjNo ) + 95 end tAvoidAngle = ( tAvoidAngle / 360.0 ) * 6.28 local tAvoidX = GetEntityPositionX( e ) + sin( tAvoidAngle ) * 30 local tAvoidZ = GetEntityPositionZ( e ) + cos( tAvoidAngle ) * 30 AIEntityGoToPosition( AIObjNo, tAvoidX, GetEntityPositionY( e ), tAvoidZ ) StartTimer( e ) else if g_Time < avoid_time[ e ] then AIEntityGoToPosition( AIObjNo, ai_bot_targetx[ e ], ai_bot_targetz[ e ] ) SetRotation( e, 0, AIGetEntityAngleY( AIObjNo ), 0 ) else --settings for the avoidance pathing local avoidance_time = 50 local raydist = 120 local yoffset = 15 local obsray = module_combatcore.checkentityrays( e, raydist, 0, AIObjNo, yoffset ) if obsray == nil then obsray = 0 end if obsray > 0 and GetObjectExist( obsray ) > 0 then local obsE = P.ObjectToEntity( obsray ) if obsE ~= nil then --PromptLocal( e, "Avoiding entity " .. obsE ) local nex = GetEntityPositionX( obsE ) local nez = GetEntityPositionZ( obsE ) if velox[ obsE ] == nil then velox[ obsE ] = 0 end if veloz[ obsE ] == nil then veloz[ obsE ] = 0 end local oangy = module_combatcore.getangletopoint( obsE, nex + ( velox[ obsE ] * 1000 ), nez + ( veloz[ obsE ] * 1000 ) ) + 180 oangy = ( oangy / 360.0 ) * 6.28 ai_bot_targetx[ e ] = GetEntityPositionX( e ) + sin( oangy ) * 30 ai_bot_targetz[ e ] = GetEntityPositionZ( e ) + cos( oangy ) * 30 avoid_time[ e ] = g_Time + avoidance_time end end end end end if ai_bot_substate[ e ] > 0 and ai_bot_state[ e ] ~= ai_state_duck then SetRotation( e, 0, AIGetEntityAngleY( AIObjNo ), 0 ) if movementfrozen == 0 then if AIGetEntityIsMoving( AIObjNo ) == 1 then if MoveType == ai_movetype_useanim then MoveWithAnimation( e, 1 ) else MoveForward( e, AIGetEntitySpeed( AIObjNo ) ) end else MoveForward( e, 0.0 ) end AISetEntityPosition( AIObjNo, GetEntityPositionX( e ), GetEntityPositionY( e ), GetEntityPositionZ( e ) ) end if GetTimer( e ) > 1000 then ai_bot_substate[ e ] = 0 end end end function module_combatcore.donotmove( e ) MoveForward( e, 0 ) ai_bot_substate[ e ] = 0 end function module_combatcore.sensepunch( e, AIObjNo, PlayerDist, combattype ) local Ent = g_Entity[ e ] if PlayerDist < 150 and combattype == ai_combattype_freezermelee and ai_bot_state[ e ] ~= ai_state_move then RotateToPlayer( e ) end if ai_bot_state[ e ] == ai_state_move or ai_bot_state[ e ] == ai_state_fireonspot then if PlayerDist < 75 and g_PlayerPosY > Ent.y and g_PlayerPosY < Ent.y + 70 then -- must also check for line of sight (i.e not through walls) (first and third person) local thaslineofsight = false local tthitvalue = IntersectAll( Ent.x, Ent.y + 50, Ent.z, g_PlayerPosX, g_PlayerPosY + 50, g_PlayerPosZ, AIObjNo ) local ttpersonobj = 0 if GetGamePlayerControlThirdpersonEnabled() == 1 then local ttpersone = GetGamePlayerControlThirdpersonCharactere() if ttpersone > 0 then ttpersonobj = GetEntityElementObj( ttpersone ) if GetObjectExist( ttpersonobj ) == 0 then ttpersonobj = 0 end end end if tthitvalue == 0 or tthitvalue == playerobj then thaslineofsight = true end if thaslineofsight then ai_bot_state[ e ] = ai_state_punch SetAnimation( 2 ) PlayAnimation( e ) SetAnimationSpeedModulation( e, 1.0 ) PlaySound( e, 1 ) RotateToPlayer(e) if combattype == ai_combattype_freezermelee then module_cameraoverride.beingattackedby( e, 60.0 ) end end end end end function module_combatcore.hurt( e, PlayerDist, responsestate ) local Ent = g_Entity[ e ] if ai_bot_state[ e ] == ai_state_idle or ai_bot_state[ e ] == ai_state_patrol or ai_bot_state[ e ] == ai_state_move or ai_bot_state[ e ] == ai_state_fireonspot or ai_bot_state[ e ] == ai_state_recover or ai_bot_state[ e ] == ai_state_punch or ai_bot_state[ e ] == ai_state_duck then if Ent.health < ai_bot_oldhealth[e] then if ai_bot_state[ e ] == ai_state_duck then ai_bot_state[ e ] = ai_state_unduckstart elseif ( ai_bot_state[ e ] == ai_state_move or ai_bot_state[ e ] == ai_state_idle or ai_bot_state[ e ] == ai_state_fireonspot ) and PlayerDist > 300 then if random( 1, 3 ) == 1 then ai_bot_state[ e ] = ai_state_rollstart else ai_bot_state[ e ] = ai_state_crouchdashstart end elseif ai_bot_state[ e ] == ai_state_roll then -- AI is immune to damage when rolling SetEntityHealth( e, ai_bot_oldhealth[ e ] ) else local flinch = math.random( 1, 3 ) if flinch == 1 then ai_bot_state[ e ] = ai_state_hurt SetAnimationSpeed( e, 3.0 ) SetAnimation( 3 ) PlayAnimation( e ) SetAnimationSpeedModulation( e, 1.0 ) end end ai_bot_oldhealth[ e ] = Ent.health ai_bot_angryhurt[ e ] = 1 PlaySound( e, math.random( 3, 4 ) ) module_agro.alertallwithinradius( Ent.x, Ent.y, Ent.z, 250.0 ) end end if ai_bot_state[ e ] == ai_state_hurt then MoveForward( e, 0.0 ) RotateToPlayerSlowly( e, 10.0 ) local tFrame = GetAnimationFrame( e ) local tStart = GetEntityAnimationFinish( e, 3 ) if tFrame >= tStart then SetAnimationSpeed( e, 1.0 ) ai_bot_state[ e ] = responsestate end end end function module_combatcore.headshot( e ) if string.find( string.lower( g_Entity[ e ].limbhit ), "head" ) ~= nil then SetEntityHealth( e, -1 ) ResetLimbHit( e ) end end function module_combatcore.soundawareness( e, AIObjNo ) if AIGetEntityHeardSound( AIObjNo ) == 1 then local botState = ai_bot_state[ e ] if botState == ai_state_idle or botState == ai_state_hurt then ai_bot_sighting[ e ] = Timer() + 500 elseif botstate == ai_state_patrol then ai_bot_state[ e ] = ai_state_startidle ai_bot_sighting[ e ] = Timer() + 500 else ai_bot_sighting[ e ] = 0 end end if ai_bot_sighting[ e ] > 0 and Timer() < ai_bot_sighting[ e ] then RotateToPlayerSlowly( e, 10.0 ) end end function module_combatcore.punch( e, AIObjNo, PlayerDist, combattype, afterstate ) if ai_bot_state[ e ] == ai_state_punch then local wemoved = 0 if combattype == ai_combattype_freezermelee then if module_cameraoverride.manageattackcycle( e ) == 1 then MoveWithAnimation( e, 1 ) wemoved = 1 end end local tFrame = GetAnimationFrame( e ) local tStart = GetEntityAnimationStart( e, 2 ) local tFinish = GetEntityAnimationFinish( e, 2 ) local tDamageFramesStart = GetEntityAnimationStart( e, 5 ) local tDamageFramesFinish = GetEntityAnimationFinish( e, 5 ) if tDamageFramesStart > 0 and tDamageFramesFinish > 0 then -- override defaults if anim5 specifies specific damage frame range tStart = tDamageFramesStart tFinish = tDamageFramesFinish if combattype == ai_combattype_freezermelee then tStart = tStart - 10 tFinish = tFinish + 30 elseif combattype == ai_combattype_bashmelee then tStart = tStart - 25 else tStart = tStart - 10 end end if PlayerDist < 90 then if combattype == ai_combattype_freezermelee then if tFrame >= tStart + 10 and tFrame <= tFinish - 30 then if random( 1, 7 ) == 1 then HurtPlayer( e, random( 1, 2 ) ) end end elseif combattype == ai_combattype_bashmelee then if tFrame >= tStart + 25 and tFrame <= tStart + 35 then HurtPlayer( e, math.random( 2, 3 ) ) ForcePlayer( g_Entity[ e ].angley, 2.0 ) end elseif tFrame >= tStart + 10 and tFrame <= tStart + 15 then HurtPlayer( e, math.random( 2, 3 ) ) ForcePlayer ( g_Entity[ e ].angley, 3.0 ) end end if combattype == ai_combattype_freezermelee then if tFrame >= tFinish - 30 then if module_cameraoverride.finishbeingattacked( e ) == 1 then ForcePlayer ( g_Entity[ e ].angley, 3.0 ) end else if module_cameraoverride.hasowner() == 0 then ai_bot_state[ e ] = ai_state_recoverstart end end end if tFrame >= tFinish then if combattype == ai_combattype_freezermelee or combattype == ai_combattype_bashmelee then ai_bot_state[ e ] = ai_state_recoverstart else ai_bot_state[ e ] = afterstate end end if wemoved == 0 then module_combatcore.donotmove( e ) end end end function module_combatcore.recover (e, resumestate ) if ai_bot_state[ e ] == ai_state_recoverstart then ai_bot_state[ e ] = ai_state_recover StopAnimation( e ) SetAnimation( 0 ) SetAnimationFrame( e, GetEntityAnimationStart( e, 0 ) ) PlayAnimation( e ) SetAnimationSpeedModulation( e, 1.0 ) StartTimer( e ) end if ai_bot_state[ e ] == ai_state_recover then module_combatcore.donotmove( e ) if GetTimer( e ) > 100 then ai_bot_state[ e ] = resumestate end end end function module_combatcore.fireonspot( e, AIObjNo ) if ai_bot_state[ e ] == ai_state_startfireonspot then ai_bot_state[ e ] = ai_state_fireonspot StopAnimation( e ) SetAnimation( 0 ) LoopAnimation( e ) SetAnimationSpeedModulation( e, 1.0 ) StartTimer( e ) end if ai_bot_state[ e ] == ai_state_fireonspot then if g_Entity[ e ]plrvisible == 0 and GetTimer( e ) > 500 then if ai_bot_state[ e ] ~= ai_state_startidle then ai_bot_state[ e ] = ai_state_startidle end else RotateToPlayer( e ) module_combatcore.fireweapon( e ) ai_bot_targetx[ e ] = g_PlayerPosX ai_bot_targety[ e ] = g_PlayerPosY ai_bot_targetz[ e ] = g_PlayerPosZ AIEntityGoToPosition( AIObjNo, ai_bot_targetx[ e ], ai_bot_targety[ e ], ai_bot_targetz[ e ] ) end module_combatcore.donotmove( e ) end end function module_combatcore.fireweapon( e ) if ai_bot_state[ e ] ~= ai_state_startreload and ai_bot_state[ e ] ~= ai_state_reload and ai_bot_state[ e ] ~= ai_state_reloadsettle then if GetAmmoClip( e ) > 0 then FireWeapon( e ) else local tReloadFinishFrame = GetEntityAnimationFinish( e, 4 ) if tReloadFinishFrame > 0 then ai_bot_state[ e ] = ai_state_startreload end end end end function module_combatcore.reloadweapon( e ) if ai_bot_state[ e ] == ai_state_startreload then ai_bot_state[ e ] = ai_state_reload SetAnimation( 4 ) PlayAnimation( e ) SetAnimationSpeedModulation( e, 1.0 ) local tStart = GetEntityAnimationStart( e, 4 ) SetAnimationFrame( e, tStart ) StartTimer( e ) elseif ai_bot_state[ e ] == ai_state_reload then if GetTimer( e ) > 500 then local tFrame = GetAnimationFrame( e ) local tStart = GetEntityAnimationStart( e, 4 ) local tFinish = GetEntityAnimationFinish( e, 4 ) local tDiffHalf = ( tFinish - tStart ) / 3 if ( tFrame >= tFinish - tDiffHalf and tFrame <= tFinish ) or tFinish == 0 then ai_bot_state[ e ] = ai_state_reloadsettle StartTimer( e ) end end module_combatcore.donotmove( e ) elseif ai_bot_state[ e ] == ai_state_reloadsettle then if GetTimer( e ) > 750 then SetAmmoClip( e, GetAmmoClipMax( e ) ) ai_bot_state[ e ] = ai_state_startidle end module_combatcore.donotmove( e ) end end function module_combatcore.preexit( e, MoveType ) local tFrame = GetAnimationFrame( e ) local tDyingAnimStart = GetEntityAnimationStart( e, 6 ) local tDyingAnimFinish = GetEntityAnimationFinish( e, 6 ) if tDyingAnimStart > 0 and tDyingAnimFinish > 0 then if ai_bot_state[ e ] ~= ai_state_preexit then ai_bot_state[ e ] = ai_state_preexit CharacterControlLimbo( e ) StopAnimation( e ) SetAnimation( 6 ) PlayAnimation( e ) SetAnimationFrame( e, tDyingAnimStart ) SetAnimationSpeedModulation( e, 1.0 ) end else return 1 end if tFrame >= tDyingAnimFinish - 2 then return 1 else return 0 end end function module_combatcore.exit( e ) StopSound( e, 0 ) StopSound( e, 1 ) CollisionOff( e ) end function module_combatcore.evasiveactions( e, AIObjNo, PlayerDist ) local aibs = ai_bot_state[ e ] if aibs ~= ai_state_idle and aibs ~= ai_state_move and aibs ~= ai_state_startmove and aibs ~= ai_state_roll and aibs ~= ai_state_strafeleft and aibs ~= ai_state_strafeleftstart and aibs ~= ai_state_straferightstart and aibs ~= ai_state_straferight and aibs ~= ai_state_duckstart and aibs ~= ai_state_duck and aibs ~= ai_state_unduckstart then if random() > 0.5 then if PlayerDist > 200 then if module_combatcore.playerlooking( e, PlayerDist, 10 ) == 1 then local rays = module_combatcore.checkplayertoentityrays( PlayerDist + 5, 0, 0, 60 ) if rays == AIObjNo or rays == 0 then local temp = math.random( 1, 6 ) --set max to 7 or higher to add a chance to roll if temp < 7 then if module_combatcore.entitylookingatplayer( e, PlayerDist, 10 ) ~= 1 then temp = 99 end end if ai_bot_last_sidestep[ e ] == nil then ai_bot_last_sidestep[ e ] = 0 end if temp < 4 then if ai_bot_last_sidestep[ e ] == 0 then ai_bot_last_sidestep[ e ] = -15 ai_bot_state[ e ] = ai_state_strafeleftstart else if ai_bot_last_sidestep[ e ] < 0 then ai_bot_last_sidestep[ e ] = ai_bot_last_sidestep[ e ] + 1 else ai_bot_last_sidestep[ e ] = ai_bot_last_sidestep[ e ] - 1 end end elseif temp < 7 then if ai_bot_last_sidestep[ e ] == 0 then ai_bot_last_sidestep[ e ] = 15 ai_bot_state[ e ] = ai_state_straferightstart else if ai_bot_last_sidestep[ e ] < 0 then ai_bot_last_sidestep[ e ] = ai_bot_last_sidestep[ e ] + 1 else ai_bot_last_sidestep[ e ] = ai_bot_last_sidestep[ e ] - 1 end end elseif temp < 8 then ai_bot_state[ e ] = ai_state_rollstart end end end end end end end function module_combatcore.strafeleft( e, speedmod ) local Ent = g_Entity[ e ] local aibs = ai_bot_state[ e ] if aibs == ai_state_strafeleftstart then ai_bot_state[ e ] = ai_state_checkforcover local randomevade = random( 45, 90 ) * -1 local dist = 120 local rays = module_combatcore.checkentityrays( e, dist, randomevade, Ent.obj, 20 ) if rays == 0 then ai_bot_state[ e ] = ai_state_strafeleft ai_bot_substate[ e ] = 0 SetAnimationFrame( e, GetEntityAnimationStart( e, 15 ) ) SetAnimation( 15 ) PlayAnimation( e ) Ent.animating = 15 ModulateSpeed( e, 1 ) SetAnimationSpeedModulation( e, 1.5 ) ai_bot_roty[ e ] = AIGetEntityAngleY( Ent.obj ) local temprot = ai_bot_roty[ e ] + randomevade SetRotation( e, 0, temprot, 0 ) ai_bot_newroty[ e ] = temprot end end if aibs == ai_state_strafeleft then local tFrame = GetAnimationFrame( e ) local tStart = GetEntityAnimationStart( e, 15 ) local tFinish = GetEntityAnimationFinish( e, 15 ) if tFrame >= tStart + 5 and tFrame < tFinish - 8 and Ent.animating == 15 then SetRotation( e, 0, ai_bot_newroty[ e ], 0 ) MoveForward( e, AIGetEntitySpeed( Ent.obj ) * speedmod ) end SetRotation( e, 0, ai_bot_roty[ e ], 0 ) AISetEntityPosition( Ent.obj, GetEntityPositionX( e ), GetEntityPositionY( e ), GetEntityPositionZ( e ) ) if tFrame >= tFinish - 2 and tFrame <= tFinish then ai_bot_state[ e ] = ai_state_startfireonspot SetAnimationSpeedModulation( e, 1 ) end end end function module_combatcore.straferight( e, speedmod ) local Ent = g_Entity[ e ] local aibs = ai_bot_state[ e ] if aibs == ai_state_straferightstart then ai_bot_state[ e ] = ai_state_checkforcover local randomevade = random( 45, 90 ) local dist = 120 local rays = module_combatcore.checkentityrays( e, dist, randomevade, Ent.obj, 20 ) if rays == 0 then ai_bot_state[ e ] = ai_state_straferight ai_bot_substate[ e ] = 0 SetAnimationFrame( e, GetEntityAnimationStart( e, 16 ) ) SetAnimation( 16 ) PlayAnimation( e ) Ent.animating = 16 ModulateSpeed( e, 1 ) SetAnimationSpeedModulation( e, 1.5 ) ai_bot_roty[ e ] = AIGetEntityAngleY( Ent.obj ) local temprot = ai_bot_roty[ e ] + randomevade SetRotation( e, 0, temprot, 0 ) ai_bot_newroty[ e ] = temprot end end if aibs == ai_state_straferight then local tFrame = GetAnimationFrame( e ) local tStart = GetEntityAnimationStart( e, 16 ) local tFinish = GetEntityAnimationFinish( e, 16 ) if tFrame >= tStart + 5 and tFrame < tFinish - 8 then SetRotation( e, 0, ai_bot_newroty[ e ], 0 ) MoveForward( e, AIGetEntitySpeed( Ent.obj )* speedmod ) end SetRotation( e, 0, ai_bot_roty[ e ], 0 ) AISetEntityPosition( Ent.obj, GetEntityPositionX( e ), GetEntityPositionY( e ), GetEntityPositionZ( e ) ) if tFrame >= tFinish - 2 and tFrame <= tFinish and Ent.animating == 16 then ai_bot_state[ e ] = ai_state_startfireonspot SetAnimationSpeedModulation( e, 1 ) end end end function module_combatcore.getangletopoint( e, x, z ) local Ent = g_Entity[ e ] if Ent ~= nil and x > 0 and z > 0 then local destx = x - Ent.x local destz = z - Ent.z local angle = atan( destx, destz ) angle = angle * ( 180.0 / math.pi ) if angle < 0 then angle = 360 + angle elseif angle > 360 then angle = angle - 360 end return angle end end function module_combatcore.checkfiredrecently( e, window ) if last_fired[ e ] == nil then last_fired[ e ] = g_Time end if g_Time > last_fired[ e ] + window then return 0 else return 1 end end function module_combatcore.checkentityrays( e, dist, ang, obj, yoff ) local new_y = rad( GetEntityAngleY( e ) + ang ) local x1 = GetEntityPositionX( e ) local y1 = GetEntityPositionY( e ) + yoff local z1 = GetEntityPositionZ( e ) local x2 = x1 + sin( new_y ) * dist local z2 = z1 + cos( new_y ) * dist local hit = IntersectAll( x1, y1, z1, x2, y1, z2, obj ) if hit and hit ~= 0 then return 1 end hit = RayTerrain( x1, y1, z1, x2, y1, z2 ) if hit and hit ~= 0 then return 1 end return 0 end function module_combatcore.checkplayertoentityrays( dist, ang, obj, yoff ) local new_y = rad( g_PlayerAngY ) + ang local x1, y1, z1 = g_PlayerPosX, g_PlayerPosY + yoff, g_PlayerPosZ local x2 = x1 + sin( new_y ) * dist local z2 = z1 + cos( new_y ) * dist local hit = IntersectAll( x1, y1, z1, x2, y1, z2, obj ) if hit and hit ~= 0 then return 1 end hit = RayTerrain( x1, y1, z1, x2, y1, z2 ) if hit and hit ~= 0 then return 1 end return 0 end function module_combatcore.playerlooking( e, dis, v ) dis = dis or 3000 v = v or 0.5 if U.PlayerLookingNear( e, dis, v ) then return 1 end return 0 end local function limitAngle ( Angle ) while Angle < 0 do Angle = 360 + Angle end while Angle > 360 do Angle = Angle - 360 end return Angle end function module_combatcore.entitylookingatplayer( e, dis, v ) dis = dis or 3000 v = v or 0.5 local Ent = g_Entity[ e ] if Ent ~= nil then local distx = g_PlayerPosX - Ent.x local disty = g_PlayerPosY - Ent.y local distz = g_PlayerPosZ - Ent.z local Sqdist = distx * distx + disty * disty + distz * distz if Sqdist > dis * dis then return 0 end local angle = limitAngle( atan( distx, dist ) * ( 180.0 / pi ) ) local pAng = limitAngle( Ent.angley ) local L = limitAngle( angle - v ) local R = limitAngle( angle + v ) if ( L < R and ( pAng > L and pAng < R ) ) or ( L > R and ( pAng > L or pAng < R ) ) then return 1 end end return 0 end return module_combatcore