--when enemy can react to player (but not seen or heard) local alert_range = 1050 --effects cover angle (lower value means they will leave cover sooner when getting flanked local mod = 34 --when enemies will count themselves as being in cover local in_cover_range = 60 max_per_cover = {} current_cover = {} local current_cover_dist = {} cover_zone = {} per_cover = {} local find_new_cover = {} local found_better_cover = {} local angle1 = 0 local angle2 = 0 local temp1 = 0 local temp2 = 0 function ai_take_cover_init(e) ai_soldier_state[e] = "patrol" current_cover_dist[e] = 2000 current_cover[e] = 0 find_new_cover[e] = 0 found_better_cover[e] = 0 ai_soldier_pathindex[e] = -1 SetCharacterSoundSet(e) end --use with cover_zone.lua and cover markers function ai_take_cover_main(e) while g_PlayerAngY > 359 do g_PlayerAngY = g_PlayerAngY - 360 end while g_PlayerAngY < 0 do g_PlayerAngY = g_PlayerAngY + 360 end EntObjNo = g_Entity[e]['obj'] if ai_soldier_state[e] == "patrol" then CharacterControlStand(e) CharacterControlUnarmed(e) SetCharacterToWalk(e) current_cover_dist[e] = 2000 -- Try and find a close path to patrol, just check once for it if ai_soldier_pathindex[e] == -1 then ai_soldier_pathindex[e] = -2 --CharacterControlArmed(e) -- find initial waypoint path to follow PathIndex = -1; pClosest = 99999; for pa = 1, AIGetTotalPaths(), 1 do for po = 1 , AIGetPathCountPoints(pa), 1 do pDX = g_Entity[e]['x'] - AIPathGetPointX(pa,po); pDZ = g_Entity[e]['z'] - AIPathGetPointZ(pa,po); pDist = math.sqrt(math.abs(pDX*pDX)+math.abs(pDZ*pDZ)); if pDist < pClosest and pDist < 200 then pClosest = pDist; PathIndex = pa; end end -- po end -- pa -- follow found path if PathIndex > -1 then ai_soldier_pathindex[e] = PathIndex; ai_path_point_index[e] = 2 ModulateSpeed(e,1.0) SetCharacterToWalk(e) ai_path_point_direction[e] = 1 ai_path_point_max[e] = AIGetPathCountPoints(ai_soldier_pathindex[e]) end end -- Force character as unarmed --CharacterControlUnarmed(e) -- If set to head home, lets go there if ai_returning_home[e] == 1 then tDistX = g_Entity[e]['x'] - ai_start_x[e]; tDistZ = g_Entity[e]['z'] - ai_start_z[e]; DistToStart = math.sqrt(math.abs(tDistX*tDistX)+math.abs(tDistZ*tDistZ)) if DistToStart < 200 or GetTimer(e) > ai_combat_state_delay[e] then ai_soldier_pathindex[e] = -1 SetCharacterToWalk(e) CharacterControlUnarmed(e) AIEntityStop(EntObjNo); ModulateSpeed(e,1.0) ai_returning_home[e] = 0 ai_soldier_state[e] = "alerted" ai_alerted_mode[e] = 0 else AIEntityGoToPosition(EntObjNo,ai_start_x[e],ai_start_z[e]) end -- If we have a path then lets patrol it elseif ai_soldier_pathindex[e] > -1 then ai_patrol_x[e] = AIPathGetPointX(ai_soldier_pathindex[e],ai_path_point_index[e]) ai_patrol_z[e] = AIPathGetPointZ(ai_soldier_pathindex[e],ai_path_point_index[e]) AIEntityGoToPosition(EntObjNo,ai_patrol_x[e],ai_patrol_z[e]) tDistX = g_Entity[e]['x'] - ai_patrol_x[e] tDistZ = g_Entity[e]['z'] - ai_patrol_z[e] DistFromPath = math.sqrt(math.abs(tDistX*tDistX)+math.abs(tDistZ*tDistZ)) if DistFromPath < 50 then if ai_path_point_direction[e] == 1 then ai_path_point_index[e] = ai_path_point_index[e] + 1 if ( ai_path_point_index[e] > ai_path_point_max[e] ) then ai_path_point_index[e] = ai_path_point_max[e] -1 ai_path_point_direction[e] = 0 end else ai_path_point_index[e] = ai_path_point_index[e] - 1 if ( ai_path_point_index[e] < 1 ) then ai_path_point_index[e] = 2 ai_path_point_direction[e] = 1 end end end else CharacterControlFidget(e) end --alerted to player presence so find cover asap if GetPlayerDistance(e) < alert_range or g_Entity[e]['plrvisible'] == 1 or AIGetEntityHeardSound(EntObjNo) == 1 then ai_soldier_state[e] = "find cover" PlayCharacterSound(e,"onAlert") end --look for nearest available cover elseif ai_soldier_state[e] == "find cover" then StartTimer(e) current_cover[e] = 0 current_cover_dist[e] = 2000 found_better_cover[e] = 0 for a = 1, 9999 do if cover_zone[a] ~= nil and cover_zone[a] == 1 then if max_per_cover[a] ~= nil and per_cover[a] ~= nil then if g_Entity[e]['angley'] < 0 then g_Entity[e]['angley'] = g_Entity[e]['angley'] + 360 elseif g_Entity[e]['angley'] > 359 then g_Entity[e]['angley'] = 360 - g_Entity[e]['angley'] end if per_cover[a] < max_per_cover[a] then if GetDistance(e,a) < GetPlayerDistance(a) then if GetDistance(e,a) < current_cover_dist[e] then if AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) > mod and AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ)+mod < 360 then if AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) - mod < g_Entity[a]['angley'] and AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) + mod > g_Entity[a]['angley'] then current_cover[e] = a current_cover_dist[e] = GetDistance(e,a) end elseif AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) < mod or (AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) - mod > g_Entity[a]['angley'] and g_Entity[e]['angley'] < mod) then if (AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) - mod)+360 > g_Entity[a]['angley'] and AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) + mod > g_Entity[a]['angley'] then current_cover[e] = a current_cover_dist[e] = GetDistance(e,a) end elseif AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) + mod > 360 then if AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) - mod < g_Entity[a]['angley'] and (AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ)+mod)-360 < g_Entity[a]['angley'] then current_cover[e] = a current_cover_dist[e] = GetDistance(e,a) end end end end --AI closer to cover than he is to player end end --max_per_cover nil end --cover nil check end --for a StartTimer(e) if current_cover[e] > 0 then if per_cover[current_cover[e]] ~= nil then per_cover[current_cover[e]] = per_cover[current_cover[e]] + 1 end ai_soldier_state[e] = "move to cover" current_cover_dist[e] = GetDistance(e,current_cover[e]) else ai_soldier_state[e] = "attack" end --move to the cover we have found elseif ai_soldier_state[e] == "move to cover" then CharacterControlArmed(e) SetCharacterToRun(e) FireWeapon(e) AIEntityGoToPosition(EntObjNo,g_Entity[current_cover[e]]['x'],g_Entity[current_cover[e]]['z']) if found_better_cover[e] == 0 then found_better_cover[e] = 1 end --cover couldnt be reached in time so find new cover from our current location if GetTimer(e) > 8500 then found_better_cover[e] = 0 if per_cover[current_cover[e]] ~= nil then per_cover[current_cover[e]] = per_cover[current_cover[e]] - 1 end ai_soldier_state[e] = "find cover" end if GetDistance(e,current_cover[e]) < in_cover_range then if found_better_cover[e] == 2 then found_better_cover[e] = 0 end StartTimer(e) ai_soldier_state[e] = "in cover" end --we have reached our cover elseif ai_soldier_state[e] == "in cover" then CharacterControlDucked(e) RotateToPlayer(e) FireWeapon(e) if GetTimer(e) > 1450 then CharacterControlStand(e) if GetTimer(e) > 3000 then if per_cover[current_cover[e]] ~= nil then per_cover[current_cover[e]] = per_cover[current_cover[e]] - 1 end --check if player has started to flank us and flag to find new cover if so (code actually does the opposite but that's the idea/same result) find_new_cover[e] = 1 if AngleToPoint(current_cover[e],g_PlayerPosX,g_PlayerPosZ) > mod and AngleToPoint(current_cover[e],g_PlayerPosX,g_PlayerPosZ)+mod < 360 then if AngleToPoint(current_cover[e],g_PlayerPosX,g_PlayerPosZ) - mod < g_Entity[current_cover[e]]['angley'] and AngleToPoint(current_cover[e],g_PlayerPosX,g_PlayerPosZ) + mod > g_Entity[current_cover[e]]['angley'] then find_new_cover[e] = 0 current_cover_dist[e] = GetDistance(e,current_cover[e]) end elseif AngleToPoint(current_cover[e],g_PlayerPosX,g_PlayerPosZ) < mod or (AngleToPoint(current_cover[e],g_PlayerPosX,g_PlayerPosZ) - mod > g_Entity[current_cover[e]]['angley'] and g_Entity[current_cover[e]]['angley'] < mod) then if (AngleToPoint(current_cover[e],g_PlayerPosX,g_PlayerPosZ) - mod)+360 > g_Entity[current_cover[e]]['angley'] and AngleToPoint(current_cover[e],g_PlayerPosX,g_PlayerPosZ) + mod > g_Entity[current_cover[e]]['angley'] then find_new_cover[e] = 0 current_cover_dist[e] = GetDistance(e,current_cover[e]) end elseif AngleToPoint(current_cover[e],g_PlayerPosX,g_PlayerPosZ) + mod > 360 then if AngleToPoint(current_cover[e],g_PlayerPosX,g_PlayerPosZ) - mod < g_Entity[current_cover[e]]['angley'] and (AngleToPoint(current_cover[e],g_PlayerPosX,g_PlayerPosZ)+mod)-360 < g_Entity[current_cover[e]]['angley'] then find_new_cover[e] = 0 current_cover_dist[e] = GetDistance(e,current_cover[e]) end end --if our cover is compromised then find new cover otherwise check for better position if find_new_cover[e] == 1 then found_better_cover[e] = 0 ai_soldier_state[e] = "find cover" else ai_soldier_state[e] = "find better cover" end end end --check for cover nearer to player or in flanking position elseif ai_soldier_state[e] == "find better cover" then StartTimer(e) for a = 1, 9999 do if cover_zone[a] ~= nil and cover_zone[a] == 1 then if max_per_cover[a] ~= nil and per_cover[a] ~= nil then if g_Entity[e]['angley'] < 0 then g_Entity[e]['angley'] = g_Entity[e]['angley'] + 360 elseif g_Entity[e]['angley'] > 359 then g_Entity[e]['angley'] = 360 - g_Entity[e]['angley'] end if per_cover[a] < max_per_cover[a] then if GetDistance(e,a) < GetPlayerDistance(a) then if GetPlayerDistance(a) < GetPlayerDistance(current_cover[e]) then --if we haven't already moved nearer the player previously then try to now if found_better_cover[e] < 1 then if GetDistance(e,a) < current_cover_dist[e] * 200 then if AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) > mod and AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ)+mod < 360 then if AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) - mod < g_Entity[a]['angley'] and AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) + mod > g_Entity[a]['angley'] then current_cover[e] = a current_cover_dist[e] = GetDistance(e,a) ai_soldier_state[e] = "move to cover" end elseif AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) < mod or (AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) - mod > g_Entity[a]['angley'] and g_Entity[e]['angley'] < mod) then if (AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) - mod)+360 > g_Entity[a]['angley'] and AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) + mod > g_Entity[a]['angley'] then current_cover[e] = a current_cover_dist[e] = GetDistance(e,a) ai_soldier_state[e] = "move to cover" end elseif AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) + mod > 360 then if AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) - mod < g_Entity[a]['angley'] and (AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ)+mod)-360 < g_Entity[a]['angley'] then current_cover[e] = a current_cover_dist[e] = GetDistance(e,a) ai_soldier_state[e] = "move to cover" end end end --if we have moved closer to the player then try to flank now else angle1 = g_PlayerAngY - 90 angle2 = g_PlayerAngY + 90 if angle1 < 0 then angle1 = angle1 + 360 elseif angle1 > 359 then angle1 = angle1 - 360 end if angle2 < 0 then angle2 = angle2 + 360 elseif angle2 > 359 then angle2 = angle2 - 360 end temp1 = AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) - mod temp2 = AngleToPoint(a,g_PlayerPosX,g_PlayerPosZ) + mod if temp1 < 0 then temp1 = temp1 + 360 elseif temp1 > 359 then temp1 = temp1 - 360 end if temp2 < 0 then temp2 = temp2 - 360 elseif temp2 > 359 then temp2 = temp2 - 360 end if g_PlayerAngY > 90 and g_PlayerAngY < 270 then if (temp1 > angle1 and temp2 < angle1) or (temp1 > angle2 and temp2 < angle2) then current_cover[e] = a current_cover_dist[e] = GetDistance(e,a) ai_soldier_state[e] = "move to cover" found_better_cover[e] = 2 end elseif g_PlayerAngY < 91 then if temp2 < angle1 or (temp1 > angle2 and temp2 < angle2) then current_cover[e] = a current_cover_dist[e] = GetDistance(e,a) ai_soldier_state[e] = "move to cover" found_better_cover[e] = 2 end elseif g_PlayerAngY > 269 then if (temp1 > angle1 and temp2 < angle1) or temp1 > angle2 then current_cover[e] = a current_cover_dist[e] = GetDistance(e,a) ai_soldier_state[e] = "move to cover" found_better_cover[e] = 2 end end end end end --AI closer to cover than he is to player end end --max_per_cover nil end --cover nil check end --for a StartTimer(e) --if we didn't find any cover to move to then we should go back and find new cover if ai_soldier_state[e] ~= "move to cover" then ai_soldier_state[e] = "find cover" else if per_cover[current_cover[e]] ~= nil then per_cover[current_cover[e]] = per_cover[current_cover[e]] + 1 end end --if no cover found at all right now then just charge at the player elseif ai_soldier_state[e] == "attack" then CharacterControlArmed(e) SetCharacterToRun(e) FireWeapon(e) if GetPlayerDistance(e) > 750 then AIEntityGoToPosition(EntObjNo,g_PlayerPosX,g_PlayerPosZ) else AIEntityGoToPosition(EntObjNo,g_Entity[e]['x'],g_Entity[e]['z']) RotateToPlayer(e) end --but we should still check for new cover occasionally if GetTimer(e) > 3000 then ai_soldier_state[e] = "find cover" end end --ai_soldier_state --if player dies then reset the script if g_PlayerHealth < 1 then ai_soldier_state[e] = "patrol" find_new_cover[e] = 0 found_better_cover[e] = 0 if per_cover[current_cover[e]] ~= nil then per_cover[current_cover[e]] = per_cover[current_cover[e]] - 1 end end --headshot detected if string.find(string.lower(g_Entity[e]['limbhit']), "head") ~= nil then SetEntityHealth(e,0) end end --main function ai_take_cover_exit(e) if per_cover[current_cover[e]] ~= nil then per_cover[current_cover[e]] = per_cover[current_cover[e]] - 1 end CollisionOff(e) PlayCharacterSound(e,"onDeath") end function GetDistance(e,v) if g_Entity[e] ~= nil and g_Entity[e] ~= 0 and g_Entity[v] ~= nil and g_Entity[v] ~= 0 then local disx = g_Entity[e]['x'] - g_Entity[v]['x'] local disz = g_Entity[e]['z'] - g_Entity[v]['z'] local disy = g_Entity[e]['y'] - g_Entity[v]['y'] return math.sqrt(disx^2 + disz^2 + disy^2) end end function AngleToPoint(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