DayZ Scripts
v1.21.156300 ยท Jun 20, 2023
 
Loading...
Searching...
No Matches
MeleeTargeting.c
Go to the documentation of this file.
2{
6
7 void MeleeTargetData(Object o, vector p, int c)
8 {
9 Obj = o;
10 HitPos = p;
11 HitComponent = c;
12 }
13}
14
16{
23
26
31 float MaxDist;
32
34 ref array<typename> TargetableObjects
35
36 void MeleeTargetSettings(vector coneOrigin, float coneLength, float coneHalfAngle, float coneMinHeight, float coneMaxHeight, vector rayStart, vector dir, float maxDist, EntityAI pToIgnore, array<typename> targetableObjects)
37 {
38 ConeOrigin = coneOrigin;
39 ConeLength = coneLength;
40 ConeHalfAngle = coneHalfAngle;
41 ConeHalfAngleRad = Math.DEG2RAD * coneHalfAngle;
42 ConeMinHeight = coneMinHeight;
43 ConeMaxHeight = coneMaxHeight;
44
45 RayStart = rayStart;
46 RayEnd = rayStart + Math.SqrFloat(coneLength) * dir;
47
48 Dir = dir;
49
50 XZDir = dir;
51 XZDir[1] = 0;
53
54 MaxDist = maxDist;
55
56 Attacker = pToIgnore;
57 TargetableObjects = targetableObjects;
58
59 // Calculate cone points
61 }
62}
63
65{
70}
71
72class MeleeTargeting
73{
75
76 MeleeTargetData GetMeleeTargetEx(MeleeTargetSettings settings, out array<Object> allTargets = null, array<string> blacklistedDamageZones = null)
77 {
79
80 // Easier access to MeleeTargetSettings variables
81 vector coneOrigin = settings.ConeOrigin;
82 float coneLength = settings.ConeLength;
83 float coneHalfAngle = settings.ConeHalfAngle;
84 float radAngle = settings.ConeHalfAngleRad;
85 float coneMinHeight = settings.ConeMinHeight;
86 float coneMaxHeight = settings.ConeMaxHeight;
87
88 vector coneLeft = settings.ConeLeftPoint;
89 vector coneRight = settings.ConeRightPoint;
90
91 vector rayStart = settings.RayStart;
92 vector rayEnd = settings.RayEnd;
93 vector dir = settings.Dir;
94 vector xzDir = settings.XZDir;
95 float maxDist = settings.MaxDist;
96
97 EntityAI pToIgnore = settings.Attacker;
98 array<typename> targetableObjects = settings.TargetableObjects;
99
100 // Calculate box size
101 float boxWidth = vector.Distance(coneLeft, coneRight);
102 float boxHeight = coneMaxHeight - coneMinHeight;
103
104 vector boxSize = Vector(boxWidth, boxHeight, coneLength);
105
106 // Calculate box center
107 vector centerHeight = Vector(0, Math.Lerp(coneMinHeight, coneMaxHeight, 0.5), 0);
108 vector offset = xzDir * coneLength * 0.5;
109 vector boxCenter = coneOrigin + offset + centerHeight;
110
111 // Gather all targets
113 params.SetParams(boxCenter, xzDir.VectorToAngles(), boxSize, ObjIntersect.Fire, ObjIntersect.Fire, true);
115 array<Object> toIgnore = { pToIgnore };
116 if (GetGame().IsBoxCollidingGeometryProxy(params, toIgnore, results))
117 {
118 //
119 float retVal = float.MAX;
120 float tgAngle = Math.Tan(radAngle);
121
122 #ifdef DIAG_DEVELOPER
123 if (DiagMenu.GetBool(DiagMenuIDs.MELEE_DRAW_RANGE) && DiagMenu.GetBool(DiagMenuIDs.MELEE_DEBUG))
124 Debug.DrawLine(rayStart, rayEnd, COLOR_GREEN, ShapeFlags.ONCE);
125 #endif
126
127 // Find the most suitable target
128 foreach (BoxCollidingResult bResult : results)
129 {
130 Object obj = bResult.obj;
131
132 // Check for targetable objects
133 if (!obj.IsAnyInherited(targetableObjects) || !obj.IsAlive())
134 {
135 continue;
136 }
137
138 // Ready the defaults for the object
139 vector targetPos = obj.GetPosition();
140 float targetAngle = Math.RAD2DEG * Math.AbsFloat(Math3D.AngleFromPosition(coneOrigin, dir, targetPos));
141 float targetDistance2 = vector.DistanceSq(targetPos, Math3D.NearestPoint(rayStart, rayEnd, targetPos));
142 int hitComponent = -1;
143
144 float csSum = float.MAX;
145
146 // Find the most suitable component
147 ComponentResult result;
148 if (FindMostSuitableComponentEx(obj, bResult, settings, csSum, result, blacklistedDamageZones))
149 {
150 targetPos = result.ComponentPos;
151 targetAngle = result.ComponentAngle;
152 targetDistance2 = result.ComponentDistance2;
153 hitComponent = result.ComponentIdx;
154 }
155
156 // ProxyInfo
157 if (bResult.proxyInfo)
158 {
159 foreach (BoxCollidingResult pInfo : bResult.proxyInfo)
160 {
161 if (FindMostSuitableComponentEx(obj, pInfo, settings, csSum, result, blacklistedDamageZones))
162 {
163 targetPos = result.ComponentPos;
164 targetAngle = result.ComponentAngle;
165 targetDistance2 = result.ComponentDistance2;
166 hitComponent = result.ComponentIdx;
167 }
168 }
169 }
170
171 // No suitable component found
172 if (hitComponent == -1 || csSum == float.MAX)
173 {
174 continue;
175 }
176
177 // Check if it is a better fit than what has been found previously
178 float sum = targetDistance2;
179 if (sum < retVal)
180 {
181 ret = new MeleeTargetData(obj, targetPos, hitComponent);
182 retVal = sum;
183 }
184
185 allTargets.Insert(obj);
186 }
187 }
188
189 return ret;
190 }
191
193 {
194 return GetMeleeTargetEx(settings, allTargets);
195 }
196
197
198 bool FindMostSuitableComponentEx(Object obj, BoxCollidingResult bResult, MeleeTargetSettings settings, out float sum, out ref ComponentResult result, array<string> blacklistedDamageZones)
199 {
200 foreach (ComponentInfo cInfo : bResult.componentInfo)
201 {
202 ComponentResult cResult = new ComponentResult;
203
204 if (!EvaluateComponentEx(obj, cInfo, settings, cResult, blacklistedDamageZones))
205 {
206 continue;
207 }
208
209 // Smallest number is a winner
210 float cSum = cResult.ComponentDistance2;
211 if (cSum < sum)
212 {
213 sum = cSum;
214 result = cResult;
215 }
216 }
217
218 return result != null;
219 }
220
221 bool FindMostSuitableComponent(Object obj, BoxCollidingResult bResult, MeleeTargetSettings settings, out float sum, out ref ComponentResult result)
222 {
223 return FindMostSuitableComponentEx(obj, bResult, settings, sum, result, null);
224 }
225
226 bool EvaluateComponentEx(Object obj, ComponentInfo cInfo, MeleeTargetSettings settings, out ref ComponentResult result, array<string> blacklistedDamageZones)
227 {
229 foreach (string zoneName: blacklistedDamageZones)
230 {
231 if (obj.GetDamageZoneNameByComponentIndex(cInfo.component) == zoneName)
232 {
233 return false;
234 }
235 }
236
237 vector componentPos = cInfo.componentCenter;
238
239 // Too far away! (fast reject)
240 float componentMaxDist2 = Math.SqrFloat(settings.MaxDist + cInfo.componentRadius * obj.GetScale());
241 vector nearestPoint = Math3D.NearestPoint(settings.RayStart, settings.RayEnd, componentPos);
242 float componentDistance2 = vector.DistanceSq(componentPos, nearestPoint);
243 if (componentDistance2 > componentMaxDist2)
244 {
245 return false;
246 }
247
248 // Here some more accurate check could be placed that would adjust the componentPos
249
250 // Outside of the cone angle!
251 float componentAngle = Math.RAD2DEG * Math.AbsFloat(Math3D.AngleFromPosition(settings.ConeOrigin, settings.XZDir, componentPos));
252 if (componentAngle > settings.ConeHalfAngle)
253 {
254 return false;
255 }
256
257 // Obstructed!
258 if (IsMeleeTargetObstructed(settings.RayStart, componentPos))
259 {
260 return false;
261 }
262
263 // We found something, fill it in!
264 result.ComponentPos = componentPos;
265 result.ComponentAngle = componentAngle;
266 result.ComponentDistance2 = componentDistance2;
267 result.ComponentIdx = cInfo.component;
268
269 return true;
270 }
271
272 bool EvaluateComponent(Object obj, ComponentInfo cInfo, MeleeTargetSettings settings, out ref ComponentResult result)
273 {
274 return EvaluateComponentEx(obj, cInfo, settings, result, {});
275 }
276
277 bool IsMeleeTargetObstructed(vector rayStart, vector rayEnd)
278 {
279 if (rayStart == rayEnd)
280 {
281 return true; // Not possible to trace when this happens (zero length raycast)
282 }
283
284 Object hitObject;
285 vector hitPos, hitNormal;
286 float hitFraction;
287
288 return DayZPhysics.RayCastBullet( rayStart, rayEnd, MELEE_TARGET_OBSTRUCTION_LAYERS, null, hitObject, hitPos, hitNormal, hitFraction);
289 }
290}
PhxInteractionLayers
Definition DayZPhysics.c:2
DiagMenuIDs
Definition EDiagMenuIDs.c:2
const int MAX
Definition EnConvert.c:27
float ConeHalfAngleRad
vector ConeLeftPoint
ref array< typename > TargetableObjects void MeleeTargetSettings(vector coneOrigin, float coneLength, float coneHalfAngle, float coneMinHeight, float coneMaxHeight, vector rayStart, vector dir, float maxDist, EntityAI pToIgnore, array< typename > targetableObjects)
float ConeMinHeight
float ConeLength
vector ConeRightPoint
vector XZDir
bool FindMostSuitableComponent(Object obj, BoxCollidingResult bResult, MeleeTargetSettings settings, out float sum, out ref ComponentResult result)
bool EvaluateComponent(Object obj, ComponentInfo cInfo, MeleeTargetSettings settings, out ref ComponentResult result)
float MaxDist
bool EvaluateComponentEx(Object obj, ComponentInfo cInfo, MeleeTargetSettings settings, out ref ComponentResult result, array< string > blacklistedDamageZones)
EntityAI Attacker
MeleeTargetData GetMeleeTarget(MeleeTargetSettings settings, out array< Object > allTargets=null)
float ConeMaxHeight
bool IsMeleeTargetObstructed(vector rayStart, vector rayEnd)
vector Dir
bool FindMostSuitableComponentEx(Object obj, BoxCollidingResult bResult, MeleeTargetSettings settings, out float sum, out ref ComponentResult result, array< string > blacklistedDamageZones)
class MeleeTargetData ConeOrigin
float ConeHalfAngle
class ComponentResult MELEE_TARGET_OBSTRUCTION_LAYERS
MeleeTargetData GetMeleeTargetEx(MeleeTargetSettings settings, out array< Object > allTargets=null, array< string > blacklistedDamageZones=null)
vector RayStart
vector RayEnd
Class that holds parameters to feed into CGame.IsBoxCollidingGeometryProxy.
proto native void SetParams(vector center, vector orientation, vector edgeLength, ObjIntersect primaryType, ObjIntersect secondaryType, bool fullComponentInfo)
Set the parameters.
static proto bool RayCastBullet(vector begPos, vector endPos, PhxInteractionLayers layerMask, Object ignoreObj, out Object hitObject, out vector hitPosition, out vector hitNormal, out float hitFraction)
Definition Debug.c:14
static Shape DrawLine(vector from, vector to, int color=0xFFFFFFFF, int flags=0)
Definition Debug.c:361
Definition EnMath.c:7
void MeleeTargetData(Object o, vector p, int c)
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
const float MAX
Definition EnConvert.c:99
static proto native float Distance(vector v1, vector v2)
Returns the distance between tips of two 3D vectors.
proto float Normalize()
Normalizes vector. Returns length.
static proto native float DistanceSq(vector v1, vector v2)
Returns the square distance between tips of two 3D vectors.
proto vector VectorToAngles()
Converts vector to spherical coordinates with radius = 1.
proto native CGame GetGame()
const int COLOR_GREEN
Definition constants.c:65
ShapeFlags
Definition EnDebug.c:126
static proto bool GetBool(int id, bool reverse=false)
Get value as bool from the given script id.
static proto vector NearestPoint(vector beg, vector end, vector pos)
Point on line beg .. end nearest to pos.
proto native vector Vector(float x, float y, float z)
Vector constructor from components.
static proto float AngleFromPosition(vector origin, vector originDir, vector target)
Angle that a target is from the direction of an origin.
static proto void ConePoints(vector origin, float length, float halfAngle, float angleOffset, out vector leftPoint, out vector rightPoint)
Calculates the points of a right 2D cone in 3D space.
static proto float Tan(float angle)
Returns tangent of angle in radians.
static proto float Atan2(float y, float x)
Returns angle in radians from tangent.
static proto float SqrFloat(float f)
Returns squared value.
static proto float Lerp(float a, float b, float time)
Linearly interpolates between 'a' and 'b' given 'time'.
static proto float AbsFloat(float f)
Returns absolute value.
static const float RAD2DEG
Definition EnMath.c:16
static const float DEG2RAD
Definition EnMath.c:17