Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_CharacterHitZone.c
Go to the documentation of this file.
2 {
3  WOUNDED = 3
4 };
5 
7 {
8  MODERATE = 3,
9  SERIOUS = 4,
11 };
12 
14 {
15  STRONG = 3,
16  FAINTING = 4,
18 };
19 
21 {
22  WEAKENED = 3,
23  FAINTING = 4,
24  UNCONSCIOUS = 5
25 };
26 
28 {
29  Invalid = 0,
30  UpperHead = 1,
31  LowerHead = 2,
34  LeftHand = 5,
35  RightHand = 6,
36  LeftLeg = 7,
38 };
39 
41 {
43  HitZone hitZone,
44  float DamageOverTime
45  )
46  {
47  m_hHitZone = hitZone;
48  m_fDamageOverTime = DamageOverTime;
49  }
50  HitZone m_hHitZone;
51  float m_fDamageOverTime;
52 };
53 
54 //------------------------------------------------------------------------------------------------
56 {
57  protected static const float DAMAGE_TO_BLOOD_MULTIPLIER = 1.3; //Const value is based on previous testing by caliber
58 
59  [Attribute("0.25", UIWidgets.Auto, "Multiplier of hitzone health that will be applied as bleeding damage over time when damaged")]
60  protected float m_fBleedingRateScale;
61 
62  [Attribute()]
63  protected ref array<string> m_aDamageSubmeshes;
64 
65  [Attribute("", UIWidgets.Object)]
66  protected ref array<ref LoadoutAreaType> m_aBleedingAreas;
67 
68  [Attribute(ECharacterHitZoneGroup.VIRTUAL.ToString(), UIWidgets.ComboBox, enums: ParamEnumArray.FromEnum(ECharacterHitZoneGroup))]
69  protected ECharacterHitZoneGroup m_eHitZoneGroup;
70 
71  [Attribute(EBandagingAnimationBodyParts.Invalid.ToString(), UIWidgets.ComboBox, enums: ParamEnumArray.FromEnum(EBandagingAnimationBodyParts))]
72  protected EBandagingAnimationBodyParts m_eBandageAnimationBodyPart;
73 
74  protected bool m_bIsWounded;
75 
76  //-----------------------------------------------------------------------------------------------------------
89  override void OnDamage(notnull BaseDamageContext damageContext)
90  {
91  super.OnDamage(damageContext);
92 
93  if (this != damageContext.struckHitZone)
94  return;
95 
96  // Request impact sound from damage manager
97  bool critical = damageContext.damageType == EDamageType.FIRE || damageContext.damageValue >= GetCriticalDamageThreshold() * GetMaxHealth();
98 
100  if (manager)
101  manager.SoundHit(critical, damageContext.damageType);
102 
103  // FireDamage shouldn't start bleedings
104  if (damageContext.damageType == EDamageType.FIRE)
105  return;
106 
107  // Only serious hits should cause bleeding
108  if (!critical)
109  return;
110 
111  // Adding immediately some blood to the clothes - currently it's based on the damage dealt.
112  AddBloodToClothes(Math.Clamp(damageContext.damageValue * DAMAGE_TO_BLOOD_MULTIPLIER, 0, 255));
113 
114  if (IsProxy())
115  return;
116 
117  if (Math.RandomFloat(0,1) < 0.3)
118  return;
119 
120  AddBleeding(damageContext.colliderID);
121  }
122 
123  //-----------------------------------------------------------------------------------------------------------
140  override float ComputeEffectiveDamage(notnull BaseDamageContext damageContext, bool isDOT)
141  {
142  float rawDamage = damageContext.damageValue;
143  if (damageContext.damageValue > 0 && !isDOT)
144  {
145  float protectionValue = GetArmorProtectionValue(damageContext.damageType);
146  rawDamage = Math.Max(damageContext.damageValue - protectionValue, 0);
147  }
148 
149  BaseDamageContext hack = BaseDamageContext.Cast(damageContext.Clone());
150  hack.damageValue = rawDamage;
151 
152  return super.ComputeEffectiveDamage(hack, isDOT);
153  }
154 
155  //-----------------------------------------------------------------------------------------------------------
157  float GetArmorProtectionValue(EDamageType damageType)
158  {
159  SCR_CharacterDamageManagerComponent damageMgr = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
160  if (!damageMgr)
161  return 0;
162 
163  return damageMgr.GetArmorProtection(this, damageType);
164  }
165 
166  //-----------------------------------------------------------------------------------------------------------
168  bool IsCovered()
169  {
170  CharacterIdentityComponent identity = CharacterIdentityComponent.Cast(GetOwner().FindComponent(CharacterIdentityComponent));
171  if (!identity)
172  return false;
173 
174  foreach (string submesh: m_aDamageSubmeshes)
175  {
176  if (identity.IsCovered(submesh))
177  return true;
178  }
179 
180  return false;
181  }
182 
183  //-----------------------------------------------------------------------------------------------------------
188  void AddBleeding(int colliderID = -1)
189  {
190  if (!HasColliderNodes())
191  return;
192 
193  int colliderDescriptorIndex = GetColliderDescriptorIndex(colliderID);
194  if (colliderDescriptorIndex < 0)
195  {
196  int currentHealth = GetHealth();
197  colliderDescriptorIndex = currentHealth % GetNumColliderDescriptors();
198  }
199 
200  AddBleedingToCollider(colliderDescriptorIndex);
201  }
202 
203  //-----------------------------------------------------------------------------------------------------------
208  void AddBleedingToCollider(int colliderDescriptorIndex = -1)
209  {
210  if (!HasColliderNodes())
211  return;
212 
213  // Currently we only have one bleeding per hitzone
214  SCR_CharacterDamageManagerComponent manager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
215  if (manager)
216  manager.AddBleedingHitZone(this, colliderDescriptorIndex);
217  }
218 
219  //-----------------------------------------------------------------------------------------------------------
220  override void OnDamageStateChanged()
221  {
222  super.OnDamageStateChanged();
223 
224  UpdateSubmeshes();
225  SCR_CharacterDamageManagerComponent manager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
226  if (manager)
227  manager.UpdateCharacterGroupDamage(GetHitZoneGroup());
228  }
229 
230  //-----------------------------------------------------------------------------------------------------------
231  void AddBloodToClothes(float immediateBloodEffect = 0)
232  {
233  EquipedLoadoutStorageComponent loadoutStorage = EquipedLoadoutStorageComponent.Cast(GetOwner().FindComponent(EquipedLoadoutStorageComponent));
234  if (!loadoutStorage)
235  return;
236 
237  IEntity clothEntity;
238  ParametricMaterialInstanceComponent materialComponent;
239  for (int i = m_aBleedingAreas.Count() - 1; i >= 0; i--)
240  {
241  clothEntity = loadoutStorage.GetClothFromArea(m_aBleedingAreas[i].Type());
242  if (!clothEntity)
243  continue;
244 
245  materialComponent = ParametricMaterialInstanceComponent.Cast(clothEntity.FindComponent(ParametricMaterialInstanceComponent));
246  if (!materialComponent)
247  continue;
248 
249  if (immediateBloodEffect > 0)
250  {
251  materialComponent.SetUserParam2(Math.Clamp(materialComponent.GetUserParam2() + immediateBloodEffect, 1, 255));
252  continue;
253  }
254 
255  materialComponent.SetUserParam2(Math.Clamp(materialComponent.GetUserParam2() + GetMaxBleedingRate() * 0.1, 1, 255));
256  }
257  }
258 
259  //-----------------------------------------------------------------------------------------------------------
260  void SetWoundedSubmesh(bool wounded)
261  {
262  m_bIsWounded = wounded;
263 
264  CharacterIdentityComponent identity = CharacterIdentityComponent.Cast(GetOwner().FindComponent(CharacterIdentityComponent));
265  if (!identity)
266  return;
267 
268  foreach (string submesh: m_aDamageSubmeshes)
269  identity.SetWoundState(submesh, wounded);
270  }
271 
272  //-----------------------------------------------------------------------------------------------------------
274  void UpdateSubmeshes()
275  {
276  bool isWounded = GetDamageStateThreshold(GetDamageState()) <= GetDamageStateThreshold(ECharacterDamageState.WOUNDED);
277  if (m_bIsWounded != isWounded)
278  SetWoundedSubmesh(isWounded);
279  }
280 
281  //-----------------------------------------------------------------------------------------------------------
285  float GetMaxBleedingRate()
286  {
287  SCR_CharacterDamageManagerComponent manager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
288  if (!manager)
289  return 1;
290 
291  float bleedingRate = m_fBleedingRateScale * GetMaxHealth();
292 
293  bleedingRate *= manager.GetDOTScale();
294 
295  return bleedingRate;
296  }
297 
298  //-----------------------------------------------------------------------------------------------------------
299  override EHitZoneGroup GetHitZoneGroup()
300  {
301  return m_eHitZoneGroup;
302  }
303 
304  //-----------------------------------------------------------------------------------------------------------
305  EBandagingAnimationBodyParts GetBodyPartToHeal()
306  {
307  return m_eBandageAnimationBodyPart;
308  }
309 };
310 
311 //------------------------------------------------------------------------------------------------
313 {
314  [Attribute("10", UIWidgets.Auto, "Time without receiving damage or bleeding to start regeneration\n[s]")]
315  protected float m_fRegenerationDelay;
316 
317  [Attribute("200", UIWidgets.Auto, "Time to regenerate this hitzone fully\n[s]")]
318  protected float m_fFullRegenerationTime;
319 
320  //-----------------------------------------------------------------------------------------------------------
333  override void OnDamage(notnull BaseDamageContext damageContext)
334  {
335  super.OnDamage(damageContext);
336 
337  if (IsProxy())
338  return;
339 
340  RemovePassiveRegeneration();
341  ScheduleRegeneration();
342  }
343 
344  //-----------------------------------------------------------------------------------------------------------
345  override void OnHealthSet()
346  {
347  super.OnHealthSet();
348 
349  if (IsProxy())
350  return;
351 
352  RemovePassiveRegeneration();
353  ScheduleRegeneration();
354  }
355 
356  //-----------------------------------------------------------------------------------------------------------
357  // Calculate rate of passive regeneration
358  float CalculatePassiveRegeneration()
359  {
360  if (m_fFullRegenerationTime <= 0)
361  return 0;
362 
363  // Any local damage over time shall disrupt passive regeneration
364  array<EDamageType> damageTypes = {};
365  SCR_Enum.GetEnumValues(EDamageType, damageTypes);
366  foreach (EDamageType damageType : damageTypes)
367  {
368  if (damageType == EDamageType.REGENERATION || damageType == EDamageType.HEALING)
369  continue;
370 
371  if (GetDamageOverTime(damageType) != 0)
372  return 0;
373  }
374 
375  return -GetMaxHealth() / m_fFullRegenerationTime;
376  }
377 
378  //-----------------------------------------------------------------------------------------------------------
379  // Schedule healing over time, delay current scheduled regeneration
380  void ScheduleRegeneration()
381  {
382  GetGame().GetCallqueue().Remove(UpdatePassiveRegeneration);
383  GetGame().GetCallqueue().CallLater(UpdatePassiveRegeneration, 1000 * m_fRegenerationDelay, true);
384  }
385 
386  //-----------------------------------------------------------------------------------------------------------
387  // Remove current healing over time and any scheduled regeneration
388  void RemovePassiveRegeneration()
389  {
390  GetGame().GetCallqueue().Remove(UpdatePassiveRegeneration);
391 
392  if (GetDamageOverTime(EDamageType.REGENERATION))
393  SetDamageOverTime(EDamageType.REGENERATION, 0)
394  }
395 
396  //-----------------------------------------------------------------------------------------------------------
397  protected void UpdatePassiveRegeneration()
398  {
399  float regenerationRate = CalculatePassiveRegeneration();
400  SetDamageOverTime(EDamageType.REGENERATION, regenerationRate);
401  }
402 
403  //-----------------------------------------------------------------------------------------------------------
404  override void OnDamageStateChanged()
405  {
406  super.OnDamageStateChanged();
407 
408  if (GetDamageState() == ECharacterDamageState.UNDAMAGED)
409  RemovePassiveRegeneration();
410  }
411 };
412 
413 //-----------------------------------------------------------------------------------------------------------
416 {
417  //-----------------------------------------------------------------------------------------------------------
418  override float ComputeEffectiveDamage(notnull BaseDamageContext damageContext, bool isDOT)
419  {
420  // Handle falldamage. Falldamage is applied to defaultHZ, so it's propegated down to physical hitzones manually, then back up to the health HZ like normal damage.
421  if (damageContext.damageType == EDamageType.COLLISION && damageContext.struckHitZone == this)
422  {
423  SCR_CharacterDamageManagerComponent damageManager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
424  if (damageManager && damageContext.damageValue > GetDamageThreshold())
425  damageManager.HandleFallDamage(damageContext.damageValue);
426 
427  return 0;
428  }
429 
430  return super.ComputeEffectiveDamage(damageContext, isDOT);
431  }
432 }
433 
434 //-----------------------------------------------------------------------------------------------------------
436 class SCR_CharacterResilienceHitZone : SCR_RegeneratingHitZone
437 {
438  //-----------------------------------------------------------------------------------------------------------
439  override void OnDamageStateChanged()
440  {
441  super.OnDamageStateChanged();
442 
444  }
445 
446  //-----------------------------------------------------------------------------------------------------------
448  {
449  SCR_CharacterDamageManagerComponent damageManager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
450  if (damageManager)
451  damageManager.UpdateConsciousness();
452  }
453 
454  //-----------------------------------------------------------------------------------------------------------
456  {
457  float regeneration = super.CalculatePassiveRegeneration();
458 
459  SCR_CharacterDamageManagerComponent manager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
460  if (!manager)
461  return regeneration;
462 
463  regeneration *= manager.GetResilienceRegenScale();
464 
465  return regeneration;
466  }
467 
468  //-----------------------------------------------------------------------------------------------------------
469  override void OnInit(IEntity pOwnerEntity, GenericComponent pManagerComponent)
470  {
471  super.OnInit(pOwnerEntity, pManagerComponent);
472  SCR_CharacterDamageManagerComponent characterDamageManager = SCR_CharacterDamageManagerComponent.Cast(pManagerComponent);
473  if (characterDamageManager)
474  characterDamageManager.SetResilienceHitZone(this);
475  }
476 };
477 
478 //-----------------------------------------------------------------------------------------------------------
481 {
482  ref map<SCR_CharacterHitZone, ref SCR_BleedingHitZoneParameters> m_mHitZoneDOTMap;
483  ref array<float> m_aHitZoneGroupBleedings;
484 
485  //-----------------------------------------------------------------------------------------------------------
486  override void OnDamageStateChanged()
487  {
488  super.OnDamageStateChanged();
489 
490  UpdateConsciousness();
491  }
492 
493  //-----------------------------------------------------------------------------------------------------------
494  void UpdateConsciousness()
495  {
496  SCR_CharacterDamageManagerComponent damageManager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
497  if (damageManager)
498  damageManager.UpdateConsciousness();
499  }
500 
501  //-----------------------------------------------------------------------------------------------------------
502  override void OnInit(IEntity pOwnerEntity, GenericComponent pManagerComponent)
503  {
504  super.OnInit(pOwnerEntity, pManagerComponent);
505 
506  SCR_CharacterDamageManagerComponent manager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
507  if (manager)
508  manager.SetBloodHitZone(this);
509  }
510 
511  //-----------------------------------------------------------------------------------------------------------
512  bool AddBleedingHZToMap(SCR_CharacterHitZone hitZone, SCR_BleedingHitZoneParameters localBleedingHZParams)
513  {
514  if (!m_mHitZoneDOTMap)
515  m_mHitZoneDOTMap = new map<SCR_CharacterHitZone, ref SCR_BleedingHitZoneParameters>();
516 
517  if (m_mHitZoneDOTMap.Contains(hitZone))
518  {
519  m_mHitZoneDOTMap.Set(hitZone, localBleedingHZParams);
520  return true;
521  }
522 
523  return m_mHitZoneDOTMap.Insert(hitZone, localBleedingHZParams);
524  }
525 
526  //-----------------------------------------------------------------------------------------------------------
527  void RemoveBleedingHZFromMap(SCR_CharacterHitZone hitZone)
528  {
529  if (!m_mHitZoneDOTMap)
530  return;
531 
532  m_mHitZoneDOTMap.Remove(hitZone);
533 
534  if (m_mHitZoneDOTMap.IsEmpty())
535  m_mHitZoneDOTMap = null;
536  }
537 
538  //-----------------------------------------------------------------------------------------------------------
539  float GetPhysicalHZBleedingDOT(notnull SCR_CharacterHitZone hitZone)
540  {
541  if (!m_mHitZoneDOTMap || m_mHitZoneDOTMap.IsEmpty())
542  return 0;
543 
544  SCR_BleedingHitZoneParameters localBleedingHZParams;
545 
546  if (m_mHitZoneDOTMap.Find(hitZone, localBleedingHZParams))
547  return localBleedingHZParams.m_fDamageOverTime;
548 
549  return 0;
550  }
551 
552  //-----------------------------------------------------------------------------------------------------------
553  map<SCR_CharacterHitZone, ref SCR_BleedingHitZoneParameters> GetHitZoneDOTMap()
554  {
555  return m_mHitZoneDOTMap;
556  }
557 };
558 
559 //-----------------------------------------------------------------------------------------------------------
561 {
562  //-----------------------------------------------------------------------------------------------------------
563  override void OnInit(IEntity pOwnerEntity, GenericComponent pManagerComponent)
564  {
565  super.OnInit(pOwnerEntity, pManagerComponent);
566 
568  if (manager)
569  manager.SetHeadHitZone(this);
570  }
571 
572  //-----------------------------------------------------------------------------------------------------------
573  override void OnDamageStateChanged()
574  {
575  super.OnDamageStateChanged();
576  SoundKnockout();
577  }
578 
579  //-----------------------------------------------------------------------------------------------------------
581  void SoundKnockout()
582  {
583  if (GetDamageState() != EDamageState.DESTROYED)
584  return;
585 
586  SCR_CharacterDamageManagerComponent manager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
587  if (manager)
588  manager.SoundKnockout();
589  }
590 };
ECharacterHitZoneGroup
ECharacterHitZoneGroup
Definition: SCR_CharacterDamageManagerComponent.c:1
BaseDamageContext
Definition: BaseDamageContext.c:12
LeftLeg
@ LeftLeg
Definition: SCR_CharacterHitZone.c:36
m_eHitZoneGroup
protected ECharacterHitZoneGroup m_eHitZoneGroup
Definition: SCR_InventoryHitZonePointUI.c:403
GetMaxHealth
float GetMaxHealth()
Definition: SCR_DestructibleEntity.c:122
SCR_Enum
Definition: SCR_Enum.c:1
RightLeg
@ RightLeg
Definition: SCR_CharacterHitZone.c:37
SCR_CharacterHitZone
Definition: SCR_CharacterHitZone.c:55
LowerHead
@ LowerHead
Definition: SCR_CharacterHitZone.c:31
HitZone
Definition: HitZone.c:12
WEAKENED
@ WEAKENED
Definition: SCR_CharacterHitZone.c:22
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
CalculatePassiveRegeneration
override float CalculatePassiveRegeneration()
Definition: SCR_CharacterHitZone.c:455
LowerTorso
@ LowerTorso
Definition: SCR_CharacterHitZone.c:33
Invalid
@ Invalid
Definition: SCR_CharacterHitZone.c:29
EDamageState
EDamageState
Definition: EDamageState.c:12
UNCONSCIOUS
@ UNCONSCIOUS
Definition: SCR_CharacterHitZone.c:17
SCR_CharacterBloodHitZone
Blood - does not receive damage directly, only via scripted events.
Definition: SCR_CharacterHitZone.c:480
UpperHead
@ UpperHead
Definition: SCR_CharacterHitZone.c:30
RightHand
@ RightHand
Definition: SCR_CharacterHitZone.c:35
SCR_RegeneratingHitZone
Definition: SCR_CharacterHitZone.c:312
GetDamageThreshold
float GetDamageThreshold()
Definition: SCR_DestructibleEntity.c:112
IsProxy
protected bool IsProxy()
Definition: SCR_CampaignBuildingCompositionComponent.c:456
ECharacterDamageState
ECharacterDamageState
Definition: SCR_CharacterHitZone.c:1
GetHealth
float GetHealth()
Definition: SCR_FuelNode.c:196
Attribute
typedef Attribute
Post-process effect of scripted camera.
SCR_CharacterDamageManagerComponent
Definition: SCR_CharacterDamageManagerComponent.c:18
CRITICAL
@ CRITICAL
Definition: SCR_CharacterHitZone.c:10
OnDamageStateChanged
SCR_CharacterBloodHitZone OnDamageStateChanged
Resilience - incapacitation or death, depending on game mode settings.
Definition: SCR_CharacterHitZone.c:439
STRONG
@ STRONG
Definition: SCR_CharacterHitZone.c:15
UpdateConsciousness
void UpdateConsciousness()
Definition: SCR_CharacterHitZone.c:447
ECharacterHealthState
ECharacterHealthState
Definition: SCR_CharacterHitZone.c:6
GetOwner
IEntity GetOwner()
Owner entity of the fuel tank.
Definition: SCR_FuelNode.c:128
ECharacterResilienceState
ECharacterResilienceState
Definition: SCR_CharacterHitZone.c:20
SCR_HitZone
Definition: SCR_HitZone.c:1
OnInit
override void OnInit(IEntity pOwnerEntity, GenericComponent pManagerComponent)
Definition: SCR_CharacterHitZone.c:469
EDamageType
EDamageType
Definition: EDamageType.c:12
FAINTING
@ FAINTING
Definition: SCR_CharacterHitZone.c:16
SCR_CharacterHeadHitZone
Definition: SCR_CharacterHitZone.c:560
ParametricMaterialInstanceComponent
Definition: ParametricMaterialInstanceComponent.c:12
LeftHand
@ LeftHand
Definition: SCR_CharacterHitZone.c:34
SERIOUS
@ SERIOUS
Definition: SCR_CharacterHitZone.c:9
SCR_BleedingHitZoneParameters
Definition: SCR_CharacterHitZone.c:40
UpperTorso
@ UpperTorso
Definition: SCR_CharacterHitZone.c:32
WOUNDED
@ WOUNDED
Definition: SCR_CharacterHitZone.c:3
ECharacterBloodState
ECharacterBloodState
Definition: SCR_CharacterHitZone.c:13
EBandagingAnimationBodyParts
EBandagingAnimationBodyParts
Definition: SCR_CharacterHitZone.c:27
MODERATE
@ MODERATE
Definition: SCR_CharacterHitZone.c:8
SCR_CharacterHealthHitZone
health hitzone - Receives damage from physical hitzones
Definition: SCR_CharacterHitZone.c:415