@@ -21,7 +21,7 @@ function HumanBehaviors.GetTeamShootingSkill(team)
21
21
aimSkill = 1 / (0.65 / (3.0 - math.exp (skill * 0.01 ))) -- [1.36 .. 0.48]
22
22
end
23
23
24
- return aimSpeed , aimSkill
24
+ return aimSpeed , aimSkill , skill
25
25
end
26
26
27
27
function HumanBehaviors .SetShootingSkill ()
@@ -35,10 +35,11 @@ function HumanBehaviors.GetShootingSkill()
35
35
end
36
36
37
37
-- spot targets by casting a ray in a random direction
38
- function HumanBehaviors .LookForTargets (AI , Owner )
39
- local viewAngDeg = RangeRand (35 , 85 )
38
+ function HumanBehaviors .LookForTargets (AI , Owner , Skill )
39
+ local viewAngDeg = RangeRand (50 , 120 ) * ( 0.5 + Skill / 200 )
40
40
if AI .deviceState == AHuman .AIMING then
41
- viewAngDeg = 20
41
+ AI .Ctrl :SetState (Controller .AIM_SHARP , true ) -- reinforce sharp aim controller state to enable SharpLength in LookForMOs
42
+ viewAngDeg = 15 + (Skill / 10 )
42
43
end
43
44
44
45
local FoundMO = Owner :LookForMOs (viewAngDeg , rte .grassID , false )
@@ -52,24 +53,24 @@ function HumanBehaviors.LookForTargets(AI, Owner)
52
53
end
53
54
end
54
55
55
- -- brains spot targets by casting rays at all nearby enemy actors
56
- function HumanBehaviors .CheckEnemyLOS (AI , Owner )
56
+ -- brains and snipers spot targets by casting rays at all nearby enemy actors
57
+ function HumanBehaviors .CheckEnemyLOS (AI , Owner , Skill )
57
58
if not AI .Enemies then -- add all enemy actors on our screen to a table and check LOS to them, one per frame
58
59
AI .Enemies = {}
59
60
for Act in MovableMan .Actors do
60
61
if Act .Team ~= Owner .Team then
61
62
if not AI .isPlayerOwned or not SceneMan :IsUnseen (Act .Pos .X , Act .Pos .Y , Owner .Team ) then -- AI-teams ignore the fog
62
63
local Dist = SceneMan :ShortestDistance (Owner .ViewPoint , Act .Pos , false )
63
- if (math.abs (Dist .X ) - Act .Diameter < FrameMan .PlayerScreenWidth * 0.6 ) and
64
- (math.abs (Dist .Y ) - Act .Diameter < FrameMan .PlayerScreenHeight * 0.6 )
64
+ if (math.abs (Dist .X ) - Act .Diameter < FrameMan .PlayerScreenWidth * ( 0.4 + Skill * 0.005 ) ) and
65
+ (math.abs (Dist .Y ) - Act .Diameter < FrameMan .PlayerScreenHeight * ( 0.4 + Skill * 0.005 ) )
65
66
then
66
67
table.insert (AI .Enemies , Act )
67
68
end
68
69
end
69
70
end
70
71
end
71
72
72
- return HumanBehaviors .LookForTargets (AI , Owner ) -- cast rays like normal actors occasionally
73
+ return HumanBehaviors .LookForTargets (AI , Owner , Skill ) -- cast rays like normal actors occasionally
73
74
else
74
75
local Enemy = table.remove (AI .Enemies )
75
76
if Enemy then
@@ -87,7 +88,7 @@ function HumanBehaviors.CheckEnemyLOS(AI, Owner)
87
88
if Door and Door :IsAttached () then
88
89
LookTarget = Door .Pos
89
90
else
90
- return HumanBehaviors .LookForTargets (AI , Owner ) -- this door is destroyed, cast rays like normal actors
91
+ return HumanBehaviors .LookForTargets (AI , Owner , Skill ) -- this door is destroyed, cast rays like normal actors
91
92
end
92
93
else
93
94
LookTarget = Enemy .Pos
@@ -133,7 +134,7 @@ function HumanBehaviors.CheckEnemyLOS(AI, Owner)
133
134
end
134
135
else
135
136
AI .Enemies = nil
136
- return HumanBehaviors .LookForTargets (AI , Owner ) -- cast rays like normal actors occasionally
137
+ return HumanBehaviors .LookForTargets (AI , Owner , Skill ) -- cast rays like normal actors occasionally
137
138
end
138
139
end
139
140
end
@@ -273,13 +274,14 @@ end
273
274
274
275
-- deprecated since B30. make sure we equip our preferred device if we have one. return true if we must run this function again to be sure
275
276
function HumanBehaviors .EquipPreferredWeapon (AI , Owner )
276
- if AI .PlayerPreferredHD then
277
- Owner :EquipNamedDevice (AI .PlayerPreferredHD , true )
278
- elseif not Owner :EquipDeviceInGroup (" Weapons - Primary" , true ) then
279
- Owner :EquipDeviceInGroup (" Weapons - Secondary" , true )
277
+ if AI .squadShoot == false then
278
+ if AI .PlayerPreferredHD then
279
+ Owner :EquipNamedDevice (AI .PlayerPreferredHD , true )
280
+ elseif not Owner :EquipDeviceInGroup (" Weapons - Primary" , true ) then
281
+ Owner :EquipDeviceInGroup (" Weapons - Secondary" , true )
282
+ end
283
+ return false
280
284
end
281
-
282
- return false
283
285
end
284
286
285
287
-- deprecated since B30. make sure we equip a primary weapon if we have one. return true if we must run this function again to be sure
@@ -840,7 +842,7 @@ function HumanBehaviors.BrainSearch(AI, Owner, Abort)
840
842
Owner :AddAIMOWaypoint (Brains [1 ])
841
843
AI :CreateGoToBehavior (Owner )
842
844
end
843
- else
845
+ else -- lobotomy test
844
846
local ClosestBrain
845
847
local minDist = math.huge
846
848
for _ , Act in pairs (Brains ) do
@@ -893,9 +895,10 @@ function HumanBehaviors.BrainSearch(AI, Owner, Abort)
893
895
end
894
896
end
895
897
896
- Owner :ClearAIWaypoints ()
897
-
898
- if MovableMan :IsActor (ClosestBrain ) then
898
+ -- Owner:ClearAIWaypoints() -- this part freezes the script when facing the opposing brain
899
+ --
900
+ if MovableMan :IsActor (ClosestBrain ) then --
901
+ Owner :ClearAIWaypoints () -- moving the function here fixes it (4zK)
899
902
Owner :AddAIMOWaypoint (ClosestBrain )
900
903
AI :CreateGoToBehavior (Owner )
901
904
else
914
917
function HumanBehaviors .WeaponSearch (AI , Owner , Abort )
915
918
local minDist
916
919
local Devices = {}
917
- local pickupDiggers = not Owner :HasObjectInGroup (" Diggers" )
920
+ local pickupDiggers = not Owner :HasObjectInGroup (" Tools - Diggers" )
918
921
919
922
if AI .isPlayerOwned then
920
923
minDist = 100 -- don't move player actors more than 4m
@@ -960,7 +963,7 @@ function HumanBehaviors.WeaponSearch(AI, Owner, Abort)
960
963
elseif Item .ClassName == " TDExplosive" then
961
964
score = waypoints * 1.4 -- avoid grenades if there are other weapons
962
965
elseif Item :IsTool () then
963
- if pickupDiggers and Item :HasObjectInGroup (" Diggers" ) then
966
+ if pickupDiggers and Item :HasObjectInGroup (" Tools - Diggers" ) then
964
967
score = waypoints * 1.8 -- avoid diggers if there are other weapons
965
968
else
966
969
waypoints = minDist -- don't pick up
@@ -1061,7 +1064,7 @@ function HumanBehaviors.ToolSearch(AI, Owner, Abort)
1061
1064
1062
1065
local DevicesToPickUp = {}
1063
1066
for _ , Item in pairs (Devices ) do
1064
- if MovableMan :ValidMO (Item ) and Item :HasObjectInGroup (" Diggers" ) then
1067
+ if MovableMan :ValidMO (Item ) and Item :HasObjectInGroup (" Tools - Diggers" ) then
1065
1068
-- estimate the walking distance to the item
1066
1069
local waypoints = SceneMan .Scene :CalculatePath (Owner .Pos , Item .Pos , false , 1 )
1067
1070
if waypoints < minDist and waypoints > - 1 then
@@ -1328,7 +1331,7 @@ function HumanBehaviors.GoToWpt(AI, Owner, Abort)
1328
1331
local Free = Vector ()
1329
1332
1330
1333
-- only if we have a digging tool
1331
- if Waypoint .Type ~= " drop" and Owner :HasObjectInGroup (" Diggers" ) then
1334
+ if Waypoint .Type ~= " drop" and Owner :HasObjectInGroup (" Tools - Diggers" ) then
1332
1335
local PathSegRay = SceneMan :ShortestDistance (PrevWptPos , Waypoint .Pos , false ) -- detect material blocking the path and start digging through it
1333
1336
if AI .teamBlockState ~= Actor .BLOCKED and SceneMan :CastStrengthRay (PrevWptPos , PathSegRay , 4 , Free , 2 , rte .doorID , true ) then
1334
1337
if SceneMan :ShortestDistance (Owner .Pos , Free , false ).Magnitude < Owner .Height * 0.4 then -- check that we're close enough to start digging
@@ -1672,6 +1675,9 @@ function HumanBehaviors.GoToWpt(AI, Owner, Abort)
1672
1675
else
1673
1676
nextLatMove = Actor .LAT_STILL
1674
1677
end
1678
+ if not (Owner .FGLeg and Owner .BGLeg ) and not AI .jump then
1679
+ Owner :GetController ():SetState (Controller .BODY_CROUCH ,true ) -- crawl if no legs
1680
+ end
1675
1681
end
1676
1682
elseif ((CurrDist .X < - 5 and Owner .HFlipped ) or (CurrDist .X > 5 and not Owner .HFlipped )) and math.abs (Owner .Vel .X ) < 1 then
1677
1683
-- no legs, jump forward
@@ -2001,7 +2007,11 @@ function HumanBehaviors.GoToWpt(AI, Owner, Abort)
2001
2007
if (AI .Target and AI .BehaviorName ~= " AttackTarget" ) or
2002
2008
(Owner .AIMode ~= Actor .AIMODE_SQUAD and (AI .BehaviorName == " ShootArea" or AI .BehaviorName == " FaceAlarm" ))
2003
2009
then
2004
- AI .lateralMoveState = Actor .LAT_STILL
2010
+ if Owner .aggressive then -- the aggressive behavior setting makes the AI pursue waypoint at all times
2011
+ AI .lateralMoveState = nextLatMove
2012
+ else
2013
+ AI .lateralMoveState = Actor .LAT_STILL
2014
+ end
2005
2015
if not AI .flying then
2006
2016
AI .jump = false
2007
2017
end
@@ -2306,7 +2316,7 @@ function HumanBehaviors.ShootTarget(AI, Owner, Abort)
2306
2316
aimTarget = Dist .AbsRadAngle
2307
2317
AI .canHitTarget = true
2308
2318
if Owner .InventorySize > 0 then -- we have more things in the inventory
2309
- if range < 60 and Owner :HasObjectInGroup (" Diggers" ) then
2319
+ if range < 60 and Owner :HasObjectInGroup (" Tools - Diggers" ) then
2310
2320
AI :CreateHtHBehavior (Owner )
2311
2321
break
2312
2322
elseif Owner :EquipLoadedFirearmInGroup (" Any" , " Weapons - Explosive" , true ) then
@@ -2421,7 +2431,9 @@ function HumanBehaviors.ShootTarget(AI, Owner, Abort)
2421
2431
end
2422
2432
2423
2433
if AI .canHitTarget then
2424
- AI .lateralMoveState = Actor .LAT_STILL
2434
+ if not Owner .aggressive then
2435
+ AI .lateralMoveState = Actor .LAT_STILL
2436
+ end
2425
2437
if not AI .flying then
2426
2438
AI .deviceState = AHuman .AIMING
2427
2439
end
@@ -2806,19 +2818,34 @@ function HumanBehaviors.AttackTarget(AI, Owner, Abort)
2806
2818
if not AI .Target or not MovableMan :ValidMO (AI .Target ) then
2807
2819
break
2808
2820
end
2821
+ -- use following sequence to attack either with a suited melee weapon or arms
2822
+ local meleeDist = 0
2823
+ local startPos = Vector (Owner .EyePos .X , Owner .EyePos .Y )
2809
2824
2810
2825
if Owner .EquippedItem then
2811
- if Owner .EquippedItem :HasObjectInGroup (" Diggers" ) then -- attack with digger
2812
- local Dist = SceneMan :ShortestDistance (Owner .EquippedItem .Pos , AI .Target .Pos , false )
2813
- if Dist .Magnitude < 40 then
2814
- AI .Ctrl .AnalogAim = SceneMan :ShortestDistance (Owner .EyePos , AI .Target .Pos , false ).Normalized
2815
- AI .fire = true
2816
- else
2817
- AI .fire = false
2818
- end
2819
- elseif not Owner :EquipDiggingTool (true ) then
2820
- break
2826
+ if Owner .EquippedItem :HasObjectInGroup (" Tools - Diggers" ) or Owner .EquippedItem :HasObjectInGroup (" Weapons - Melee" ) then
2827
+ meleeDist = Owner .Radius + 25
2828
+ startPos = Vector (Owner .EquippedItem .Pos .X , Owner .EquippedItem .Pos .Y )
2829
+ end
2830
+ elseif Owner .armSway then
2831
+ if Owner .FGArm then
2832
+ meleeDist = Owner .Radius + Owner .FGArm .Radius
2833
+ startPos = Owner .FGArm .Pos
2834
+ elseif Owner .BGArm then
2835
+ meleeDist = Owner .Radius + Owner .BGArm .Radius
2836
+ startPos = Owner .BGArm .Pos
2821
2837
end
2838
+ end
2839
+ if meleeDist > 0 then
2840
+ local dist = SceneMan :ShortestDistance (startPos , AI .Target .Pos , false )
2841
+ if dist .Magnitude < meleeDist then
2842
+ AI .Ctrl .AnalogAim = SceneMan :ShortestDistance (Owner .EyePos , AI .Target .Pos , false ).Normalized
2843
+ AI .fire = true
2844
+ else
2845
+ AI .fire = false
2846
+ end
2847
+ else
2848
+ break
2822
2849
-- else TODO: periodically look for weapons?
2823
2850
end
2824
2851
end
@@ -3070,7 +3097,9 @@ function HumanBehaviors.FaceAlarm(AI, Owner, Abort)
3070
3097
AI .AlarmPos = nil
3071
3098
for _ = 1 , math.ceil (200 / TimerMan .DeltaTimeMS ) do
3072
3099
AI .deviceState = AHuman .AIMING
3073
- AI .lateralMoveState = Actor .LAT_STILL
3100
+ if not Owner .aggressive then
3101
+ AI .lateralMoveState = Actor .LAT_STILL
3102
+ end
3074
3103
AI .Ctrl .AnalogAim = AlarmDist .Normalized
3075
3104
local _ai , _ownr , _abrt = coroutine.yield () -- wait until next frame
3076
3105
if _abrt then return true end
0 commit comments