Dayz Explorer 1.28.160049
Loading...
Searching...
No Matches
meleetargeting.c
Go to the documentation of this file.
2{
3 Object Obj;
4 vector HitPos;
5 int HitComponent;
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;
52 XZDir.Normalize();
53
54 MaxDist = maxDist;
55
56 Attacker = pToIgnore;
57 TargetableObjects = targetableObjects;
58
59 // Calculate cone points
61 }
62}
63
65{
66 vector ComponentPos;
67 float ComponentAngle;
68 float ComponentDistance2;
69 int ComponentIdx;
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 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 ComponentResult result)
222 {
223 return FindMostSuitableComponentEx(obj, bResult, settings, sum, result, null);
224 }
225
226 bool EvaluateComponentEx(Object obj, ComponentInfo cInfo, MeleeTargetSettings settings, out 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 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}
Class that holds parameters to feed into CGame.IsBoxCollidingGeometryProxy.
Definition debug.c:2
Definition enmath.c:7
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
PhxInteractionLayers
Definition dayzphysics.c:2
DiagMenuIDs
Definition ediagmenuids.c:2
const int MAX
Definition enconvert.c:27
proto native CGame GetGame()
const int COLOR_GREEN
Definition constants.c:65
ShapeFlags
Definition endebug.c:126
proto native vector Vector(float x, float y, float z)
Vector constructor from components.
float ConeHalfAngleRad
vector ConeLeftPoint
bool EvaluateComponentEx(Object obj, ComponentInfo cInfo, MeleeTargetSettings settings, out ComponentResult result, array< string > blacklistedDamageZones)
bool FindMostSuitableComponentEx(Object obj, BoxCollidingResult bResult, MeleeTargetSettings settings, out float sum, out ComponentResult result, array< string > blacklistedDamageZones)
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
bool FindMostSuitableComponent(Object obj, BoxCollidingResult bResult, MeleeTargetSettings settings, out float sum, out ComponentResult result)
vector XZDir
float MaxDist
EntityAI Attacker
MeleeTargetData GetMeleeTarget(MeleeTargetSettings settings, out array< Object > allTargets=null)
float ConeMaxHeight
bool IsMeleeTargetObstructed(vector rayStart, vector rayEnd)
bool EvaluateComponent(Object obj, ComponentInfo cInfo, MeleeTargetSettings settings, out ComponentResult result)
vector Dir
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