@@ -9,18 +9,14 @@ function HumanBehaviors.GetTeamShootingSkill(team)
9
9
end
10
10
11
11
local aimSpeed , aimSkill
12
- if skill < Activity .AVERAGESKILL then -- the AI shoot later and tracks the target slower
13
- aimSpeed = - 0.025 * skill + 3.3 -- affects the delay before the shooting starts [3.30 .. 1.55]
14
- aimSkill = - 0.011 * skill + 2.2 -- affects the precision of the shots [2.20 .. 1.43]
15
- elseif skill >= Activity .UNFAIRSKILL then
16
- aimSpeed = 0.05
17
- aimSkill = 0.05
12
+ if skill >= Activity .UNFAIRSKILL then
13
+ aimSpeed = 0.04
14
+ aimSkill = 0.04
18
15
else
19
16
-- the AI shoot sooner and with slightly better precision
20
- aimSpeed = 1 / (0.55 / (2.9 - math.exp (skill * 0.01 ))) -- [1.42 .. 0.38]
21
- aimSkill = 1 / (0.65 / (3.0 - math.exp (skill * 0.01 ))) -- [1.36 .. 0.48]
17
+ aimSpeed = 1 / (0.65 / (2.9 - math.exp (skill * 0.01 )))
18
+ aimSkill = 1 / (0.75 / (3.0 - math.exp (skill * 0.01 )))
22
19
end
23
-
24
20
return aimSpeed , aimSkill , skill
25
21
end
26
22
36
32
37
33
-- spot targets by casting a ray in a random direction
38
34
function HumanBehaviors .LookForTargets (AI , Owner , Skill )
39
- local viewAngDeg = RangeRand (50 , 120 ) * Owner .Perceptiveness * (0.5 + Skill / 200 )
35
+ local viewAngDeg = RangeRand (50 , 120 ) * Owner .Perceptiveness * (0.5 + Skill / 200 )
40
36
if AI .deviceState == AHuman .AIMING then
41
37
AI .Ctrl :SetState (Controller .AIM_SHARP , true ) -- reinforce sharp aim controller state to enable SharpLength in LookForMOs
42
- viewAngDeg = 15 * Owner .Perceptiveness + (Skill / 10 )
38
+ viewAngDeg = 15 * Owner .Perceptiveness + (Skill / 10 )
43
39
end
44
40
45
41
local FoundMO = Owner :LookForMOs (viewAngDeg , rte .grassID , false )
@@ -84,6 +80,8 @@ function HumanBehaviors.CheckEnemyLOS(AI, Owner, Skill)
84
80
85
81
local LookTarget
86
82
if Enemy .ClassName == " ADoor" then
83
+ -- TO-DO: use explosive weapons on doors?
84
+
87
85
local Door = ToADoor (Enemy ).Door
88
86
if Door and Door :IsAttached () then
89
87
LookTarget = Door .Pos
@@ -257,7 +255,7 @@ function HumanBehaviors.GetGrenadeAngle(AimPoint, TargetVel, StartPos, muzVel)
257
255
Dist = SceneMan :ShortestDistance (StartPos , AimPoint , false )
258
256
end
259
257
260
- Dist = Dist / FrameMan . PPM -- convert from pixels to meters
258
+ Dist = Dist / GetPPM () -- convert from pixels to meters
261
259
local velSqr = math.pow (muzVel , 2 )
262
260
local gravity = SceneMan .GlobalAcc .Y * 0.67 -- underestimate gravity
263
261
local root = math.sqrt (velSqr * velSqr - gravity * (gravity * Dist .X * Dist .X + 2 *- Dist .Y * velSqr ))
@@ -500,8 +498,7 @@ function HumanBehaviors.Sentry(AI, Owner, Abort)
500
498
elseif AI .SentryFacing and Owner .HFlipped ~= AI .SentryFacing then
501
499
Owner .HFlipped = AI .SentryFacing -- turn to the direction we have been order to guard
502
500
break -- restart this behavior
503
- elseif math.random () < Owner .Perceptiveness then
504
-
501
+ elseif AI .Target == nil and math.random () < Owner .Perceptiveness then
505
502
-- turn around occasionally if there is open space behind our back
506
503
local backAreaRay = Vector (- math.random (FrameMan .PlayerScreenWidth / 4 , FrameMan .PlayerScreenWidth / 2 ) * Owner .FlipFactor , 0 ):DegRotate (math.random (- 25 , 25 ) * Owner .Perceptiveness )
507
504
if not SceneMan :CastStrengthRay (Owner .EyePos , backAreaRay , 10 , Vector (), 10 , rte .grassID , SceneMan .SceneWrapsX ) then
@@ -1682,13 +1679,12 @@ function HumanBehaviors.GoToWpt(AI, Owner, Abort)
1682
1679
else
1683
1680
nextLatMove = Actor .LAT_STILL
1684
1681
end
1685
- if not (Owner .FGLeg and Owner .BGLeg ) and not AI .jump then
1686
- Owner :GetController ():SetState (Controller .BODY_CROUCH ,true ) -- crawl if no legs
1687
- end
1688
1682
end
1689
1683
elseif ((CurrDist .X < - 5 and Owner .HFlipped ) or (CurrDist .X > 5 and not Owner .HFlipped )) and math.abs (Owner .Vel .X ) < 1 then
1690
1684
-- no legs, jump forward
1691
1685
AI .jump = true
1686
+ elseif not AI .jump then
1687
+ AI .proneState = AHuman .GOPRONE
1692
1688
end
1693
1689
1694
1690
if Waypoint .Type == " right" then
@@ -1715,8 +1711,8 @@ function HumanBehaviors.GoToWpt(AI, Owner, Abort)
1715
1711
-- predict jetpack movement when jumping and there is a target (check one direction)
1716
1712
local jetStrength = AI .jetImpulseFactor / Owner .Mass
1717
1713
local t = math.min (0.4 , Owner .JetTimeLeft * 0.001 )
1718
- local PixelVel = Owner .Vel * (FrameMan . PPM * t )
1719
- local Accel = SceneMan .GlobalAcc * FrameMan . PPM
1714
+ local PixelVel = Owner .Vel * (GetPPM () * t )
1715
+ local Accel = SceneMan .GlobalAcc * GetPPM ()
1720
1716
1721
1717
-- a burst use 10x more fuel
1722
1718
if Owner .Jetpack :CanTriggerBurst () then
@@ -1779,8 +1775,8 @@ function HumanBehaviors.GoToWpt(AI, Owner, Abort)
1779
1775
-- predict jetpack movement...
1780
1776
local jetStrength = AI .jetImpulseFactor / Owner .Mass
1781
1777
local t = math.min (0.4 , Owner .JetTimeLeft * 0.001 )
1782
- local PixelVel = Owner .Vel * (FrameMan . PPM * t )
1783
- local Accel = SceneMan .GlobalAcc * FrameMan . PPM
1778
+ local PixelVel = Owner .Vel * (GetPPM () * t )
1779
+ local Accel = SceneMan .GlobalAcc * GetPPM ()
1784
1780
1785
1781
-- a burst use 10x more fuel
1786
1782
if Owner .Jetpack :CanTriggerBurst () then
@@ -1821,7 +1817,7 @@ function HumanBehaviors.GoToWpt(AI, Owner, Abort)
1821
1817
local delta = SceneMan :ShortestDistance (Waypoint .Pos , FallPos , false ).Magnitude - Facings [1 ].range
1822
1818
if delta < 1 then
1823
1819
AI .jump = false
1824
- elseif AI .flying or delta > 15 then
1820
+ elseif AI .flying or delta > 25 then
1825
1821
AI .jump = true
1826
1822
nextAimAngle = Owner :GetAimAngle (false ) * 0.5 + Facings [1 ].aim * 0.5 -- adjust jetpack nozzle direction
1827
1823
nextLatMove = Actor .LAT_STILL
@@ -2146,32 +2142,32 @@ function HumanBehaviors.GetProjectileData(Owner)
2146
2142
2147
2143
-- find muzzle velocity
2148
2144
PrjDat .vel = Weapon :GetAIFireVel ()
2149
-
2150
2145
-- half of the theoretical upper limit for the total amount of material strength this weapon can destroy in 250ms
2151
- PrjDat .pen = Weapon :GetAIPenetration () * math.max ((Weapon .RateOfFire / 240 ), 1 )
2152
2146
2153
2147
PrjDat .g = SceneMan .GlobalAcc .Y * 0.67 * Weapon :GetBulletAccScalar () -- underestimate gravity
2154
2148
PrjDat .vsq = PrjDat .vel ^ 2 -- muzzle velocity squared
2155
2149
PrjDat .vqu = PrjDat .vsq ^ 2 -- muzzle velocity quad
2156
2150
PrjDat .drg = 1 - Projectile .AirResistance * TimerMan .DeltaTimeSecs -- AirResistance is stored as the ini-value times 60
2157
2151
PrjDat .thr = math.min (Projectile .AirThreshold , PrjDat .vel )
2152
+ PrjDat .pen = (Projectile .Mass * Projectile .Sharpness * PrjDat .vel ) * PrjDat .drg
2158
2153
2159
2154
-- estimate theoretical max range with ...
2160
2155
local lifeTime = Weapon :GetAIBulletLifeTime ()
2161
2156
if lifeTime < 1 then -- infinite life time
2162
2157
PrjDat .rng = math.huge
2163
2158
elseif PrjDat .drg < 1 then -- AirResistance
2164
2159
PrjDat .rng = 0
2165
- local threshold = PrjDat .thr * FrameMan .PPM * TimerMan .DeltaTimeSecs -- AirThreshold in pixels/frame
2166
- local vel = PrjDat .vel * FrameMan .PPM * TimerMan .DeltaTimeSecs -- muzzle velocity in pixels/frame
2160
+ local threshold = PrjDat .thr * rte .PxTravelledPerFrame -- AirThreshold in pixels/frame
2161
+ local vel = PrjDat .vel * rte .PxTravelledPerFrame -- muzzle velocity in pixels/frame
2162
+
2167
2163
for _ = 0 , math.ceil (lifeTime / TimerMan .DeltaTimeMS ) do
2168
2164
PrjDat .rng = PrjDat .rng + vel
2169
2165
if vel > threshold then
2170
2166
vel = vel * PrjDat .drg
2171
2167
end
2172
2168
end
2173
2169
else -- no AirResistance
2174
- PrjDat .rng = PrjDat .vel * FrameMan . PPM * TimerMan . DeltaTimeSecs * (lifeTime / TimerMan .DeltaTimeMS )
2170
+ PrjDat .rng = PrjDat .vel * rte . PxTravelledPerFrame * (lifeTime / TimerMan .DeltaTimeMS )
2175
2171
end
2176
2172
2177
2173
-- Artificially decrease reported range to make sure AI
@@ -2633,9 +2629,9 @@ function HumanBehaviors.ThrowTarget(AI, Owner, Abort)
2633
2629
local scan = 0
2634
2630
local miss = 0 -- stop scanning after a few missed attempts
2635
2631
local AimPoint , Dist , MO , ID , rootID , LOS , aim
2636
-
2632
+
2637
2633
AI .TargetLostTimer :SetSimTimeLimitMS (1500 )
2638
-
2634
+
2639
2635
while true do
2640
2636
if not MovableMan :ValidMO (AI .Target ) then
2641
2637
break
@@ -2747,7 +2743,7 @@ function HumanBehaviors.ThrowTarget(AI, Owner, Abort)
2747
2743
aim = HumanBehaviors .GetGrenadeAngle (AimPoint , Vector (), Grenade .MuzzlePos , Grenade .MaxThrowVel )
2748
2744
if aim then
2749
2745
ThrowTimer :Reset ()
2750
- aimTime = RangeRand (1000 , 1200 )
2746
+ aimTime = RangeRand (900 , 1100 )
2751
2747
local maxAim = aim
2752
2748
2753
2749
-- try again with an average throw vel
@@ -2829,24 +2825,22 @@ function HumanBehaviors.AttackTarget(AI, Owner, Abort)
2829
2825
local meleeDist = 0
2830
2826
local startPos = Vector (Owner .EyePos .X , Owner .EyePos .Y )
2831
2827
2832
- if Owner .EquippedItem then
2833
- if Owner .EquippedItem :HasObjectInGroup (" Tools - Diggers" ) or Owner .EquippedItem :HasObjectInGroup (" Weapons - Melee" ) then
2834
- meleeDist = Owner .Radius + 25
2835
- startPos = Vector (Owner .EquippedItem .Pos .X , Owner .EquippedItem .Pos .Y )
2836
- end
2828
+ if Owner :EquipDeviceInGroup (" Tools - Diggers" , true ) or Owner :EquipDeviceInGroup (" Weapons - Melee" , true ) then
2829
+ meleeDist = Owner .Radius + 25
2830
+ startPos = Vector (Owner .EquippedItem .Pos .X , Owner .EquippedItem .Pos .Y )
2837
2831
elseif Owner .armSway then
2838
- if Owner .FGArm then
2839
- meleeDist = Owner .Radius + Owner .FGArm .Radius
2840
- startPos = Owner .FGArm .Pos
2841
- elseif Owner .BGArm then
2842
- meleeDist = Owner .Radius + Owner .BGArm .Radius
2843
- startPos = Owner .BGArm .Pos
2832
+ local arm = Owner .FGArm or Owner .BGArm
2833
+ if arm then
2834
+ meleeDist = arm .Radius + arm .Radius
2835
+ startPos = arm .Pos
2844
2836
end
2845
2837
end
2846
2838
if meleeDist > 0 then
2847
- local dist = SceneMan :ShortestDistance (startPos , AI .Target .Pos , false )
2839
+ local attackPos = (AI .Target .ClassName == " ADoor" and ToADoor (AI .Target ).Door and ToADoor (AI .Target ).Door :IsAttached ()) and ToADoor (AI .Target ).Door .Pos or AI .Target .Pos
2840
+ local dist = SceneMan :ShortestDistance (startPos , attackPos , false )
2848
2841
if dist .Magnitude < meleeDist then
2849
- AI .Ctrl .AnalogAim = SceneMan :ShortestDistance (Owner .EyePos , AI .Target .Pos , false ).Normalized
2842
+ AI .lateralMoveState = Actor .LAT_STILL
2843
+ AI .Ctrl .AnalogAim = SceneMan :ShortestDistance (Owner .EyePos , attackPos , false ).Normalized
2850
2844
AI .fire = true
2851
2845
else
2852
2846
AI .fire = false
@@ -2931,7 +2925,7 @@ function HumanBehaviors.GetAngleToHit(PrjDat, Dist)
2931
2925
return Dist .AbsRadAngle
2932
2926
else -- compensate for gravity
2933
2927
local rootSq , muzVelSq
2934
- local D = Dist / FrameMan . PPM -- convert from pixels to meters
2928
+ local D = Dist / GetPPM () -- convert from pixels to meters
2935
2929
if PrjDat .drg < 1 then -- compensate for air resistance
2936
2930
local rng = D .Magnitude
2937
2931
local timeToTarget = math.floor ((rng / math.max (PrjDat .vel * PrjDat .drg ^ math.floor (rng / (PrjDat .vel + 1 )+ 0.5 ), PrjDat .thr )) / TimerMan .DeltaTimeSecs ) -- estimate time of flight in frames
0 commit comments