Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_AISuppressionVolume.c
Go to the documentation of this file.
1// Base class of volume object representing space used to calculate suppression lines
2// Child classes can represent different shapes (bbox or sphere), can be static or dynamic (e.g. bbox attached to base target)
4{
5 // Max angle at which end of suppression line can be placed relative to shooter position (right-left)
6 protected static const float MAX_X_ANGLE_DEG = 12;
7
8 // Min angle at which end of suppression line should be placed relative to shooter position (right-left)
9 protected static const float MIN_X_ANGLE_DEG = 2;
10
11 // Max angle at which end of suppression line can be placed relative to shooter position (top-down)
12 protected static const float MAX_Y_ANGLE_DEG = 4;
13
14 // Min angle at which end of suppression line should be placed relative to shooter position (top-down)
15 protected static const float MIN_Y_ANGLE_DEG = 0.5;
16
17 // Min Y above surface of suppression line positions
18 protected static const float MIN_SURFACE_Y = 0.2;
19
20 // Random chance of going at opposite direction (RandomFloat01 < CHANCE)
21 protected static const float CHANCE_FOR_OPPOSITE_DIR = 0.150;
22
23#ifdef WORKBENCH
24 ref Shape m_DebugShape;
25
26 //---------------------------------------------------------------------------------------
27 protected void UpdateDebug()
28 {
29 if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_AI_SHOW_SUPPRESS_DEBUG))
30 m_DebugShape = GetDebugShape();
31 else
32 if (m_DebugShape)
33 delete m_DebugShape;
34 }
35#endif
36
37 //---------------------------------------------------------------------------------------
38 protected Shape GetDebugShape()
39 {
40 return null;
41 }
42
43 //---------------------------------------------------------------------------------------
44 protected static void GetPositionsAreaBBox(array<vector> positions, out vector bbMin, out vector bbMax)
45 {
46 bbMin = vector.Zero;
47 bbMax = vector.Zero;
48
49 if (positions.Count() > 0)
50 {
51 bbMin = Vector(float.MAX, float.MAX, float.MAX);
52 bbMax = Vector(-float.MAX, -float.MAX, -float.MAX);
53 }
54
55 foreach (vector position : positions)
56 {
57 for (int i = 0; i < 3; i++)
58 {
59 float posI = position[i];
60 if (posI > bbMax[i])
61 bbMax[i] = posI;
62 if (posI < bbMin[i])
63 bbMin[i] = posI;
64 }
65 }
66 }
67
68 //---------------------------------------------------------------------------------------
69 protected static vector RotateDirection90Degrees(vector currentDirection, bool rotateRight = true)
70 {
71 vector newDirection;
72 newDirection[1] = currentDirection[1]; // Y remains unchanged
73
74 if (rotateRight)
75 {
76 // To rotate 90 degrees to the right, swap X and Z and negate the new X
77 newDirection[0] = -currentDirection[2]; // New X is -Z
78 newDirection[2] = currentDirection[0]; // New Z is X
79 }
80 else
81 {
82 // To rotate 90 degrees to the left, swap X and Z and negate the new Z
83 newDirection[0] = currentDirection[2]; // New X is Z
84 newDirection[2] = -currentDirection[0]; // New Z is -X
85 }
86
87 return newDirection;
88 }
89
90 //---------------------------------------------------------------------------------------
92 {
93 return vector.Zero;
94 }
95
96 //---------------------------------------------------------------------------------------
97 protected void GetEdgePositions(vector startPos, vector dir, out vector minEdgePos, out vector maxEdgePos, out float minEdgeDist, out float maxEdgeDist)
98 {
99 minEdgePos = GetOutsideEdgePos(dir * -1);
100 minEdgeDist = vector.DistanceXZ(startPos, minEdgePos) * -1;
101
102 maxEdgePos = GetOutsideEdgePos(dir);
103 maxEdgeDist = vector.DistanceXZ(startPos, maxEdgePos);
104 }
105
106 //---------------------------------------------------------------------------------------
107 protected void GetYRange(vector position, out float minY, out float maxY)
108 {
109 minY = 0;
110 maxY = 0;
111 }
112
113 //---------------------------------------------------------------------------------------
114 protected void GetWorldYRange(BaseWorld world, vector position, out float minWorldY, out float maxWorldY)
115 {
116 float minY, maxY;
117 GetYRange(position, minY, maxY);
118 minWorldY = Math.Max(minY, world.GetSurfaceY(position[0], position[2]) + MIN_SURFACE_Y);
119 maxWorldY = Math.Max(maxY, minWorldY);
120 }
121
122 //---------------------------------------------------------------------------------------
123 bool IsInsideVolume2D(vector insidePos)
124 {
125 return false;
126 }
127
128 //---------------------------------------------------------------------------------------
129 vector GetRandomPosition(notnull IEntity shooter, inout vector startPos = vector.Zero, vector lastLineDir = vector.Zero)
130 {
131 vector centerPos = GetCenterPosition();
132
133 // Use center pos as default ref pos
134 if (!startPos || startPos == vector.Zero)
135 startPos = centerPos;
136
137 // Save start pos original Y
138 float startPosY = startPos[1];
139
140 // Make everything 2D
141 vector shooterPos = shooter.GetOrigin();
142 shooterPos[1] = 0;
143 startPos[1] = 0;
144 centerPos[1] = 0;
145
146 // Get direction sideways (rotate 90 degrees right)
147 vector rightDir = RotateDirection90Degrees(vector.Direction(shooterPos, centerPos).Normalized());
148
149 // Get edge positions (min is in opposite direction, max is forward)
150 vector minEdgePos, maxEdgePos;
151 float minEdgeDist, maxEdgeDist;
152 GetEdgePositions(startPos, rightDir, minEdgePos, maxEdgePos, minEdgeDist, maxEdgeDist);
153
154 vector sideDir = rightDir;
155
156 float maxDist = maxEdgeDist;
157 float minEdgeDistAbs = Math.AbsFloat(minEdgeDist);
158 float maxDistToEdge = Math.Max(maxEdgeDist, minEdgeDistAbs);
159 float lineLength = minEdgeDistAbs + maxEdgeDist;
160
161 // Get max possible dist based on angle
162 float distToCenter = vector.Distance(shooterPos, centerPos);
163 float minPossibleDist = Math.Tan(MIN_X_ANGLE_DEG * Math.DEG2RAD) * distToCenter;
164 float maxPossibleDist = Math.Tan(MAX_X_ANGLE_DEG * Math.DEG2RAD) * distToCenter;
165
166 // Last direction provided
167 if (lastLineDir != vector.Zero)
168 {
169 float dot = vector.DotXZ(lastLineDir, sideDir);
170
171 // Last dir is aligned with current dir
172 // Use last general dir as default dir
173 if (Math.AbsFloat(dot) > 0.9 && dot < 0)
174 {
175 sideDir = rightDir * -1;
176 maxDist = minEdgeDistAbs;
177 }
178 }
179
180 // Outside of BBox or given startPos is misaligned with suppression line
181 if (!IsInsideVolume2D(startPos))
182 {
183 // Start with min edge pos, line towards max edge
184 startPos = minEdgePos;
185 vector maxEndPos = maxEdgePos;
186
187 // Go opposite if max edge is closer
188 if (minEdgeDistAbs > Math.AbsFloat(maxEdgeDist))
189 {
190 startPos = maxEdgePos;
191 maxEndPos = minEdgePos;
192 }
193
194 // Get final direction and max distance
195 sideDir = vector.Direction(startPos, maxEndPos).Normalized();
196 maxDist = vector.DistanceXZ(startPos, maxEndPos);
197 }
198 else
199 // Inside BBox
200 {
201 // Chance of going opposite direction
202 if (Math.RandomFloat01() < CHANCE_FOR_OPPOSITE_DIR)
203 {
204 sideDir = rightDir * -1;
205 maxDist = minEdgeDistAbs;
206 }
207 }
208
209 BaseWorld world = shooter.GetWorld();
210
211 // Get start pos Y ranges
212 float startPosMinY, startPosMaxY;
213 GetWorldYRange(world, startPos, startPosMinY, startPosMaxY);
214
215 // Use closest edge if start pos Y is out of bounds
216 startPos[1] = Math.Max(Math.Min(startPosY, startPosMaxY), startPosMinY);
217
218 // It's possible minPossibleDist will make us go out of bounds
219 // We ensure minPossibleDist is respected no matter what, so it can be used for movement balancing
220 float endPosDistRandMax = Math.Max(minPossibleDist, Math.Min(maxPossibleDist, maxDist));
221 float endPosDist;
222 if (minPossibleDist == endPosDistRandMax)
223 endPosDist = minPossibleDist;
224 else
225 endPosDist = Math.RandomFloatInclusive(minPossibleDist, endPosDistRandMax);
226
227 // Get end pos
228 vector endPos = startPos + (sideDir * endPosDist);
229
230 // Get end pos Y ranges
231 float endPosMinY, endPosMaxY;
232 GetWorldYRange(world, endPos, endPosMinY, endPosMaxY);
233
234 // Use closest edge if end pos Y is out of bounds
235 float endPosY = Math.Max(Math.Min(endPos[1], endPosMaxY), endPosMinY);
236
237 // Get ranges
238 float endPosYTopRange = endPosMaxY - endPosY;
239 float endPosYBottomRange = endPosY - endPosMinY;
240
241 // Assume movement towards the top
242 int endPosYDir = 1;
243 float endPosYRange = endPosYTopRange;
244
245 // Get Y angle limits
246 float minYDiff = Math.Tan(MIN_Y_ANGLE_DEG * Math.DEG2RAD) * distToCenter;
247 float maxYDiff = Math.Tan(MAX_Y_ANGLE_DEG * Math.DEG2RAD) * distToCenter;
248
249 // Min Y is larger than BBox Y range
250 if (minYDiff > Math.Max(endPosYTopRange, endPosYBottomRange))
251 {
252 // Go down if large enough diff
253 if (endPosYBottomRange > endPosYTopRange / 2)
254 {
255 endPosYDir = -1;
256 minYDiff = endPosYBottomRange;
257 }
258 else
259 {
260 // Cut Y diff in half, check if it's tolerable
261 minYDiff *= 0.5;
262
263 // Range still too high, cut to BBox
264 if (minYDiff > endPosYTopRange)
265 minYDiff = endPosYTopRange;
266 }
267
268 endPosYRange = minYDiff;
269 }
270 else
271 {
272 // Use opposite direction if top too small or bottom has been drawn
273 if (endPosYBottomRange > minYDiff &&
274 (endPosYTopRange < minYDiff || Math.RandomFloat01() < (endPosYBottomRange / (endPosYBottomRange + endPosYTopRange))))
275 {
276 endPosYDir = -1;
277 endPosYRange = endPosYBottomRange;
278 }
279 }
280
281 // Get final end Y range with respect to min and max Y diffs
282 float endYRange = Math.Max(maxYDiff, Math.Min(endPosYRange - minYDiff, maxYDiff - minYDiff));
283
284 endPos[1] = endPosY + (Math.RandomFloatInclusive(minYDiff, endYRange) * endPosYDir);
285
286 return endPos;
287 }
288
289 //---------------------------------------------------------------------------------------
291 {
292 return vector.Zero;
293 }
294}
295
297{
300
301 //---------------------------------------------------------------------------------------
303 {
304 m_vBBMin = bbMin;
305 m_vBBMax = bbMax;
306
307#ifdef WORKBENCH
308 UpdateDebug();
309#endif
310 }
311
312 //---------------------------------------------------------------------------------------
313 override protected Shape GetDebugShape()
314 {
315 return Shape.Create(ShapeType.BBOX, Color.DARK_GREEN, ShapeFlags.NOZBUFFER | ShapeFlags.WIREFRAME, m_vBBMin, m_vBBMax);
316 }
317
318 //---------------------------------------------------------------------------------------
319 override protected void GetYRange(vector position, out float minY, out float maxY)
320 {
321 minY = m_vBBMin[1];
322 maxY = m_vBBMax[1];
323 }
324
325 //---------------------------------------------------------------------------------------
327 {
328 vector centerPos = GetCenterPosition();
329
330 // Calculate the slope of the direction vector
331 float zDirection = direction[2];
332 if (zDirection == 0)
333 zDirection = 0.000000000000000000000000000001;
334 float slope = direction[0] / zDirection;
335
336 // Calculate intersection with vertical edge
337 float zEdge = m_vBBMin[2];
338 if (direction[2] > 0)
339 zEdge = m_vBBMax[2];
340 float xIntersectVertical = slope * (zEdge - centerPos[2]) + centerPos[0];
341
342 // Calculate intersection with horizontal edge
343 float xEdge = m_vBBMin[0];
344 if (direction[0] > 0)
345 xEdge = m_vBBMax[0];
346 float zIntersectHorizontal = (xEdge - centerPos[0]) / slope + centerPos[2];
347
348 // Check if intersections are within bounds and get possible intersection points
349 vector vEdgeIntersectPos = vector.Zero;
350 if (xIntersectVertical >= m_vBBMin[0] && xIntersectVertical <= m_vBBMax[0])
351 vEdgeIntersectPos = Vector(xIntersectVertical, 0, zEdge);
352
353 vector hEdgeIntersectPos = vector.Zero;
354 if (zIntersectHorizontal >= m_vBBMin[2] && zIntersectHorizontal <= m_vBBMax[2])
355 hEdgeIntersectPos = Vector(xEdge, 0, zIntersectHorizontal);
356
357 // Get closest valid edge position
358 if (hEdgeIntersectPos == vector.Zero || vector.DistanceXZ(centerPos, vEdgeIntersectPos) < vector.DistanceXZ(centerPos, hEdgeIntersectPos))
359 return vEdgeIntersectPos;
360 else
361 return hEdgeIntersectPos;
362 }
363
364 //---------------------------------------------------------------------------------------
365 override bool IsInsideVolume2D(vector insidePos)
366 {
367 return Math.IsInRange(insidePos[0], m_vBBMin[0], m_vBBMax[0]) && Math.IsInRange(insidePos[2], m_vBBMin[2], m_vBBMax[2]);
368 }
369
370 //---------------------------------------------------------------------------------------
372 {
373 return 0.5 * (m_vBBMin + m_vBBMax);
374 }
375}
376
377class SCR_AISuppressionVolumeSphere : SCR_AISuppressionVolumeBase
378{
379 vector m_vPos;
380 float m_fRadius;
381
382 //---------------------------------------------------------------------------------------
383 void SCR_AISuppressionVolumeSphere(vector pos, float radius)
384 {
385 m_vPos = pos;
386 m_fRadius = radius;
387
388#ifdef WORKBENCH
389 UpdateDebug();
390#endif
391 }
392
393 //---------------------------------------------------------------------------------------
394 override protected Shape GetDebugShape()
395 {
396 return Shape.CreateSphere(Color.DARK_GREEN, ShapeFlags.NOZBUFFER | ShapeFlags.WIREFRAME, m_vPos, m_fRadius);
397 }
398
399 //---------------------------------------------------------------------------------------
400 override protected void GetYRange(vector position, out float minY, out float maxY)
401 {
402 vector centerPos = GetCenterPosition();
403 float distToCenter2D = vector.DistanceXZ(centerPos, position);
404
405 float maxDist = Math.Sqrt((m_fRadius * m_fRadius) - (distToCenter2D * distToCenter2D));
406
407 maxY = centerPos[1] + maxDist;
408 minY = centerPos[1] - maxDist;
409 }
410
411 //---------------------------------------------------------------------------------------
413 {
414 return m_vPos + direction * m_fRadius;
415 }
416
417 //---------------------------------------------------------------------------------------
418 override bool IsInsideVolume2D(vector insidePos)
419 {
420 return vector.DistanceXZ(GetCenterPosition(), insidePos) < m_fRadius;
421 }
422
423 //---------------------------------------------------------------------------------------
425 {
426 return m_vPos;
427 }
428}
429
430
431class SCR_AISuppressionObjectVolumeBox : SCR_AISuppressionVolumeBox
432{
433 // Object volume scaling settings
434 protected static const float OBJECT_VOLUME_MAX_SCALE_DISTANCE = 600.0;
435 protected static const float OBJECT_VOLUME_MAX_SCALE = 5; // How much bigger volume will get at max scaling distance
436 protected static const float OBJECT_VOLUME_MIN_SCALE = 1.5;
437
438 protected static const float TARGET_MIN_SIZE = 3; // Minimal size of target in meters
439 protected static const float OBJECT_VOLUME_MIN_Y = 4; // Min vertical size of object volume
440 protected static const float NOT_RECOGNIZED_CLUSTER_SCALE = 3; // Scale multiplier for cluster volumes of not recognized targets
441
442 //---------------------------------------------------------------------------------------
443 static void ScaleTargetBBox(inout vector bbMin, inout vector bbMax, float distance, bool recognized = true)
444 {
446 float targetSize = Math.Max(vector.DistanceXZ(bbMin, bbMax), TARGET_MIN_SIZE);
447 float factor = Math.Map(distance, 0, OBJECT_VOLUME_MAX_SCALE_DISTANCE, OBJECT_VOLUME_MIN_SCALE, OBJECT_VOLUME_MAX_SCALE);
448
449 // Volumes for not recognized targets are much bigger
450 if (!recognized)
451 factor *= NOT_RECOGNIZED_CLUSTER_SCALE;
452
453 float extraSize = targetSize * (factor - 1);
454
455 bbMin[0] = bbMin[0] - extraSize;
456 bbMin[2] = bbMin[2] - extraSize;
457 bbMax[0] = bbMax[0] + extraSize;
458 bbMax[2] = bbMax[2] + extraSize;
459
460 // Add Y if not much vertical room
461 if ((bbMax[1] - bbMin[1]) < OBJECT_VOLUME_MIN_Y)
462 {
463 bbMin[1] = bbMin[1] - OBJECT_VOLUME_MIN_Y / 2;
464 bbMax[1] = bbMax[1] + OBJECT_VOLUME_MIN_Y / 2;
465 }
466 }
467}
468
469class SCR_AISuppressionVolumeBaseTargetBox : SCR_AISuppressionObjectVolumeBox
470{
472
473 //---------------------------------------------------------------------------------------
474 void SetTarget(BaseTarget baseTarget, IEntity shooter, vector destination)
475 {
476 m_BaseTarget = baseTarget;
477
478 if (!m_BaseTarget)
479 return;
480
481 IEntity targetEnt = m_BaseTarget.GetTargetEntity();
482 if (!targetEnt)
483 return;
484
485 vector lastSeenPos = m_BaseTarget.GetLastSeenPosition();
486
487 // Get volume BBox
488 array<vector> positions = {};
489
490 if (lastSeenPos != vector.Zero)
491 positions.Insert(lastSeenPos);
492
493 if (destination != vector.Zero)
494 positions.Insert(destination);
495
496 GetPositionsAreaBBox(positions, m_vBBMin, m_vBBMax);
497
498 // Get target local bounds
499 vector localBBMin, localBBMax;
500 targetEnt.GetBounds(localBBMin, localBBMax);
501
502 // Adjust volume Y to target
503 m_vBBMax[1] = m_vBBMax[1] + (localBBMax[1] - localBBMin[1]);
504
505 // Scale BBox
506 ScaleTargetBBox(m_vBBMin, m_vBBMax, m_BaseTarget.GetDistance());
507
508#ifdef WORKBENCH
509 // Update debug shape
510 UpdateDebug();
511#endif
512 }
513}
514
515class SCR_AISuppressionVolumeClusterBox : SCR_AISuppressionObjectVolumeBox
516{
518
519 //---------------------------------------------------------------------------------------
520 static SCR_AISuppressionVolumeClusterBox GetVolumeFromClusterState(SCR_AITargetClusterState clusterState)
521 {
522 SCR_AISuppressionVolumeClusterBox volume = new SCR_AISuppressionVolumeClusterBox(vector.Zero, vector.Zero);
523 volume.SetClusterState(clusterState);
524 return volume;
525 }
526
527 //---------------------------------------------------------------------------------------
532
533 //---------------------------------------------------------------------------------------
534 void SetClusterState(SCR_AITargetClusterState clusterState, bool scaleTarget = true)
535 {
536 m_ClusterState = clusterState;
537
538 if (!m_ClusterState)
539 return;
540
541 m_vBBMin = m_ClusterState.m_vBBMin;
542 m_vBBMax = m_ClusterState.m_vBBMax;
543
544 // Scale BBox
545 if (scaleTarget)
546 ScaleTargetBBox(m_vBBMin, m_vBBMax, m_ClusterState.m_fDistMin, clusterState.m_iCountIdentified > 0);
547
548#ifdef WORKBENCH
549 UpdateDebug();
550#endif
551 }
552}
553
554class SCR_AISuppressionVolumeWaypoint : SCR_AISuppressionObjectVolumeBox
555{
556 protected AIWaypoint m_Waypoint;
557
558 void SetWaypoint(notnull AIWaypoint wp, float height)
559 {
560 m_Waypoint = wp;
561
562 // Take approximate BB based on waypoint radius and height
563 float r = wp.GetCompletionRadius();
564 vector pos = wp.GetOrigin();
565
566 m_vBBMin = pos - Vector(r, 0, r);
567 m_vBBMax = pos + Vector(r, height, r);
568
569 #ifdef WORKBENCH
570 UpdateDebug();
571 #endif
572 }
573
574 //------------------------------------------------------------------------------------------------
575 AIWaypoint GetWaypoint()
576 {
577 return m_Waypoint;
578 }
579}
SCR_DebugMenuID
This enum contains all IDs for DiagMenu entries added in script.
Definition DebugMenuID.c:4
void UpdateDebug()
vector m_vBBMax
void SCR_AISuppressionVolumeBox(vector bbMin, vector bbMax)
SCR_AISuppressionVolumeSphere OBJECT_VOLUME_MAX_SCALE_DISTANCE
void SetClusterState(SCR_AITargetClusterState clusterState, bool scaleTarget=true)
SCR_AISuppressionVolumeBaseTargetBox m_ClusterState
SCR_AITargetClusterState GetClusterState()
class SCR_AISuppressionVolumeBase m_vBBMin
vector m_vBBMax
vector m_vBBMin
void SCR_AITargetClusterState(SCR_AIGroupTargetCluster cluster)
float distance
vector direction
vector position
Definition Color.c:13
Diagnostic and developer menu system.
Definition DiagMenu.c:18
proto external void GetBounds(out vector mins, out vector maxs)
Definition Math.c:13
static vector RotateDirection90Degrees(vector currentDirection, bool rotateRight=true)
bool IsInsideVolume2D(vector insidePos)
vector GetRandomPosition(notnull IEntity shooter, inout vector startPos=vector.Zero, vector lastLineDir=vector.Zero)
static void GetPositionsAreaBBox(array< vector > positions, out vector bbMin, out vector bbMax)
void GetYRange(vector position, out float minY, out float maxY)
vector GetOutsideEdgePos(vector direction)
void GetWorldYRange(BaseWorld world, vector position, out float minWorldY, out float maxWorldY)
void GetEdgePositions(vector startPos, vector dir, out vector minEdgePos, out vector maxEdgePos, out float minEdgeDist, out float maxEdgeDist)
void SetTarget(BaseTarget baseTarget, IEntity shooter, vector destination)
vector GetOutsideEdgePos(vector direction)
void GetYRange(vector position, out float minY, out float maxY)
override bool IsInsideVolume2D(vector insidePos)
void SetWaypoint(notnull AIWaypoint wp, float height)
Instance of created debug visualizer.
Definition Shape.c:14
ShapeType
Definition ShapeType.c:13
ShapeFlags
Definition ShapeFlags.c:13
@ MAX
proto native vector Vector(float x, float y, float z)