Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_AIGetAimErrorOffset.c
Go to the documentation of this file.
8
10{
11 static const string PORT_ERROR_OFFSET = "ErrorOffset";
12 static const string PORT_BASE_TARGET = "BaseTargetIn";
13 static const string PORT_AIM_POINT = "AimPoint";
14 static const string PORT_TOLERANCE = "AimingTolerance";
15 static const string PORT_AIMPOINT_TYPE_0 = "AimpointType0"; // Primary aimpoint type
16 static const string PORT_AIMPOINT_TYPE_1 = "AimpointType1"; // Secondary aimpoint type
17 static const float CLOSE_RANGE_THRESHOLD = 15.0;
18 static const float LONG_RANGE_THRESHOLD = 200.0;
19 static const float AIMING_ERROR_SCALE = 1.0; // TODO: game master and server option
20 static const float AIMING_ERROR_FACTOR_MIN = 0.4;
21 static const float AIMING_ERROR_CLOSE_RANGE_FACTOR_MIN = 0.05;
22 static const float AIMING_ERROR_FACTOR_MAX = 1.4;
23 static const float MAXIMAL_TOLERANCE = 10.0;
24 static const float MINIMAL_TOLERANCE = 0.003;
25
26 protected SCR_AICombatComponent m_CombatComponent;
27 // private SCR_AIInfoComponent m_InfoComponent; temporary removed (adding threat effect later)
28
29#ifdef AI_DEBUG
30 protected ref array<ref Shape> m_aDebugShapes = {};
31#endif
32 [Attribute("2", UIWidgets.ComboBox, "Hit zone selection", "", ParamEnumArray.FromEnum(EAimingPreference) )]
34
35 [Attribute("0", UIWidgets.ComboBox, "AimPoint type for fixed option", "", ParamEnumArray.FromEnum(EAimPointType) )]
37
38 [Attribute("0.03", UIWidgets.EditBox, "Default PrecisionXY")]
39 protected float m_fDefaultPrecisionXY;
40
41 private int m_iTorsoCount = 0;
42
43 //------------------------------------------------------------------------------------------------
44 override void OnInit(AIAgent owner)
45 {
46 IEntity ent = owner.GetControlledEntity();
47 if (ent)
48 m_CombatComponent = SCR_AICombatComponent.Cast(ent.FindComponent(SCR_AICombatComponent));
49 //m_InfoComponent = SCR_AIInfoComponent.Cast(owner.FindComponent(SCR_AIInfoComponent));
50 }
51
52 //------------------------------------------------------------------------------------------------
53 protected static ref TStringArray s_aVarsOut = {
54 PORT_ERROR_OFFSET,
55 PORT_AIM_POINT,
56 PORT_TOLERANCE
57 };
58 override array<string> GetVariablesOut()
59 {
60 return s_aVarsOut;
61 }
62
63 //------------------------------------------------------------------------------------------------
64 protected static ref TStringArray s_aVarsIn = {
65 PORT_BASE_TARGET,
66 PORT_AIMPOINT_TYPE_0,
67 PORT_AIMPOINT_TYPE_1
68 };
69 override array<string> GetVariablesIn()
70 {
71 return s_aVarsIn;
72 }
73
74 //------------------------------------------------------------------------------------------------
75 override ENodeResult EOnTaskSimulate(AIAgent owner, float dt)
76 {
77 //if (!m_CombatComponent || !m_InfoComponent)
79 return ENodeResult.FAIL;
80
81 IEntity entity = owner.GetControlledEntity();
82 if (!entity)
83 return ENodeResult.FAIL;
84
85#ifdef AI_DEBUG
86 m_aDebugShapes.Clear();
87
88#endif
89
90 BaseTarget target;
91 GetVariableIn(PORT_BASE_TARGET, target);
92
93 // Bail if target is invalid
94 if (!target)
95 {
96 ClearPorts();
97 return ENodeResult.FAIL;
98 }
99
100 // Bail if target is invalid
101 IEntity targetEntity = target.GetTargetEntity();
102 if (!targetEntity)
103 {
104 ClearPorts();
105 return ENodeResult.FAIL;
106 }
107
108 // Resolve which aimpoint types to use
109 EAimPointType aimpointTypes[3];
110 EAimPointType aimpointType0, aimpointType1;
111 if (!GetVariableIn(PORT_AIMPOINT_TYPE_0, aimpointType0))
112 aimpointType0 = -1;
113 if (!GetVariableIn(PORT_AIMPOINT_TYPE_1, aimpointType1))
114 aimpointType1 = -1;
115 aimpointTypes[0] = aimpointType0;
116 aimpointTypes[1] = aimpointType1;
117 aimpointTypes[2] = m_eAimPointType;
118
119 // Try to find aimpoint
120 AimPoint aimPoint = GetAimPoint(target, aimpointTypes);
121
122 // Bail if aimpoint was not found
123 if (!aimPoint)
124 {
125 ClearPorts();
126 return ENodeResult.FAIL;
127 }
128
129 EWeaponType weaponType = m_CombatComponent.GetCurrentWeaponType();
130
131#ifdef AI_DEBUG
132 if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_AI_SHOW_TARGET_AIMPOINT))
133 m_aDebugShapes.Insert(Shape.CreateSphere(COLOR_YELLOW_A, ShapeFlags.NOZBUFFER | ShapeFlags.TRANSP, aimPoint.GetPosition(),aimPoint.GetDimension()));
134#endif
135
136 // Calculate angular bounds
137 vector offsetX, offsetY;
138 float angularSize, distance, tolerance;
139 GetTargetAngularBounds(entity, aimPoint, offsetX, offsetY, angularSize, distance);
140
141 // Correct aim point size based on factors
142 float distanceFactor = GetDistanceFactor(distance);
143 float offsetWeaponFactor = GetOffsetWeaponTypeFactor(weaponType);
144 float illuminationFactor = GetTargetIlluminationFactor(target);
145
146 EAISkill currentSkill = m_CombatComponent.GetAISkill();
147 offsetX = GetRandomFactor(currentSkill, 0) * offsetX * AIMING_ERROR_SCALE * distanceFactor * offsetWeaponFactor * illuminationFactor;
148 offsetY = GetRandomFactor(currentSkill, 0) * offsetY * AIMING_ERROR_SCALE * distanceFactor * offsetWeaponFactor * illuminationFactor;
149
150 tolerance = GetTolerance(entity, targetEntity, angularSize, distance, weaponType);
151
152 SetVariableOut(PORT_ERROR_OFFSET, offsetX + offsetY);
153 SetVariableOut(PORT_AIM_POINT, aimPoint);
154 SetVariableOut(PORT_TOLERANCE, tolerance);
155
156#ifdef WORKBENCH
157 // PrintFormat("Target size - used in tolerance: %1 target aimpointPosition: %2", distance * Math.Tan(tolerance * Math.DEG2RAD), aimPoint.GetPosition());
158#endif
159
160 return ENodeResult.SUCCESS;
161 }
162
164 {
165 ClearVariable(PORT_ERROR_OFFSET);
166 ClearVariable(PORT_AIM_POINT);
167 ClearVariable(PORT_TOLERANCE);
168 }
169
170 //----------------------------------------------------------------------------------------------------------------------------------------------
172 void GetTargetAngularBounds(IEntity shooter, AimPoint targetAimpoint, out vector sizeVectorX, out vector sizeVectorY, out float angularSize, out float distance)
173 {
174
175 vector shooterCenter, joinNorm, join, min, max;
176 float dimension = 2 * targetAimpoint.GetDimension();
177 shooter.GetWorldBounds(min,max);
178
179 // we wanted to use muzzle transform but that is unrelyable (when weapon switches, on init of fight, and so on)
180 shooterCenter = (min + max) * 0.5;
181 join = targetAimpoint.GetPosition() - shooterCenter;
182 distance = join.Length();
183 angularSize = Math.Atan2(dimension, distance) * Math.RAD2DEG;
184
185 joinNorm = join.Normalized();
186 sizeVectorX = (vector.Up * joinNorm).Normalized();
187 sizeVectorY = (joinNorm * sizeVectorX).Normalized();
188
189 sizeVectorX *= dimension;
190 sizeVectorY *= dimension;
191
192#ifdef AI_DEBUG
193 if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_AI_SHOW_TARGET_PROJECTED_SIZE))
194 {
195 m_aDebugShapes.Insert(Shape.CreateArrow(shooterCenter, shooterCenter + sizeVectorX, 0.1, COLOR_BLUE, ShapeFlags.NOZBUFFER));
196 m_aDebugShapes.Insert(Shape.CreateArrow(shooterCenter, shooterCenter + sizeVectorY, 0.1, COLOR_RED, ShapeFlags.NOZBUFFER));
197 m_aDebugShapes.Insert(Shape.CreateArrow(shooterCenter, shooterCenter + joinNorm * dimension, 0.1, COLOR_YELLOW, ShapeFlags.NOZBUFFER));
198 }
199#endif
200 }
201
202 //----------------------------------------------------------------------------------------------------------------------------------------------
205 {
206 if (distance < CLOSE_RANGE_THRESHOLD)
207 return Math.Map(distance, 0, CLOSE_RANGE_THRESHOLD, AIMING_ERROR_CLOSE_RANGE_FACTOR_MIN, AIMING_ERROR_FACTOR_MIN);
208
209 float distanceCl = Math.Clamp((distance - CLOSE_RANGE_THRESHOLD) / LONG_RANGE_THRESHOLD, 0, 1);
210 return Math.Lerp(AIMING_ERROR_FACTOR_MIN, AIMING_ERROR_FACTOR_MAX, distanceCl);
211 }
212
213 //------------------------------------------------------------------------------------------------
216 {
217 PerceivableComponent perceivable = tgt.GetPerceivableComponent();
218 if (!perceivable)
219 return 1.0;
220
221 if (perceivable.GetIlluminationFactor() < 0.5)
222 return 2.0;
223
224 return 1.0;
225 }
226
227 //------------------------------------------------------------------------------------------------
228 // returns random factor based on AI skill
229 float GetRandomFactor(EAISkill skill,float mu)
230 {
231 float sigma;
232 switch (skill)
233 {
234 case EAISkill.NOOB :
235 {
236 sigma = 4;
237 break;
238 }
239 case EAISkill.ROOKIE :
240 {
241 sigma = 2;
242 break;
243 }
244 case EAISkill.REGULAR :
245 {
246 sigma = 1;
247 break;
248 }
249 case EAISkill.VETERAN :
250 {
251 sigma = 0.5;
252 break;
253 }
254 case EAISkill.EXPERT :
255 {
256 sigma = 0.25;
257 break;
258 }
259 case EAISkill.CYLON :
260 {
261 return 0;
262 }
263 }
264 // PrintFormat("Gauss: %1, sigma: %2, skill: %3",result,sigma,typename.EnumToString(EAISkill,skill));
265 return Math.RandomGaussFloat(sigma,mu);
266 }
267
268 //------------------------------------------------------------------------------------------------
270 float GetTolerance(IEntity observer, IEntity target, float angularSize, float distance, EWeaponType weaponType)
271 {
272 float tolerance;
273 bool setMaxTolerance;
274
275 // Always use max tolerance in close range
276 if (distance < CLOSE_RANGE_THRESHOLD)
277 return MAXIMAL_TOLERANCE;
278
279 tolerance = angularSize / 2; // half of the size
280 // angular speed
281 tolerance *= GetAngularSpeedFactor(observer, target, setMaxTolerance);
282
283 if (setMaxTolerance)
284 tolerance = MAXIMAL_TOLERANCE;
285 else
286 {
287 // weapon type tolerance modifier
288 tolerance *= GetWeaponTypeFactor(weaponType);
289 };
290 return Math.Clamp(tolerance, MINIMAL_TOLERANCE, MAXIMAL_TOLERANCE);
291 }
292
293 //------------------------------------------------------------------------------------------------
294 float GetAngularSpeedFactor(IEntity observer, IEntity enemy, out bool setBigTolerance)
295 {
296 vector enemyVelocity;
297 IEntity enemyRoot = enemy.GetRootParent();
298 Physics enemyPhysics = enemyRoot.GetPhysics();
299 if (enemyPhysics)
300 enemyVelocity = enemyPhysics.GetVelocity();
301
302 vector observerVelocity;
303 vector observerAngularVelocity;
304 IEntity observerRoot = observer.GetRootParent();
305 Physics observerPhysics = observerRoot.GetPhysics();
306 if (observerPhysics)
307 {
308 observerVelocity = observerPhysics.GetVelocity();
309 observerAngularVelocity = observerPhysics.GetAngularVelocity();
310 }
311
312 vector relativeVelocity = enemyVelocity - observerVelocity;
313
314 vector positionVector = enemy.GetOrigin() - observer.GetOrigin();
315 vector targetLocalAngularVelocity = observerAngularVelocity + (positionVector * relativeVelocity / positionVector.LengthSq()); // omega = (r x v) / ||r||^2
316 float totalTargetLocalAngularVelocity = targetLocalAngularVelocity.Length();
317
318 if (totalTargetLocalAngularVelocity < 0.07) // rougly 4 degs in radians
319 return 1.0;
320 else if (totalTargetLocalAngularVelocity < 0.17) // roughly 10 degs in radians
321 return 2;
322
323 setBigTolerance = true;
324 return 0;
325 }
326
327 //------------------------------------------------------------------------------------------------
329 {
330 switch(weaponType)
331 {
332 case EWeaponType.WT_RIFLE:
333 {
334 return 1.0;
335 }
336 case EWeaponType.WT_MACHINEGUN:
337 {
338 return 2.0;
339 }
340 case EWeaponType.WT_HANDGUN:
341 {
342 return 1.5;
343 }
344 case EWeaponType.WT_FRAGGRENADE:
345 {
346 return 3.0;
347 }
348 case EWeaponType.WT_SMOKEGRENADE:
349 {
350 return 4.0;
351 }
352 case EWeaponType.WT_ROCKETLAUNCHER:
353 {
354 return 0.5;
355 }
356 case EWeaponType.WT_SNIPERRIFLE:
357 {
358 return 0.5;
359 }
360 }
361 return 1.0;
362 }
363
364 //------------------------------------------------------------------------------------------------
367 {
368 if (weaponType == EWeaponType.WT_ROCKETLAUNCHER)
369 return 0;
370 else
371 return 1.0;
372 }
373
374 //------------------------------------------------------------------------------------------------
376 {
377 PerceivableComponent targetPerceivable = target.GetPerceivableComponent();
378 if (!targetPerceivable)
379 return null;
380
381 array<ref AimPoint> aimPoints = {};
382
383 // Try to find an aimpoint
384 for (int i = 0; i < 3; i++)
385 {
386 EAimPointType aimpointType = aimpointTypes[i];
387 if (aimpointType == -1)
388 continue;
389
390 targetPerceivable.GetAimpointsOfType(aimPoints, aimpointType);
391 if (!aimPoints.IsEmpty())
392 break;
393 }
394
395 int index = aimPoints.GetRandomIndex(); // more aimpoints of same type -> pick one at random
396
397 if (index != -1)
398 return aimPoints[index];
399 else
400 return null;
401 }
402
403 //------------------------------------------------------------------------------------------------
404 static override bool VisibleInPalette() {return true;}
405
406 //------------------------------------------------------------------------------------------------
407 protected static override string GetOnHoverDescription() {return "Get aiming error position from the center of the target";}
408};
409
SCR_DebugMenuID
This enum contains all IDs for DiagMenu entries added in script.
Definition DebugMenuID.c:4
when task is activated by player or by killing enemy
float distance
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
Diagnostic and developer menu system.
Definition DiagMenu.c:18
proto external Managed FindComponent(typename typeName)
proto external vector GetOrigin()
proto external Physics GetPhysics()
proto external void GetWorldBounds(out vector mins, out vector maxs)
proto external IEntity GetRootParent()
Definition Math.c:13
proto void SetVariableOut(string name, void val)
proto bool GetVariableIn(string name, out void val)
proto void ClearVariable(string name)
float GetTolerance(IEntity observer, IEntity target, float angularSize, float distance, EWeaponType weaponType)
basic tolerance based on angular size of target in degrees
static override string GetOnHoverDescription()
float GetRandomFactor(EAISkill skill, float mu)
float GetDistanceFactor(float distance)
returns factor of error scale based on distance to target
override array< string > GetVariablesIn()
SCR_AICombatComponent m_CombatComponent
float GetAngularSpeedFactor(IEntity observer, IEntity enemy, out bool setBigTolerance)
EAimingPreference m_eAimingPreference
static override bool VisibleInPalette()
float GetOffsetWeaponTypeFactor(EWeaponType weaponType)
Scales offset depending on weapon type.
void GetTargetAngularBounds(IEntity shooter, AimPoint targetAimpoint, out vector sizeVectorX, out vector sizeVectorY, out float angularSize, out float distance)
returns vectors of aimpoint volume projected onto shooter's BB center and the angular size of the tar...
float GetWeaponTypeFactor(EWeaponType weaponType)
static ref TStringArray s_aVarsOut
AimPoint GetAimPoint(BaseTarget target, EAimPointType aimpointTypes[3])
static ref TStringArray s_aVarsIn
override array< string > GetVariablesOut()
float GetTargetIlluminationFactor(BaseTarget tgt)
returns 1.0 if target is well illuminated, and a bigger value if target is poorly illuminated.
override ENodeResult EOnTaskSimulate(AIAgent owner, float dt)
Instance of created debug visualizer.
Definition Shape.c:14
ENodeResult
Definition ENodeResult.c:13
EAimPointType
const int COLOR_BLUE
Definition constants.c:23
const int COLOR_RED
Definition constants.c:21
const int COLOR_YELLOW_A
Definition constants.c:29
const int COLOR_YELLOW
Definition constants.c:24
ShapeFlags
Definition ShapeFlags.c:13
@ NONE
When Shape is created and not initialized yet.
Definition ShapeType.c:15
SCR_FieldOfViewSettings Attribute
array< string > TStringArray
Definition Types.c:385
EWeaponType
Definition EWeaponType.c:13
@ RANDOM