so i have some form of it working, they can stray a set distance from the point they are aggroed if the player is more than the minimum range (edit; added a check so they can move within minimum range if player isn't visible).
they return to the patrol if the player moves out of sight for a while (time set in the script)
it's still possible to lure them away if you keep swapping them from attack to patrol (as the distance gets reset each time they enter attack state) but it's certainly not like the default AI.
let me know if you need it changed.
ai_on_path.lua
local headshots_on = 1 --set to 0 if you dont want characters to instantly die from a headshot
local headshot_damage = 50 --set how much damage to apply for a headshot (if headshots are set to on/1)
local lose_interest_delay = 4000 --how long before we go back to patrol state if player moves out of range/sight
local max_move = 500 --how far away from the path the character can move if aggro/attacking
local min_attack_range = 750 --wont move towards player if within this range
local alert_range = 400 --cant see player but we can "detect" him (sneaking behind character?)
local startx = {}
local startz = {}
function ai_on_path_init(e)
ai_soldier_state[e] = "patrol"
ai_soldier_pathindex[e] = -1
end
function ai_on_path_main(e)
EntObjNo = g_Entity[e]['obj']
-- Patrol Mode
if ai_soldier_state[e] == "patrol" then
CharacterControlUnarmed(e)
-- 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
-- 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
-- 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
if (g_Entity[e]['plrvisible'] == 1 and GetPlayerDistance(e) < 1500+max_move) or AIGetEntityHeardSound(EntObjNo) == 1 or GetPlayerDistance(e) < alert_range then
AIEntityGoToPosition(EntObjNo,g_Entity[e]['x'],g_Entity[e]['z'])
startx[e] = g_Entity[e]['x']
startz[e] = g_Entity[e]['z']
StartTimer(e)
ai_soldier_state[e] = "attack"
end
elseif ai_soldier_state[e] == "attack" then
CharacterControlArmed(e)
RotateToPlayer(e)
if (GetPlayerDistance(e) > min_attack_range or g_Entity[e]['plrvisible'] == 0) and GetDistanceToPoint(e,startx[e],startz[e]) < max_move then
AIEntityGoToPosition(EntObjNo,g_PlayerPosX,g_PlayerPosZ)
else
AIEntityGoToPosition(EntObjNo,g_Entity[e]['x'],g_Entity[e]['z'])
end
if g_Entity[e]['plrvisible'] == 1 and GetPlayerDistance(e) < 1500 then
StartTimer(e)
FireWeapon(e)
else
if GetTimer(e) > lose_interest_delay then
ai_soldier_state[e] = "patrol"
end
end
end --state
if headshots_on == 1 then
if ai_soldier_state[e] ~= "deathanim" then
if string.find(string.lower(g_Entity[e]['limbhit']), "head") ~= nil then
ai_soldier_state[e] = "deathanim"
PlayCharacterSound(e,"onDeath")
StartTimer(e)
CharacterControlLimbo(e)
BulletRayDX = g_Entity[e]['x'] - g_PlayerPosX;
BulletRayDY = g_Entity[e]['y'] - g_PlayerPosY;
BulletRayDZ = g_Entity[e]['z'] - g_PlayerPosZ;
BulletAngle = (math.atan2(BulletRayDX,BulletRayDZ)/6.28)*360
BulletAngle = BulletAngle + g_Entity[e]['angley']
if BulletAngle < 0 then
BulletAngle = BulletAngle + 360
end
if BulletAngle >= 360 then
BulletAngle = BulletAngle - 360
end
if BulletAngle >= 360 then
BulletAngle = BulletAngle - 360
end
if BulletAngle >= 360-45 or BulletAngle <= 0+45 then
SetAnimationFrames(5031,5050)
SetAnimationFrame(e,5031)
end
if BulletAngle >= 180-45 and BulletAngle <= 180+45 then
SetAnimationFrames(4972,5002)
SetAnimationFrame(e,4972)
end
if BulletAngle >= 90-45 and BulletAngle <= 90+45 then
-- side hit animations not aligned for this technique (yet)
SetAnimationFrames(4972,5002)
SetAnimationFrame(e,4972)
end
if BulletAngle >= 270-45 and BulletAngle <= 270+45 then
-- side hit animations not aligned for this technique (yet)
SetAnimationFrames(4972,5002)
SetAnimationFrame(e,4972)
end
PlayAnimation(e)
ModulateSpeed(e,1.0)
SetAnimationSpeed(e,1.5)
end
else --DeathAnim Else
-- wait until death anim mostly over, then switch to ragdoll
if GetTimer(e)>200 then
SetEntityHealth(e,g_Entity[e]['health']-headshot_damage)
BulletRayDX = g_Entity[e]['x'] - g_PlayerPosX;
BulletRayDY = g_Entity[e]['y'] - g_PlayerPosY;
BulletRayDZ = g_Entity[e]['z'] - g_PlayerPosZ;
SetEntityRagdollForce(e,g_Entity[e]['limbhitindex'],BulletRayDX,BulletRayDY,BulletRayDZ,750)
ResetLimbHit(e)
end
end --DeathAnim Endif
end
end --main
function ai_on_path_exit(e)
if ai_soldier_state[e] ~= "deathanim" then
PlayCharacterSound(e,"onDeath")
end
end
function GetDistanceToPoint(e,x,z)
if g_Entity[e] ~= nil and g_Entity[e] ~= 0 then
local disx = g_Entity[e]['x'] - x
local disz = g_Entity[e]['z'] - z
return math.sqrt(disx^2 + disz^2)
end
end
life\'s one big game
windows vista ultimate
i5 @3.3ghz, 4gb ram, AMD R9 200 series , directx 11