Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_CharacterHitZone.c
Go to the documentation of this file.
1//---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
2// TODO: Move enum definitions to separate file possibly in Damage folder
7
14
21
28
41
48
49//---- REFACTOR NOTE END ----
50
51class SCR_BleedingHitZoneParameters : Managed
52{
53 void SCR_BleedingHitZoneParameters(
54 HitZone hitZone,
55 float DamageOverTime
56 )
57 {
58 m_hHitZone = hitZone;
59 m_fDamageOverTime = DamageOverTime;
60 }
61 HitZone m_hHitZone;
62 float m_fDamageOverTime;
63};
64
65//------------------------------------------------------------------------------------------------
67{
68 [Attribute(defvalue: "200", desc: "Time required to fully regenerate this hit zone\n[s]")]
69 protected float m_fFullRegenerationTime;
70
71 protected bool m_bAutoRegenOnHealthSet = true;
72
73 //-----------------------------------------------------------------------------------------------------------
78 float CalculatePassiveRegenDPS(bool considerRegenScale = true)
79 {
81 return 0;
82
83 if (considerRegenScale)
84 {
86 if (damageMgr && damageMgr.s_HealthSettings)
87 {
88 if (SCR_CharacterResilienceHitZone.Cast(this))
89 return ((GetMaxHealth() / m_fFullRegenerationTime) * damageMgr.s_HealthSettings.GetResilienceHzRegenScale());
90
91 return (GetMaxHealth() / m_fFullRegenerationTime) * damageMgr.GetRegenScale();
92 }
93 }
94
96 }
97
98 //-----------------------------------------------------------------------------------------------------------
100 float GetHitZoneDamageOverTime(EDamageType targetDamageType)
101 {
102 array<ref SCR_PersistentDamageEffect> effects = {};
103 float dot;
104
105 // if damageManager is not cast, throw assert
106 SCR_CharacterDamageManagerComponent damageMgr = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
107 if (damageMgr == null)
108 return 0;
109
110 damageMgr.FindDamageEffectsOnHitZone(this, effects);
111
112 // if wanted dps is physical hitZone passive regen, return the exact value. If the regen is still in delaytimer, return 0
113 if (targetDamageType == EDamageType.REGENERATION && SCR_CharacterHitZone.Cast(this))
114 {
115 array<ref SCR_PersistentDamageEffect> persistentEffects = damageMgr.GetAllPersistentEffectsOfType(SCR_PhysicalHitZonesRegenDamageEffect);
116 if (!persistentEffects.IsEmpty())
117 {
118 SCR_PhysicalHitZonesRegenDamageEffect regenDamageEffect = SCR_PhysicalHitZonesRegenDamageEffect.Cast(persistentEffects[0]);
119 if (regenDamageEffect.DelayTimerRanOut())
121 else
122 return 0;
123 }
124 }
125
126 // if wanted dps is physical hitZone healing, add defaultHitZone to checked hitZones
127 if (SCR_CharacterHitZone.Cast(this) && targetDamageType == EDamageType.HEALING)
128 damageMgr.FindDamageEffectsOnHitZone(damageMgr.GetDefaultHitZone(), effects);
129
130 foreach (SCR_PersistentDamageEffect effect : effects)
131 {
132 DotDamageEffect dotEffect = DotDamageEffect.Cast(effect);
133 if (dotEffect && dotEffect.GetDamageType() == targetDamageType)
134 dot += dotEffect.GetDPS();
135 }
136
137 return dot;
138 }
139
140 //-----------------------------------------------------------------------------------------------------------
142 override void OnHealthSet()
143 {
144 super.OnHealthSet();
145
147 return;
148
149 SCR_CharacterDamageManagerComponent damageMgr = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
150 if (!damageMgr)
151 return;
152
153 // OnHealthSet, call start relevant passive regeneration depending on the hitzone type
154 if (SCR_CharacterHitZone.Cast(this))
155 damageMgr.RegenPhysicalHitZones();
156 else
157 damageMgr.RegenVirtualHitZone(this);
158 }
159
160 //-----------------------------------------------------------------------------------------------------------
164 {
165 m_bAutoRegenOnHealthSet = doRegen;
166 }
167}
168
169//------------------------------------------------------------------------------------------------
170class SCR_CharacterHitZone : SCR_RegeneratingHitZone
171{
172 protected static const float DAMAGE_TO_BLOOD_MULTIPLIER = 15; //Const value is based on previous testing by caliber
173
174 [Attribute("0.65", UIWidgets.Auto, "Multiplier of hitzone health that will be applied as bleeding damage over time when damaged")]
175 protected float m_fBleedingRateScale;
176
177 [Attribute()]
178 protected ref array<string> m_aDamageSubmeshes;
179
180 [Attribute("", UIWidgets.Object)]
181 protected ref array<ref LoadoutAreaType> m_aBleedingAreas;
182
183 [Attribute(ECharacterHitZoneGroup.VIRTUAL.ToString(), UIWidgets.ComboBox, enumType: ECharacterHitZoneGroup)]
185
186 [Attribute(EBandagingAnimationBodyParts.Invalid.ToString(), UIWidgets.ComboBox, enumType: EBandagingAnimationBodyParts)]
188
189 [Attribute(SCR_EForcedWoundedSubmesh.DISABLED.ToString(), UIWidgets.ComboBox, enumType: SCR_EForcedWoundedSubmesh)]
191
192 protected bool m_bIsWounded;
193
194 //-----------------------------------------------------------------------------------------------------------
195 override void OnInit(IEntity pOwnerEntity, GenericComponent pManagerComponent)
196 {
197 super.OnInit(pOwnerEntity, pManagerComponent);
198
200 GetGame().GetCallqueue().CallLater(UpdateSubmeshes);
201 }
202
203 //-----------------------------------------------------------------------------------------------------------
204 override void OnDamage(notnull BaseDamageContext damageContext)
205 {
206 super.OnDamage(damageContext);
207
208 if (this != damageContext.struckHitZone)
209 return;
210
211 // Request impact sound from damage manager
212 bool critical = damageContext.damageType == EDamageType.FIRE || damageContext.damageValue >= GetCriticalHealthThreshold();
213
215 if (!manager)
216 return;
217
218 manager.SoundHit(critical, damageContext.damageType);
219
220 // FireDamage shouldn't make character look bloody
221 if (damageContext.damageType == EDamageType.FIRE)
222 return;
223
224 float bloodAddition = damageContext.damageValue / GetMaxHealth() * DAMAGE_TO_BLOOD_MULTIPLIER;
225
226 // Adding immediately some blood to the clothes - currently it's based on the damage dealt.
227 manager.AddBloodToClothes(this, Math.Clamp(bloodAddition , 0, 255));
228 }
229
230 //-----------------------------------------------------------------------------------------------------------
231 override float ComputeEffectiveDamage(notnull BaseDamageContext damageContext, bool isDOT)
232 {
233 if (isDOT)
234 return super.ComputeEffectiveDamage(damageContext, isDOT);
235
236 BaseDamageContext hack = BaseDamageContext.Cast(damageContext.Clone());
237 float damage = damageContext.damageValue * GetBaseDamageMultiplier();
238 damage *= GetDamageMultiplier(damageContext.damageType);
239
240 if (damage > 0)
241 {
242 float protectionValue = GetArmorProtectionValue(damageContext.damageType);
243 float damageScale = ((damage - protectionValue) / damage);
244 damageScale = Math.Max(damageScale, 0);
245
246 hack.damageValue *= damageScale;
247 }
248
249 return super.ComputeEffectiveDamage(hack, isDOT);
250 }
251
252 //-----------------------------------------------------------------------------------------------------------
255 {
256 SCR_CharacterDamageManagerComponent damageMgr = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
257 if (!damageMgr)
258 return 0;
259
260 return damageMgr.GetArmorProtection(this, damageType);
261 }
262
263 //-----------------------------------------------------------------------------------------------------------
266 {
267 CharacterIdentityComponent identity = CharacterIdentityComponent.Cast(GetOwner().FindComponent(CharacterIdentityComponent));
268 if (!identity)
269 return false;
270
271 foreach (string submesh: m_aDamageSubmeshes)
272 {
273 if (identity.IsCovered(submesh))
274 return true;
275 }
276
277 return false;
278 }
279
280 //-----------------------------------------------------------------------------------------------------------
281 override void OnDamageStateChanged(EDamageState newState, EDamageState previousDamageState, bool isJIP)
282 {
283 super.OnDamageStateChanged(newState, previousDamageState, isJIP);
284
286
288 if (manager)
290 }
291
292 //-----------------------------------------------------------------------------------------------------------
293 void SetWoundedSubmesh(bool wounded)
294 {
295 m_bIsWounded = wounded;
296
297 CharacterIdentityComponent identity = CharacterIdentityComponent.Cast(GetOwner().FindComponent(CharacterIdentityComponent));
298 if (!identity)
299 return;
300
301 foreach (string submesh: m_aDamageSubmeshes)
302 identity.SetWoundState(submesh, wounded);
303 }
304
305 //-----------------------------------------------------------------------------------------------------------
308 {
309 bool isWounded;
311 {
312 case SCR_EForcedWoundedSubmesh.DISABLED:
313 isWounded = GetDamageStateThreshold(GetDamageState()) <= GetDamageStateThreshold(ECharacterDamageState.WOUNDED);
314 break;
315
316 case SCR_EForcedWoundedSubmesh.FORCED_WOUNDED:
317 isWounded = true;
318 break;
319
320 case SCR_EForcedWoundedSubmesh.FORCED_NOT_WOUNDED:
321 isWounded = false;
322 break;
323 }
324
325 if (m_bIsWounded != isWounded)
326 SetWoundedSubmesh(isWounded);
327 }
328
329 //-----------------------------------------------------------------------------------------------------------
333 {
335 if (!manager)
336 return 1;
337
338 float bleedingRate = m_fBleedingRateScale * GetMaxHealth();
339
340 bleedingRate *= manager.GetBleedingScale();
341
342 return bleedingRate;
343 }
344
345 //-----------------------------------------------------------------------------------------------------------
348 {
349 return GetCriticalDamageThreshold() * GetMaxHealth();
350 }
351
352 //-----------------------------------------------------------------------------------------------------------
354 {
355 return m_eHitZoneGroup;
356 }
357
358 //-----------------------------------------------------------------------------------------------------------
359 array<ref LoadoutAreaType> GetBleedingAreas()
360 {
361 return m_aBleedingAreas;
362 }
363
364 //-----------------------------------------------------------------------------------------------------------
369};
370
371//-----------------------------------------------------------------------------------------------------------
376
377//-----------------------------------------------------------------------------------------------------------
379class SCR_CharacterResilienceHitZone : SCR_RegeneratingHitZone
380{
381 //-----------------------------------------------------------------------------------------------------------
382 override void OnDamage(notnull BaseDamageContext damageContext)
383 {
384 super.OnDamage(damageContext);
385
386 SCR_CharacterDamageManagerComponent characterDmgManager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
387 if (!characterDmgManager)
388 return;
389
390 // passive healing on resilienceHitZone should stop when resilience is damaged
391 array<ref SCR_PersistentDamageEffect> effects = {};
392 characterDmgManager.FindAllDamageEffectsOfTypeOnHitZone(SCR_PassiveHitZoneRegenDamageEffect, this, effects);
393 foreach (SCR_PersistentDamageEffect effect : effects)
394 {
395 effect.Terminate();
396 }
397
398 characterDmgManager.RegenVirtualHitZone(this);
399 }
400
401 //-----------------------------------------------------------------------------------------------------------
402 override void OnDamageStateChanged(EDamageState newState, EDamageState previousDamageState, bool isJIP)
403 {
404 super.OnDamageStateChanged(newState, previousDamageState, isJIP);
405
407 }
408
409 //-----------------------------------------------------------------------------------------------------------
411 {
412 SCR_CharacterDamageManagerComponent damageManager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
413 if (damageManager)
414 damageManager.UpdateConsciousness();
415 }
416
417 //-----------------------------------------------------------------------------------------------------------
418 override void OnInit(IEntity pOwnerEntity, GenericComponent pManagerComponent)
419 {
420 super.OnInit(pOwnerEntity, pManagerComponent);
421 SCR_CharacterDamageManagerComponent characterDamageManager = SCR_CharacterDamageManagerComponent.Cast(pManagerComponent);
422 if (characterDamageManager)
423 characterDamageManager.SetResilienceHitZone(this);
424 }
425};
426
427//-----------------------------------------------------------------------------------------------------------
430{
432 ref array<float> m_aHitZoneGroupBleedings;
433
434 //-----------------------------------------------------------------------------------------------------------
435 override void OnDamageStateChanged(EDamageState newState, EDamageState previousDamageState, bool isJIP)
436 {
437 super.OnDamageStateChanged(newState, previousDamageState, isJIP);
438
440 }
441
442 //-----------------------------------------------------------------------------------------------------------
444 {
445 SCR_CharacterDamageManagerComponent damageManager = SCR_CharacterDamageManagerComponent.Cast(GetHitZoneContainer());
446 if (damageManager)
447 damageManager.UpdateConsciousness();
448 }
449
450 //-----------------------------------------------------------------------------------------------------------
451 override void OnInit(IEntity pOwnerEntity, GenericComponent pManagerComponent)
452 {
453 super.OnInit(pOwnerEntity, pManagerComponent);
454
456 if (manager)
457 manager.SetBloodHitZone(this);
458 }
459
460 //-----------------------------------------------------------------------------------------------------------
461 float GetTotalBleedingAmount()
462 {
463 float dps;
464
465 SCR_ExtendedDamageManagerComponent extendedDmgManager = SCR_ExtendedDamageManagerComponent.Cast(GetHitZoneContainer());
466 if (!extendedDmgManager)
467 return dps;
468
469 DotDamageEffect dotEffect;
470 array<ref SCR_PersistentDamageEffect> bleedingEffects = extendedDmgManager.GetAllPersistentEffectsOfType(SCR_BleedingDamageEffect);
471 foreach (SCR_PersistentDamageEffect effect : bleedingEffects)
472 {
473 dotEffect = DotDamageEffect.Cast(effect);
474 if (!dotEffect)
475 continue;
476
477 dps += dotEffect.GetDPS();
478 }
479
480 return dps;
481 }
482
483 //---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
484 //-----------------------------------------------------------------------------------------------------------
485 bool AddBleedingHZToMap(SCR_CharacterHitZone hitZone, SCR_BleedingHitZoneParameters localBleedingHZParams)
486 {
487 if (!m_mHitZoneDOTMap)
489
490 if (m_mHitZoneDOTMap.Contains(hitZone))
491 {
492 m_mHitZoneDOTMap.Set(hitZone, localBleedingHZParams);
493 return true;
494 }
495
496 return m_mHitZoneDOTMap.Insert(hitZone, localBleedingHZParams);
497 }
498
499 //-----------------------------------------------------------------------------------------------------------
500 void RemoveBleedingHZFromMap(SCR_CharacterHitZone hitZone)
501 {
502 if (!m_mHitZoneDOTMap)
503 return;
504
505 m_mHitZoneDOTMap.Remove(hitZone);
506
507 if (m_mHitZoneDOTMap.IsEmpty())
508 m_mHitZoneDOTMap = null;
509 }
510
511 //-----------------------------------------------------------------------------------------------------------
513 {
514 return m_mHitZoneDOTMap;
515 }
516 //---- REFACTOR NOTE END ----
517};
518
519//-----------------------------------------------------------------------------------------------------------
520class SCR_CharacterHeadHitZone : SCR_CharacterHitZone
521{
522 //-----------------------------------------------------------------------------------------------------------
523 override void OnInit(IEntity pOwnerEntity, GenericComponent pManagerComponent)
524 {
525 super.OnInit(pOwnerEntity, pManagerComponent);
526
528 if (manager)
529 manager.SetHeadHitZone(this);
530 }
531
532 //-----------------------------------------------------------------------------------------------------------
533 override void OnDamageStateChanged(EDamageState newState, EDamageState previousDamageState, bool isJIP)
534 {
535 super.OnDamageStateChanged(newState, previousDamageState, isJIP);
536 SoundKnockout();
537 }
538
539 //-----------------------------------------------------------------------------------------------------------
541 void SoundKnockout()
542 {
543 if (GetDamageState() != EDamageState.DESTROYED)
544 return;
545
547 if (manager)
548 manager.SoundKnockout();
549 }
550};
EHitZoneGroup
ArmaReforgerScripted GetGame()
Definition game.c:1398
@ WOUNDED
float m_fBleedingRateScale
SCR_RegeneratingHitZone DAMAGE_TO_BLOOD_MULTIPLIER
SCR_CharacterBloodHitZone OnDamage
Resilience - incapacitation or death, depending on game mode settings.
EBandagingAnimationBodyParts
ECharacterHealthState
void UpdateConsciousness()
ECharacterBloodState
void UpdateSubmeshes()
Manage wounds submeshes.
void SetWoundedSubmesh(bool wounded)
EBandagingAnimationBodyParts m_eBandageAnimationBodyPart
float GetMaxBleedingRate()
array< ref LoadoutAreaType > GetBleedingAreas()
float GetArmorProtectionValue(EDamageType damageType)
Get strength of protection from armor attribute on prefab of clothing item.
ECharacterDamageState
ref array< string > m_aDamageSubmeshes
bool IsCovered()
Whether hitzone submeshes are hidden with clothing.
float GetCriticalHealthThreshold()
ECharacterResilienceState
@ UNCONSCIOUS
SCR_EForcedWoundedSubmesh
@ FORCED_WOUNDED
@ FORCED_NOT_WOUNDED
ref array< ref LoadoutAreaType > m_aBleedingAreas
EBandagingAnimationBodyParts GetBodyPartToHeal()
override float ComputeEffectiveDamage(notnull BaseDamageContext damageContext, bool isDOT)
SCR_EForcedWoundedSubmesh m_eForcedWoundedSubmesh
ECharacterHitZoneGroup m_eHitZoneGroup
bool m_bIsWounded
float GetDamageMultiplier(EDamageType type)
float GetMaxHealth()
override void OnDamageStateChanged(EDamageState newState, EDamageState previousDamageState, bool isJIP)
override EHitZoneGroup GetHitZoneGroup()
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
enum EVehicleType IEntity
Definition Math.c:13
Blood - does not receive damage directly, only via scripted events.
void RegenVirtualHitZone(SCR_RegeneratingHitZone targetHitZone, float dps=-1, bool skipRegenDelay=false)
float GetArmorProtection(notnull SCR_CharacterHitZone charHitZone, EDamageType damageType)
Get protection value of particular hitZone stored on m_mClothItemDataMap.
void SoundHit(bool critical, EDamageType damageType)
void UpdateCharacterGroupDamage(ECharacterHitZoneGroup hitZoneGroup)
void SoundKnockout()
Tell m_CommunicationSound to stop character from screaming, otherwise ignore.
void AddBloodToClothes(notnull SCR_CharacterHitZone hitZone, float immediateBloodEffect)
health hitzone - Receives damage from physical hitzones
void OnDamageStateChanged(EDamageState newState, EDamageState previousDamageState, bool isJIP)
Called when the damage state changes.
Definition SCR_HitZone.c:60
float CalculatePassiveRegenDPS(bool considerRegenScale=true)
override void OnHealthSet()
HealthSet could have decreased health, so passive regeneration is planned.
void ToggleHitZoneAutoRegenOnHealthSet(bool doRegen)
float GetHitZoneDamageOverTime(EDamageType targetDamageType)
Get current total damage per second of this hitZone.
Definition Types.c:486
IEntity GetOwner()
Owner entity of the fuel tank.
SCR_FieldOfViewSettings Attribute
@ DISABLED
General event switch.
Definition EntityEvent.c:35
EDamageType
Definition EDamageType.c:13
EDamageState