Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_MeleeComponent.c
Go to the documentation of this file.
1 [ComponentEditorProps(category: "GameScripted/Character", description: "Enables melee for character")]
2 class SCR_MeleeComponentClass : ScriptComponentClass
3 {
4 }
5 
6 class SCR_MeleeHitDataClass
7 {
8  IEntity m_Entity = null;
9  IEntity m_Weapon = null;
10  SurfaceProperties m_SurfaceProps = null;
11  int m_iNodeIndex = -1;
12  float m_fDamage = 0;
13  int m_iColliderIndex = -1;
14  vector m_vHitPosition = vector.Zero;
15  vector m_vHitDirection = vector.Zero;
16  vector m_vHitNormal = vector.Zero;
17 }
18 
19 void OnMeleePerformedDelegate(IEntity owner);
21 typedef ScriptInvokerBase<OnMeleePerformedDelegate> OnMeleePerformedInvoker;
22 
24 {
25  //#define SCR_MELEE_DEBUG //! uncomment to enable melee debug draws
26  //#define SCR_MELEE_DEBUG_MSG //! uncomment to enable melee debug prints into console
27 #ifdef SCR_MELEE_DEBUG
28  ref array<ref Shape> m_aDbgSamplePositionsShapes;
29  ref array<ref Shape> m_aDbgCollisionShapes;
30 #endif
31 
32  private ref SCR_MeleeHitDataClass m_MeleeHitData;
33  private bool m_bMeasurementDone;
34  private bool m_bAttackAlreadyExecuted = false;
35  private bool m_bMeleeAttackStarted = false;
36  private float m_fMWPWeaponRange = 1;
37  protected ref OnMeleePerformedInvoker m_OnMeleePerformed;
38 
39  //------------------------------------------------------------------------------------------------
41  OnMeleePerformedInvoker GetOnMeleePerformed()
42  {
43  if (!m_OnMeleePerformed)
44  m_OnMeleePerformed = new OnMeleePerformedInvoker;
45 
46  return m_OnMeleePerformed;
47  }
48 
49  //------------------------------------------------------------------------------------------------
51  void PerformAttack()
52  {
53  if (m_bAttackAlreadyExecuted)
54  return;
55 
56 #ifdef SCR_MELEE_DEBUG
57  Do_ClearDbgShapes();
58 #endif
59 
60  //This can be attached to a script invoker, which tells us the player changed their weapon
61  CollectMeleeWeaponProperties();
62  m_bAttackAlreadyExecuted = true;
63  }
64 
65  //------------------------------------------------------------------------------------------------
68  void SetMeleeAttackStarted(bool started)
69  {
70  m_bMeleeAttackStarted = started;
71 
72  if (!started)
73  Do_OnFrameCleanup();
74  }
75 
76  //------------------------------------------------------------------------------------------------
77  protected bool TraceFilter(notnull IEntity e)
78  {
79  return !SCR_ArmorDamageManagerComponent.Cast(e.FindComponent(SCR_ArmorDamageManagerComponent));
80  }
81 
82  //------------------------------------------------------------------------------------------------
86  protected bool CheckCollisionsSimple(out SCR_MeleeHitDataClass pHitData)
87  {
88  ChimeraCharacter character = ChimeraCharacter.Cast(GetOwner());
89  TraceSphere param = new TraceSphere();
90  param.Exclude = character;
91  param.LayerMask = EPhysicsLayerDefs.Projectile;
92  param.Flags = TraceFlags.ENTS | TraceFlags.WORLD;
93  param.Radius = 0.3;
94  param.Start = character.EyePosition();
96  param.End = param.Start + GetPlayersDirection(character) * m_fMWPWeaponRange;
97 
98  // Trace stops on the first hit entity if you want to change this, change the filter callback
99  float hit = character.GetWorld().TraceMove(param, TraceFilter);
100 
101  if (!param.TraceEnt)
102  return false;
103 
104  vector dir = (param.End - param.Start);
105 
106  pHitData.m_Entity = param.TraceEnt;
107  pHitData.m_iColliderIndex = param.ColliderIndex;
108  pHitData.m_vHitPosition = dir * hit + param.Start;
109  pHitData.m_vHitDirection = dir.Normalized();
110  pHitData.m_vHitNormal = param.TraceNorm;
111  pHitData.m_SurfaceProps = param.SurfaceProps;
112  pHitData.m_iNodeIndex = param.NodeIndex;
113 
114 #ifdef SCR_MELEE_DEBUG_MSG
115  MCDbgPrint("Check collision from: "+param.Start);
116  MCDbgPrint("Check collision to: "+param.End);
117  MCDbgPrint("Check collision range: " +vector.Distance(param.End, param.Start));
118  MCDbgPrint("Check collision entity: "+pHitData.m_Entity.ToString());
119  MCDbgPrint("Check collision hitzone: "+pHitData.m_sHitZoneName);
120  MCDbgPrint("Check collision hitPos: "+pHitData.m_vHitPosition);
121 #endif
122 
123  return true;
124  }
125 
126  // TODO: call this from SCR_CharacterControllerComponent.OnWeaponSelected() when possible and remove from PerformAttack()
127  //------------------------------------------------------------------------------------------------
130  protected void CollectMeleeWeaponProperties()
131  {
132  BaseWeaponManagerComponent wpnManager = BaseWeaponManagerComponent.Cast(GetOwner().FindComponent(BaseWeaponManagerComponent));
133  if (!wpnManager)
134  return;
135 
136  WeaponSlotComponent currentSlot = WeaponSlotComponent.Cast(wpnManager.GetCurrent());
137  if (!currentSlot)
138  return;
139 
141  m_MeleeHitData.m_Weapon = currentSlot.GetWeaponEntity();
142 
143  IEntity weaponEntity = currentSlot.GetWeaponEntity();
144  if (!weaponEntity)
145  return;
146 
147  SCR_MeleeWeaponProperties meleeWeaponProperties = SCR_MeleeWeaponProperties.Cast(weaponEntity.FindComponent(SCR_MeleeWeaponProperties));
148  if (!meleeWeaponProperties)
149  return;
150 
151  m_MeleeHitData.m_fDamage = meleeWeaponProperties.GetWeaponDamage();
152  m_fMWPWeaponRange = meleeWeaponProperties.GetWeaponRange();
153  }
154 
155  //------------------------------------------------------------------------------------------------
157  protected vector GetPlayersDirection(ChimeraCharacter character)
158  {
159  vector aimMat[4];
160  if (character)
161  Math3D.AnglesToMatrix(character.GetCharacterController().GetInputContext().GetAimingAngles() * Math.RAD2DEG, aimMat);
162 
163  return aimMat[2];
164  }
165 
166  //------------------------------------------------------------------------------------------------
168  protected void HandleMeleeSound()
169  {
170  IEntity weapon = m_MeleeHitData.m_Weapon;
171  if (!weapon)
172  return;
173 
174  GameMaterial material = m_MeleeHitData.m_SurfaceProps;
175  if (!material)
176  return;
177 
178  int surfaceInt = material.GetSoundInfo().GetSignalValue();
179 
180  PlaySound(m_MeleeHitData.m_Weapon, m_MeleeHitData.m_vHitPosition, m_MeleeHitData.m_iColliderIndex, surfaceInt);
181 
182  RplComponent weaponRpl = RplComponent.Cast(m_MeleeHitData.m_Weapon.FindComponent(RplComponent));
183  if (!weaponRpl)
184  return;
185 
186  Rpc(RPC_HandleMeleeSound, weaponRpl.Id(), m_MeleeHitData.m_vHitPosition, m_MeleeHitData.m_iColliderIndex, surfaceInt);
187 
188  #ifdef WORKBENCH
189  if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_SOUNDS_PRINT_MELEESURFACE))
190  {
191  Print(string.Format("HitZone: %1", m_MeleeHitData.m_iColliderIndex), LogLevel.NORMAL);
192  Print(string.Format("Surface: %1", surfaceInt), LogLevel.NORMAL);
193  Print(string.Format("-------------------------------------"), LogLevel.NORMAL);
194  }
195  #endif
196  }
197 
198  //------------------------------------------------------------------------------------------------
199  protected void PlaySound(IEntity weaponEntity, vector position, int signalValue0, int signalValue1)
200  {
201  SoundComponent soundComp = SoundComponent.Cast(weaponEntity.FindComponent(SoundComponent));
202  if (!soundComp)
203  return;
204 
205  soundComp.SetSignalValueStr("HitZone", signalValue0);
206  soundComp.SetSignalValueStr("Surface", signalValue1);
207 
208  vector transform[4];
209  Math3D.MatrixIdentity3(transform);
210  transform[3] = position;
211 
212  soundComp.SoundEventTransform(SCR_SoundEvent.SOUND_MELEE_IMPACT, transform);
213  }
214 
215  //------------------------------------------------------------------------------------------------
216  [RplRpc(RplChannel.Unreliable, RplRcver.Broadcast)]
217  protected void RPC_HandleMeleeSound(RplId weaponID, vector position, int signalValue0, int signalValue1)
218  {
219  RplComponent weaponRpl = RplComponent.Cast(Replication.FindItem(weaponID));
220  if (!weaponRpl)
221  return;
222 
223  IEntity weaponEntity = weaponRpl.GetEntity();
224  if (!weaponEntity)
225  return;
226 
227  PlaySound(weaponEntity, position, signalValue0, signalValue1);
228  }
229 
230  //------------------------------------------------------------------------------------------------
235  protected SCR_DamageManagerComponent SearchHierarchyForDamageManager(IEntity startEntity, out HitZone hitZone)
236  {
237  if (!startEntity)
238  return null;
239 
240  SCR_DamageManagerComponent damageManager;
241  while (startEntity)
242  {
243  damageManager = SCR_DamageManagerComponent.GetDamageManager(startEntity);
244  if (damageManager)
245  break;
246 
247  startEntity = startEntity.GetParent();
248  }
249 
250  if (damageManager)
251  hitZone = damageManager.GetDefaultHitZone();
252 
253  return damageManager;
254  }
255 
256  //------------------------------------------------------------------------------------------------
258  protected void ProcessMeleeAttack()
259  {
260  RplComponent rplComponent = RplComponent.Cast(GetOwner().FindComponent(RplComponent));
261  if (rplComponent && rplComponent.IsProxy())
262  return; // Don't call on clients
263 
264  if (!CheckCollisionsSimple(m_MeleeHitData))
265  return;
266 
267  if (m_MeleeHitData.m_Weapon)
268  HandleMeleeSound();
269 
270 #ifdef SCR_MELEE_DEBUG
271  m_aDbgSamplePositionsShapes.Clear();
272  Debug_DrawSphereAtPos(m_MeleeHitData.m_vHitPosition, m_aDbgSamplePositionsShapes, 0xff00ff00, 0.03, ShapeFlags.NOZBUFFER);
273 #endif
274 
275  vector hitPosDirNorm[3];
276  hitPosDirNorm[0] = m_MeleeHitData.m_vHitPosition;
277  hitPosDirNorm[1] = m_MeleeHitData.m_vHitDirection;
278  hitPosDirNorm[2] = m_MeleeHitData.m_vHitNormal;
279 
280  if (m_OnMeleePerformed)
281  m_OnMeleePerformed.Invoke(GetOwner());
282 
283  // check if the entity is destructible entity
284  SCR_DestructibleEntity destructibleEntity = SCR_DestructibleEntity.Cast(m_MeleeHitData.m_Entity);
285  if (destructibleEntity)
286  {
287  destructibleEntity.HandleDamage(EDamageType.MELEE, m_MeleeHitData.m_fDamage, hitPosDirNorm);
288  return;
289  }
290 
291  // check if the entity has the damage manager component
292  HitZone hitZone;
293  SCR_DamageManagerComponent damageManager = SearchHierarchyForDamageManager(m_MeleeHitData.m_Entity, hitZone);
294  if (!hitZone && damageManager)
295  hitZone = damageManager.GetDefaultHitZone();
296 
297  if (hitZone)
298  hitZone.HandleDamage(m_MeleeHitData.m_fDamage, EDamageType.MELEE, GetOwner());
299  }
300 
301  //------------------------------------------------------------------------------------------------
303  //------------------------------------------------------------------------------------------------
304 
305  //------------------------------------------------------------------------------------------------
307  protected void Do_OnFrameCleanup()
308  {
309  m_bAttackAlreadyExecuted = false;
310  m_bMeasurementDone = false;
311  }
312 
313 #ifdef SCR_MELEE_DEBUG
314  // dbg
315  //------------------------------------------------------------------------------------------------
317  protected void Do_ClearDbgShapes()
318  {
319  m_aDbgSamplePositionsShapes.Clear();
320  m_aDbgCollisionShapes.Clear();
321  }
322 #endif
323 
324  //------------------------------------------------------------------------------------------------
326  //------------------------------------------------------------------------------------------------
327 
328  //------------------------------------------------------------------------------------------------
330  protected void Debug_DrawSphereAtPos(vector v, array<ref Shape> dbgShapes, int color = COLOR_BLUE, float size = 0.03, ShapeFlags shapeFlags = ShapeFlags.VISIBLE)
331  {
332  shapeFlags = ShapeFlags.NOOUTLINE | shapeFlags;
333 
334  vector matx[4];
335  Math3D.MatrixIdentity4(matx);
336  matx[3] = v;
337  Shape s = Shape.CreateSphere(color, shapeFlags, GetOwner().GetOrigin(), size);
338  s.SetMatrix(matx);
339  dbgShapes.Insert(s);
340  }
341 
342  //------------------------------------------------------------------------------------------------
343  protected void Debug_DrawSphereAtPos(vector pos, int color, array<ref Shape> dbgShapes)
344  {
345  vector matx[4];
346  Math3D.MatrixIdentity4(matx);
347  matx[3] = pos;
348  int shapeFlags = ShapeFlags.NOOUTLINE|ShapeFlags.NOZBUFFER|ShapeFlags.TRANSP;
349  Shape s = Shape.CreateSphere(color, shapeFlags, pos, 0.05);
350  s.SetMatrix(matx);
351  dbgShapes.Insert(s);
352  }
353 
354  //------------------------------------------------------------------------------------------------
355  protected void Debug_DrawLineSimple(vector start, vector end, array<ref Shape> dbgShapes)
356  {
357  vector p[2];
358  p[0] = start;
359  p[1] = end;
360 
361  int shapeFlags = ShapeFlags.NOOUTLINE;
362  Shape s = Shape.CreateLines(ARGBF(1, 1, 1, 1), shapeFlags, p, 2);
363  dbgShapes.Insert(s);
364  }
365 
366 #ifdef SCR_MELEE_DEBUG_MSG
367  //------------------------------------------------------------------------------------------------
370  protected void MCDbgPrint(string msg = "")
371  {
372  Print("\\_ SCR_MELEE_DEBUG] " + GetGame().GetTickCount().ToString() + " ** " + msg, LogLevel.NORMAL);
373  }
374 #endif
375 
376  //------------------------------------------------------------------------------------------------
378  //------------------------------------------------------------------------------------------------
379 
380  //------------------------------------------------------------------------------------------------
383  void Update(float timeSlice)
384  {
385  if (!m_bAttackAlreadyExecuted || !m_bMeleeAttackStarted || m_bMeasurementDone)
386  return;
387 
389 #ifdef SCR_MELEE_DEBUG
390  vector start = ChimeraCharacter.Cast(GetOwner()).EyePosition();
392  vector end = start + GetPlayersDirection() * m_fMWPWeaponRange;
393 
394  Debug_DrawLineSimple(start, end, m_aDbgCollisionShapes);
395  Debug_DrawSphereAtPos(start, ARGBF(0.75, 0, 0, 1), m_aDbgCollisionShapes);
396  Debug_DrawSphereAtPos(end, ARGBF(0.75, 0, 0, 1), m_aDbgCollisionShapes);
397 #endif
398 
399  ProcessMeleeAttack();
400  m_bMeasurementDone = true;
401  }
402 
403  //------------------------------------------------------------------------------------------------
404  override void OnPostInit(IEntity owner)
405  {
406  super.OnPostInit(owner);
407  SetEventMask(owner, EntityEvent.INIT);
408  }
409 
410  //------------------------------------------------------------------------------------------------
411  override void EOnInit(IEntity owner)
412  {
413  m_MeleeHitData = new SCR_MeleeHitDataClass;
414 
415  if (!GetGame().GetWorldEntity())
416  return;
417 
418  #ifdef ENABLE_DIAG
419  DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_SOUNDS_PRINT_MELEESURFACE, "", "Print Melee Surface", "Sounds");
420  #endif
421 
422 #ifdef SCR_MELEE_DEBUG
423  m_aDbgSamplePositionsShapes = {};
424  m_aDbgCollisionShapes = {};
425 #endif
426  }
427 }
ComponentEditorProps
SCR_FragmentEntityClass ComponentEditorProps
m_fDamage
float m_fDamage
Definition: SCR_MeleeComponent.c:12
SCR_MeleeWeaponProperties
Definition: SCR_MeleeWeaponProperties.c:7
m_iColliderIndex
int m_iColliderIndex
Definition: SCR_MeleeComponent.c:13
ScriptComponent
SCR_SiteSlotEntityClass ScriptComponent
HitZone
Definition: HitZone.c:12
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
m_Weapon
IEntity m_Weapon
Definition: SCR_MeleeComponent.c:9
SCR_SoundEvent
Definition: SCR_SoundEvent.c:1
SCR_DestructibleEntity
void SCR_DestructibleEntity(IEntitySource src, IEntity parent)
Definition: SCR_DestructibleEntity.c:464
WeaponSlotComponent
Definition: WeaponSlotComponent.c:12
RplRpc
SCR_AchievementsHandlerClass ScriptComponentClass RplRpc(RplChannel.Reliable, RplRcver.Owner)] void UnlockOnClient(AchievementId achievement)
Definition: SCR_AchievementsHandler.c:11
func
func
Definition: SCR_AIThreatSystem.c:5
OnMeleePerformedInvoker
ScriptInvokerBase< OnMeleePerformedDelegate > OnMeleePerformedInvoker
Definition: SCR_MeleeComponent.c:21
m_SurfaceProps
SurfaceProperties m_SurfaceProps
Definition: SCR_MeleeComponent.c:10
GetOrigin
vector GetOrigin()
Definition: SCR_AIUtilityComponent.c:279
m_vHitNormal
vector m_vHitNormal
Definition: SCR_MeleeComponent.c:16
GetOwner
IEntity GetOwner()
Owner entity of the fuel tank.
Definition: SCR_FuelNode.c:128
m_Entity
SCR_MeleeComponentClass m_Entity
m_vHitDirection
vector m_vHitDirection
Definition: SCR_MeleeComponent.c:15
EDamageType
EDamageType
Definition: EDamageType.c:12
m_vHitPosition
vector m_vHitPosition
Definition: SCR_MeleeComponent.c:14
SCR_DebugMenuID
SCR_DebugMenuID
This enum contains all IDs for DiagMenu entries added in script.
Definition: DebugMenuID.c:3
position
vector position
Definition: SCR_DestructibleTreeV2.c:30
GameMaterial
Definition: GameMaterial.c:12
m_iNodeIndex
int m_iNodeIndex
Definition: SCR_MeleeComponent.c:11
OnMeleePerformedDelegate
func OnMeleePerformedDelegate
Definition: SCR_MeleeComponent.c:20
SCR_MeleeComponentClass
Definition: SCR_MeleeComponent.c:2
SCR_MeleeComponent
Definition: SCR_MeleeComponent.c:23
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180