Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_MeleeComponent.c
Go to the documentation of this file.
1[ComponentEditorProps(category: "GameScripted/Character", description: "Enables melee for character")]
5
6class SCR_MeleeHitDataClass
7{
12 int m_iNodeIndex = -1;
13 float m_fDamage = 0;
18}
19
22typedef ScriptInvokerBase<OnMeleePerformedDelegate> OnMeleePerformedInvoker;
23
25{
26 //#define SCR_MELEE_DEBUG //! uncomment to enable melee debug draws
27 //#define SCR_MELEE_DEBUG_MSG //! uncomment to enable melee debug prints into console
28#ifdef SCR_MELEE_DEBUG
29 ref array<ref Shape> m_aDbgSamplePositionsShapes;
30 ref array<ref Shape> m_aDbgCollisionShapes;
31#endif
32
33 protected ref SCR_MeleeHitDataClass m_MeleeHitData;
34 protected bool m_bMeasurementDone;
35 protected bool m_bAttackAlreadyExecuted = false;
36 protected bool m_bMeleeAttackStarted = false;
37 protected float m_fWeaponMeleeAccuracy;
38 protected float m_fWeaponMeleeRange;
41
42 [RplProp()]
43 protected bool m_bHasBayonet;
44
45 //------------------------------------------------------------------------------------------------
48 {
49 return m_bHasBayonet;
50 }
51
52 //------------------------------------------------------------------------------------------------
61
62 //------------------------------------------------------------------------------------------------
65 {
67 return;
68
69#ifdef SCR_MELEE_DEBUG
70 Do_ClearDbgShapes();
71#endif
72
73 //This can be attached to a script invoker, which tells us the player changed their weapon
76 }
77
78 //------------------------------------------------------------------------------------------------
81 void SetMeleeAttackStarted(bool started)
82 {
83 m_bMeleeAttackStarted = started;
84
85 if (!started)
87 }
88
89 //------------------------------------------------------------------------------------------------
90 protected bool TraceFilter(notnull IEntity ent)
91 {
92 if (SCR_ChimeraCharacter.Cast(ent))
93 return true;
94
95 return !SCR_ChimeraCharacter.Cast(ent.GetRootParent()); // Ignore anything that is not a character but attached to one e.g. weapons, armor, etc.
96 }
97
98 //------------------------------------------------------------------------------------------------
99 protected vector GetAimingVector(notnull ChimeraCharacter character)
100 {
101 vector aimMat[4];
102 if (character)
103 Math3D.AnglesToMatrix(character.GetCharacterController().GetInputContext().GetAimingAngles() * Math.RAD2DEG, aimMat);
104
105 return aimMat[2];
106 }
107
108 //------------------------------------------------------------------------------------------------
112 protected bool CheckCollisionsSimple(out SCR_MeleeHitDataClass pHitData)
113 {
114 SCR_ChimeraCharacter character = SCR_ChimeraCharacter.Cast(GetOwner());
115 if (!character)
116 return false;
117
118 TraceSphere param = new TraceSphere();
119 param.LayerMask = EPhysicsLayerDefs.Projectile;
120 param.Flags = TraceFlags.ENTS | TraceFlags.WORLD;
121 array<IEntity> ExcludeArray = {character};
122 param.ExcludeArray = ExcludeArray;
123
124 param.Radius = m_fWeaponMeleeAccuracy;
125 param.Start = character.EyePosition();
126 param.End = param.Start + GetAimingVector(character) * m_fWeaponMeleeRange;
127
128 // Trace stops on the first hit entity if you want to change this, change the filter callback
129 float hit = GetOwner().GetWorld().TraceMove(param, TraceFilter);
130
131 if (!param.TraceEnt)
132 return false;
133
134 vector dir = (param.End - param.Start);
135
136 pHitData.m_Entity = param.TraceEnt;
137 pHitData.m_iColliderIndex = param.ColliderIndex;
138 pHitData.m_vHitPosition = dir * hit + param.Start;
139 pHitData.m_vHitDirection = dir.Normalized();
140 pHitData.m_vHitNormal = param.TraceNorm;
141 pHitData.m_SurfaceProps = param.SurfaceProps;
142 pHitData.m_iNodeIndex = param.NodeIndex;
143
144#ifdef SCR_MELEE_DEBUG_MSG
145 MCDbgPrint("Check collision from: "+param.Start);
146 MCDbgPrint("Check collision to: "+param.End);
147 MCDbgPrint("Check collision range: " +vector.Distance(param.End, param.Start));
148 MCDbgPrint("Check collision entity: "+pHitData.m_Entity.ToString());
149 MCDbgPrint("Check collision hitzone: "+pHitData.m_sHitZoneName);
150 MCDbgPrint("Check collision hitPos: "+pHitData.m_vHitPosition);
151#endif
152
153 return true;
154 }
155
156 // TODO: call this from SCR_CharacterControllerComponent.OnWeaponSelected() when possible and remove from PerformAttack()
157 //------------------------------------------------------------------------------------------------
161 {
162 BaseWeaponManagerComponent wpnManager = BaseWeaponManagerComponent.Cast(GetOwner().FindComponent(BaseWeaponManagerComponent));
163 if (!wpnManager)
164 return;
165
166 WeaponSlotComponent currentSlot = WeaponSlotComponent.Cast(wpnManager.GetCurrent());
167 if (!currentSlot)
168 return;
169
171 m_MeleeHitData.m_Weapon = currentSlot.GetWeaponEntity();
172
173 IEntity weaponEntity = currentSlot.GetWeaponEntity();
174 if (!weaponEntity)
175 return;
176
179 return;
180
181 m_MeleeHitData.m_fDamage = m_MeleeWeaponProperties.GetWeaponDamage();
183 m_fWeaponMeleeAccuracy = m_MeleeWeaponProperties.GetWeaponMeleeAccuracy();
184
185 IEntity bayonet;
186 IEntity child = weaponEntity.GetChildren();
187 while (child)
188 {
189 if (child.FindComponent(SCR_BayonetComponent))
190 {
191 bayonet = child;
192 break;
193 }
194
195 child = child.GetSibling();
196 }
197
198 m_MeleeHitData.m_Bayonet = bayonet;
199 m_bHasBayonet = m_MeleeHitData.m_Bayonet != null;
200 Replication.BumpMe();
201 }
202
203 //------------------------------------------------------------------------------------------------
205 protected void HandleMeleeSound()
206 {
207 IEntity weapon = m_MeleeHitData.m_Weapon;
208 if (!weapon)
209 return;
210
211 GameMaterial material = m_MeleeHitData.m_SurfaceProps;
212 if (!material)
213 return;
214
215 int surfaceInt = material.GetSoundInfo().GetSignalValue();
216
217 PlaySound(m_MeleeHitData.m_Weapon, m_MeleeHitData.m_vHitPosition, m_MeleeHitData.m_iColliderIndex, surfaceInt);
218
219 RplComponent weaponRpl = RplComponent.Cast(m_MeleeHitData.m_Weapon.FindComponent(RplComponent));
220 if (!weaponRpl)
221 return;
222
223 Rpc(RPC_HandleMeleeSound, weaponRpl.Id(), m_MeleeHitData.m_vHitPosition, m_MeleeHitData.m_iColliderIndex, surfaceInt);
224
225 #ifdef WORKBENCH
226 if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_SOUNDS_PRINT_MELEESURFACE))
227 {
228 Print(string.Format("HitZone: %1", m_MeleeHitData.m_iColliderIndex), LogLevel.NORMAL);
229 Print(string.Format("Surface: %1", surfaceInt), LogLevel.NORMAL);
230 Print(string.Format("-------------------------------------"), LogLevel.NORMAL);
231 }
232 #endif
233 }
234
235 //------------------------------------------------------------------------------------------------
236 protected void PlaySound(IEntity weaponEntity, vector position, int signalValue0, int signalValue1)
237 {
238 SoundComponent soundComp = SoundComponent.Cast(weaponEntity.FindComponent(SoundComponent));
239 if (!soundComp)
240 return;
241
242 SignalsManagerComponent signalsManagerComponent = SignalsManagerComponent.Cast(weaponEntity.FindComponent(SignalsManagerComponent));
243 if (signalsManagerComponent)
244 {
245 int signalHitZone = signalsManagerComponent.FindSignal("HitZone");
246 int signalSurface = signalsManagerComponent.FindSignal("Surface");
247
248 // Signals are expected to exist on the weapon already.
249 // This function does not necessary run from the main thread and adding signals will be ignored.
250 signalsManagerComponent.SetSignalValue(signalHitZone, signalValue0);
251 signalsManagerComponent.SetSignalValue(signalSurface, signalValue1);
252 }
253
254 vector transform[4];
255 Math3D.MatrixIdentity3(transform);
256 transform[3] = position;
257
258 if (m_bHasBayonet)
259 soundComp.SoundEventTransform(SCR_SoundEvent.SOUND_MELEE_IMPACT_BAYONET, transform);
260 else
261 soundComp.SoundEventTransform(SCR_SoundEvent.SOUND_MELEE_IMPACT, transform);
262 }
263
264 //------------------------------------------------------------------------------------------------
265 [RplRpc(RplChannel.Unreliable, RplRcver.Broadcast)]
266 protected void RPC_HandleMeleeSound(RplId weaponID, vector position, int signalValue0, int signalValue1)
267 {
268 RplComponent weaponRpl = RplComponent.Cast(Replication.FindItem(weaponID));
269 if (!weaponRpl)
270 return;
271
272 IEntity weaponEntity = weaponRpl.GetEntity();
273 if (!weaponEntity)
274 return;
275
276 PlaySound(weaponEntity, position, signalValue0, signalValue1);
277 }
278
279 //------------------------------------------------------------------------------------------------
284 protected SCR_DamageManagerComponent SearchHierarchyForDamageManager(IEntity startEntity, out HitZone hitZone)
285 {
286 if (!startEntity)
287 return null;
288
289 SCR_DamageManagerComponent damageManager;
290 while (startEntity)
291 {
292 damageManager = SCR_DamageManagerComponent.GetDamageManager(startEntity);
293 if (damageManager)
294 break;
295
296 startEntity = startEntity.GetParent();
297 }
298
299 if (damageManager)
300 {
301 hitZone = damageManager.GetHitZoneByColliderID(m_MeleeHitData.m_iColliderIndex);
302 if (!hitZone)
303 hitZone = damageManager.GetDefaultHitZone();
304 }
305
306 return damageManager;
307 }
308
309 //------------------------------------------------------------------------------------------------
311 protected void ProcessMeleeAttack()
312 {
313 RplComponent rplComponent = RplComponent.Cast(GetOwner().FindComponent(RplComponent));
314 if (rplComponent && rplComponent.IsProxy())
315 return; // Don't call on clients
316
318 return;
319
320 if (m_MeleeHitData.m_Weapon)
322
323#ifdef SCR_MELEE_DEBUG
324 m_aDbgSamplePositionsShapes.Clear();
325 Debug_DrawSphereAtPos(m_MeleeHitData.m_vHitPosition, m_aDbgSamplePositionsShapes, 0xff00ff00, 0.03, ShapeFlags.NOZBUFFER);
326#endif
327
330
331 // This callLater is necessary because the use of traces pushed the handledamage out of main thread, which causes VME's
332 GetGame().GetCallqueue().CallLater(HandleDamageDelayed);
333 }
334
335 //------------------------------------------------------------------------------------------------
336 protected void HandleDamageDelayed()
337 {
338 if (m_MeleeHitData.m_Bayonet && m_MeleeHitData.m_Entity)
339 {
340 SCR_BayonetComponent bayonet = SCR_BayonetComponent.Cast(m_MeleeHitData.m_Bayonet.FindComponent(SCR_BayonetComponent));
341 if (bayonet && SCR_ChimeraCharacter.Cast(m_MeleeHitData.m_Entity))
342 bayonet.AddBloodToBayonet();
343
344 SCR_BayonetEffectComponent effectComponent = SCR_BayonetEffectComponent.Cast(m_MeleeHitData.m_Bayonet.FindComponent(SCR_BayonetEffectComponent));
345 if (effectComponent)
346 effectComponent.OnImpact(
347 m_MeleeHitData.m_Entity,
348 m_MeleeHitData.m_fDamage,
349 m_MeleeHitData.m_vHitPosition,
350 m_MeleeHitData.m_vHitNormal,
351 m_MeleeHitData.m_SurfaceProps);
352 }
353
354 vector hitPosDirNorm[3];
355 hitPosDirNorm[0] = m_MeleeHitData.m_vHitPosition;
356 hitPosDirNorm[1] = m_MeleeHitData.m_vHitDirection;
357 hitPosDirNorm[2] = m_MeleeHitData.m_vHitNormal;
358
359 // check if the entity is destructible entity
360 SCR_DestructibleEntity destructibleEntity = SCR_DestructibleEntity.Cast(m_MeleeHitData.m_Entity);
361 if (destructibleEntity)
362 {
363 destructibleEntity.HandleDamage(EDamageType.MELEE, m_MeleeHitData.m_fDamage, hitPosDirNorm);
364 return;
365 }
366
367 // check if the entity has the damage manager component
368 HitZone hitZone;
369 SCR_DamageManagerComponent damageManager = SearchHierarchyForDamageManager(m_MeleeHitData.m_Entity, hitZone);
370 if (!hitZone || !damageManager)
371 return;
372
373 SCR_DamageContext context = new SCR_DamageContext(EDamageType.MELEE, m_MeleeHitData.m_fDamage, hitPosDirNorm,
374 damageManager.GetOwner(), hitZone, Instigator.CreateInstigator(GetOwner()),
375 m_MeleeHitData.m_SurfaceProps, m_MeleeHitData.m_iColliderIndex, m_MeleeHitData.m_iNodeIndex);
376
377 if (m_MeleeHitData.m_Bayonet)
378 context.damageSource = m_MeleeHitData.m_Bayonet;
379 else
380 context.damageSource = m_MeleeHitData.m_Weapon;
381
382 if (m_MeleeHitData.m_Bayonet)
383 context.damageSource = m_MeleeHitData.m_Bayonet;
384 else
385 context.damageSource = m_MeleeHitData.m_Weapon;
386
387 context.damageEffect = new SCR_MeleeDamageEffect();
388 damageManager.HandleDamage(context);
389 }
390
391 //------------------------------------------------------------------------------------------------
393 //------------------------------------------------------------------------------------------------
394
395 //------------------------------------------------------------------------------------------------
397 protected void Do_OnFrameCleanup()
398 {
400 m_bMeasurementDone = false;
401 }
402
403#ifdef SCR_MELEE_DEBUG
404 // dbg
405 //------------------------------------------------------------------------------------------------
407 protected void Do_ClearDbgShapes()
408 {
409 m_aDbgSamplePositionsShapes.Clear();
410 m_aDbgCollisionShapes.Clear();
411 }
412#endif
413
414 //------------------------------------------------------------------------------------------------
416 //------------------------------------------------------------------------------------------------
417
418 //------------------------------------------------------------------------------------------------
420 protected void Debug_DrawSphereAtPos(vector v, array<ref Shape> dbgShapes, int color = COLOR_BLUE, float size = 0.03, ShapeFlags shapeFlags = ShapeFlags.VISIBLE)
421 {
422 shapeFlags = ShapeFlags.NOOUTLINE | shapeFlags;
423
424 vector matx[4];
425 Math3D.MatrixIdentity4(matx);
426 matx[3] = v;
427 Shape s = Shape.CreateSphere(color, shapeFlags, GetOwner().GetOrigin(), size);
428 s.SetMatrix(matx);
429 dbgShapes.Insert(s);
430 }
431
432 //------------------------------------------------------------------------------------------------
433 protected void Debug_DrawSphereAtPos(vector pos, int color, array<ref Shape> dbgShapes)
434 {
435 vector matx[4];
436 Math3D.MatrixIdentity4(matx);
437 matx[3] = pos;
438 int shapeFlags = ShapeFlags.NOOUTLINE|ShapeFlags.NOZBUFFER|ShapeFlags.TRANSP;
439 Shape s = Shape.CreateSphere(color, shapeFlags, pos, 0.05);
440 s.SetMatrix(matx);
441 dbgShapes.Insert(s);
442 }
443
444 //------------------------------------------------------------------------------------------------
445 protected void Debug_DrawLineSimple(vector start, vector end, array<ref Shape> dbgShapes)
446 {
447 vector p[2];
448 p[0] = start;
449 p[1] = end;
450
451 int shapeFlags = ShapeFlags.NOOUTLINE;
452 Shape s = Shape.CreateLines(ARGBF(1, 1, 1, 1), shapeFlags, p, 2);
453 dbgShapes.Insert(s);
454 }
455
456#ifdef SCR_MELEE_DEBUG_MSG
457 //------------------------------------------------------------------------------------------------
460 protected void MCDbgPrint(string msg = "")
461 {
462 Print("\\_ SCR_MELEE_DEBUG] " + GetGame().GetTickCount().ToString() + " ** " + msg, LogLevel.NORMAL);
463 }
464#endif
465
466 //------------------------------------------------------------------------------------------------
468 //------------------------------------------------------------------------------------------------
469
470 //------------------------------------------------------------------------------------------------
473 void Update(float timeSlice)
474 {
476 return;
477
479 m_bMeasurementDone = true;
480 }
481
482 //------------------------------------------------------------------------------------------------
483 override void OnPostInit(IEntity owner)
484 {
485 super.OnPostInit(owner);
486 SetEventMask(owner, EntityEvent.INIT);
487 }
488
489 //------------------------------------------------------------------------------------------------
490 override void EOnInit(IEntity owner)
491 {
492 m_MeleeHitData = new SCR_MeleeHitDataClass;
493
494 if (!GetGame().GetWorldEntity())
495 return;
496
497 #ifdef ENABLE_DIAG
498 DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_SOUNDS_PRINT_MELEESURFACE, "", "Print Melee Surface", "Sounds");
499 #endif
500
501#ifdef SCR_MELEE_DEBUG
502 m_aDbgSamplePositionsShapes = {};
503 m_aDbgCollisionShapes = {};
504#endif
505 }
506}
SCR_DebugMenuID
This enum contains all IDs for DiagMenu entries added in script.
Definition DebugMenuID.c:4
ArmaReforgerScripted GetGame()
Definition game.c:1398
int size
enum EAIGroupCombatMode ComponentEditorProps(category:"GameScripted/AI", description:"Component for utility AI system for groups")
enum EAITargetInfoCategory m_Entity
vector GetOrigin()
SCR_CacheNoteComponentClass ScriptComponentClass RplProp()] protected ref array< string > m_aLines
void SCR_DestructibleEntity(IEntitySource src, IEntity parent)
vector position
SurfaceProperties m_SurfaceProps
ScriptInvokerBase< OnMeleePerformedDelegate > OnMeleePerformedInvoker
int m_iColliderIndex
vector m_vHitPosition
vector m_vHitDirection
func OnMeleePerformedDelegate
vector m_vHitNormal
IEntity m_Weapon
IEntity m_Bayonet
float m_fDamage
int m_iNodeIndex
Diagnostic and developer menu system.
Definition DiagMenu.c:18
proto external int SetEventMask(notnull IEntity owner, int mask)
proto external GenericComponent FindComponent(typename typeName)
void Rpc(func method, void p0=NULL, void p1=NULL, void p2=NULL, void p3=NULL, void p4=NULL, void p5=NULL, void p6=NULL, void p7=NULL)
proto external Managed FindComponent(typename typeName)
proto external IEntity GetChildren()
proto external BaseWorld GetWorld()
proto external IEntity GetParent()
proto external IEntity GetSibling()
Definition Math.c:13
Main replication API.
Definition Replication.c:14
Replication item identifier.
Definition RplId.c:14
void Debug_DrawSphereAtPos(vector pos, int color, array< ref Shape > dbgShapes)
vector GetAimingVector(notnull ChimeraCharacter character)
SCR_DamageManagerComponent SearchHierarchyForDamageManager(IEntity startEntity, out HitZone hitZone)
SCR_MeleeWeaponProperties m_MeleeWeaponProperties
void Debug_DrawLineSimple(vector start, vector end, array< ref Shape > dbgShapes)
void Do_OnFrameCleanup()
cleanup
void Update(float timeSlice)
Event methods.
void RPC_HandleMeleeSound(RplId weaponID, vector position, int signalValue0, int signalValue1)
bool TraceFilter(notnull IEntity ent)
void SetMeleeAttackStarted(bool started)
void PlaySound(IEntity weaponEntity, vector position, int signalValue0, int signalValue1)
void Debug_DrawSphereAtPos(vector v, array< ref Shape > dbgShapes, int color=COLOR_BLUE, float size=0.03, ShapeFlags shapeFlags=ShapeFlags.VISIBLE)
DEBUG methods.
ref OnMeleePerformedInvoker m_OnMeleePerformed
void PerformAttack()
Called from character command handler, based on user input.
ref SCR_MeleeHitDataClass m_MeleeHitData
bool m_bMeleeAttackStarted
attack execution limiter
bool m_bMeasurementDone
holds melee hit data
bool CheckCollisionsSimple(out SCR_MeleeHitDataClass pHitData)
void HandleMeleeSound()
Handles playing of sound & setting of signals (AUDIO).
override void OnPostInit(IEntity owner)
override void EOnInit(IEntity owner)
void ProcessMeleeAttack()
Processes the melee attack. Applies the damage if applicable.
OnMeleePerformedInvoker GetOnMeleePerformed()
proto external GenericEntity GetOwner()
Get owner entity.
Instance of created debug visualizer.
Definition Shape.c:14
const int COLOR_BLUE
Definition constants.c:23
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
ShapeFlags
Definition ShapeFlags.c:13
EntityEvent
Various entity events.
Definition EntityEvent.c:14
EDamageType
Definition EDamageType.c:13
void RplRpc(RplChannel channel, RplRcver rcver, RplCondition condition=RplCondition.None, string customConditionName="")
Definition EnNetwork.c:95
RplRcver
Definition RplRcver.c:59
RplChannel
Communication channel. Reliable is guaranteed to be delivered. Unreliable not.
Definition RplChannel.c:14
proto external string ToString()
Plain C++ pointer, no weak pointers, no memory management.
TraceFlags
Definition TraceFlags.c:13
proto int ARGBF(float fa, float fr, float fg, float fb)
Converts <0.0, 1.0> ARGB into color.