Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_DamageManagerComponent.c
Go to the documentation of this file.
2{
3 [Attribute()]
4 protected ref SCR_SecondaryExplosions m_SecondaryExplosions;
5
6 [Attribute()]
7 protected ref SCR_SecondaryExplosions m_SecondaryFires;
8
9 [Attribute(category: "Repairs")]
11
13
14 //------------------------------------------------------------------------------------------------
15 SCR_SecondaryExplosions GetSecondaryExplosions()
16 {
18 }
19
20 //------------------------------------------------------------------------------------------------
21 SCR_SecondaryExplosions GetSecondaryFires()
22 {
23 return m_SecondaryFires;
24 }
25
26 //------------------------------------------------------------------------------------------------
28 //! \param[in] health percenatage of total health (0.0 to 1.0)
29 //! \param[out] state output that will contain state that coresponds to the provided health or SCR_EBurningState.NONE if there is no such state
30 //! \return true if coresponding state was found
31 bool GetBurnStateForHealth(float health, out SCR_EBurningState state)
32 {
33 if (!m_RepairConfig)
34 {
35 state = SCR_EBurningState.NONE;
36 return false;
37 }
38
39 return m_RepairConfig.GetBurnStateForHealth(health, state);
40 }
41
42 //------------------------------------------------------------------------------------------------
43 //! Retreives a list of ids which are corresponding to the id of the hit zones that are part of the provided group
44 //! \param[in] hitZoneGroup
45 //! \return list of ids, if none are found then null
46 array<int> GetGroupHitZoneIds(EHitZoneGroup hitZoneGroup)
47 {
49 return null;
50
51 return m_mHitZoneGroupMap.Get(hitZoneGroup);
52 }
53
54 //------------------------------------------------------------------------------------------------
57 void InitPrefabData(notnull IEntity owner, notnull SCR_DamageManagerComponent dmgManager)
58 {
60 return; // if it isnt null then we assume that this was already done, thus we quit
61
62 array<HitZone> allHitZones = {};
63 if (dmgManager.GetAllHitZonesInHierarchy(allHitZones) < 1)
64 return; // we have to ignore such entities as PreloadManager can spawn character prefabs on game startup, but they will not have any hit zones. This would result in us having an empty map if we wouldn't quit now
65
67 EHitZoneGroup group;
68 SCR_HitZone scrHitZone;
69 array<int> groupedIds;
70 foreach (int hitZoneId, HitZone hitzone : allHitZones)
71 {
72 scrHitZone = SCR_HitZone.Cast(hitzone);
73 if (!scrHitZone)
74 continue;
75
76 group = scrHitZone.GetHitZoneGroup();
77 groupedIds = m_mHitZoneGroupMap.Get(group);
78 if (groupedIds)
79 groupedIds.Insert(hitZoneId);
80 else
81 groupedIds = {hitZoneId};
82
83 m_mHitZoneGroupMap.Set(group, groupedIds);
84 }
85 }
86}
87
88class SCR_DamageManagerComponent : DamageManagerComponent
89{
90 [Attribute(defvalue: SCR_EBurningState.SMOKING_LIGHT.ToString(), uiwidget: UIWidgets.ComboBox, desc: "State from which vehicle will be considered on fire thus players will be able to extinguish it", enums: ParamEnumArray.FromEnum(SCR_EBurningState))]
91 protected SCR_EBurningState m_iMinimumBurningState;
92
93 protected static const int MIN_MOMENTUM_RESPONSE_INDEX = 1;
94 protected static const int MAX_MOMENTUM_RESPONSE_INDEX = 5;
95 protected static const int MIN_DESTRUCTION_RESPONSE_INDEX = 6;
96 protected const float SIMULATION_IMPRECISION_MULTIPLIER = 1.1;
97 static const int MAX_DESTRUCTION_RESPONSE_INDEX = 10;
98 static const string MAX_DESTRUCTION_RESPONSE_INDEX_NAME = "HugeDestructible";
99 private static int s_iFirstFreeDamageManagerData = -1;
100 protected static ref array<ref SCR_DamageManagerData> s_aDamageManagerData = {};
101
102 static const ref array<EDamageType> HEALING_DAMAGE_TYPES = {EDamageType.HEALING, EDamageType.REGENERATION};
103
104 protected int m_iTimetickInstigator = System.GetTickCount();
105 protected int m_iTimeThresholdInstigatorReplacement = 180000; //180000 miliseconds = 3 minutes
106 protected int m_iPlayerId = 0;
107
108 protected int m_iDamageManagerDataIndex = -1;
109
110
111 //------------------------------------------------------------------------------------------------
113 void GetPhysicalHitZones(out notnull array<HitZone> physicalHitZones)
114 {
115 array<HitZone> hitZones = {};
116 GetAllHitZonesInHierarchy(hitZones);
117
119 foreach (HitZone hitZone : hitZones)
120 {
121 if (hitZone.HasColliderNodes())
122 {
123 physicalHitZones.Insert(hitZone);
124 continue;
125 }
126
127 // Ignore own default hit zone
128 container = hitZone.GetHitZoneContainer();
129 if (container == null || container == this)
130 continue;
131
132 // Allow subordinate default hit zone
133 if (container.GetDefaultHitZone() == hitZone)
134 physicalHitZones.Insert(hitZone);
135 }
136 }
137
138 //------------------------------------------------------------------------------------------------
140 void GetRegeneratingHitZones(out notnull array<SCR_RegeneratingHitZone> regeneratingHitZones)
141 {
142 array<HitZone> hitZones = {};
143 GetAllHitZonesInHierarchy(hitZones);
144
145 foreach (HitZone hitZone : hitZones)
146 {
147 SCR_RegeneratingHitZone regenHitZone = SCR_RegeneratingHitZone.Cast(hitZone);
148 if (regenHitZone)
149 regeneratingHitZones.Insert(regenHitZone);
150 }
151 }
152
153 //---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
154 //------------------------------------------------------------------------------------------------
160 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
161 protected void RpcDo_SetFireState_(int hitZoneIndex, SCR_EBurningState fireState)
162 {
163 array<HitZone> hitZones = {};
164 GetAllHitZones(hitZones);
165 SCR_FlammableHitZone flammableHitZone = SCR_FlammableHitZone.Cast(hitZones.Get(hitZoneIndex));
166 if (flammableHitZone)
167 flammableHitZone.SetFireState(fireState);
168 }
169 void RpcDo_SetFireState(int hitZoneIndex, SCR_EBurningState fireState)
170 {
171 Rpc(RpcDo_SetFireState_, hitZoneIndex, fireState);
172 }
173 //---- REFACTOR NOTE END ----
174
175 //------------------------------------------------------------------------------------------------
177 override bool FilterContact(IEntity owner, IEntity other, Contact contact)
178 {
179 return GetState() != EDamageState.DESTROYED;
180 }
181
182 //------------------------------------------------------------------------------------------------
183 // This method uses similar logic to the logic of DamageSurroundingHitzones, but not the same.
184 int GetSurroundingHitzones(vector origin, Physics physics, float maxDistance, out array<HitZone> outHitzones)
185 {
186 array<HitZone> hitZones = {};
187 outHitzones = {};
188 int hitZonesCount;
189
190 int count = GetAllHitZonesInHierarchy(hitZones);
191 float maxDistanceSq = maxDistance * maxDistance; //SQUARE it for faster calculations of distance
192 array<string> hitZoneColliderNames = {};
193
194 float minDistance, currentDistance;
195 int colliderCount, geomIndex;
196 vector mat[4];
197 for (int i = count - 1; i >= 0; i--)
198 {
199 minDistance = float.MAX;
200 colliderCount = hitZones[i].GetAllColliderNames(hitZoneColliderNames); //The array is cleared inside the GetAllColliderNames method
201
202 if (colliderCount == 0)
203 continue;
204
205 for (int y = colliderCount - 1; y >= 0; y--)
206 {
207 geomIndex = physics.GetGeom(hitZoneColliderNames[y]);
208 if (geomIndex == -1)
209 continue;
210
211 physics.GetGeomWorldTransform(geomIndex, mat);
212 currentDistance = vector.DistanceSq(origin, mat[3]);
213
214 if (currentDistance < minDistance)
215 minDistance = currentDistance;
216 }
217
218 if (minDistance > maxDistanceSq)
219 continue;
220
221 minDistance = Math.Sqrt(minDistance);
222
223 hitZonesCount++;
224 outHitzones.Insert(hitZones[i]);
225 }
226
227 return hitZonesCount;
228 }
229
230 //------------------------------------------------------------------------------------------------
234 */
235 float GetMinDestroyDamage(EDamageType damageType, array<HitZone> hitzones)
236 {
237 if (!IsDamageHandlingEnabled())
238 return -1;
239
240 float damage;
241 float damageMultiplier;
242 HitZone defaultHitzone = GetDefaultHitZone();
243 if (defaultHitzone.GetDamageMultiplier(damageType) * defaultHitzone.GetBaseDamageMultiplier() == 0)
244 return -1; // invalid damage value, because this vehicle cannot be destroyed
245
246 foreach (HitZone hitZone : hitzones)
247 {
248 damageMultiplier = hitZone.GetBaseDamageMultiplier() * hitZone.GetDamageMultiplier(damageType);
249 if (damageMultiplier == 0)
250 continue;
251
252 damage += (hitZone.GetMaxHealth() + hitZone.GetDamageReduction()) / damageMultiplier;
253
254 if (damage < hitZone.GetDamageThreshold())
255 damage += hitZone.GetDamageThreshold();
256 }
257
258 return damage;
259 }
260
261 //------------------------------------------------------------------------------------------------
263 {
265 m_iDamageManagerDataIndex = AllocateScriptedDamageManagerData();
266
267 return s_aDamageManagerData[m_iDamageManagerDataIndex];
268 }
269
270 //------------------------------------------------------------------------------------------------
271 private int AllocateScriptedDamageManagerData()
272 {
273 if (s_iFirstFreeDamageManagerData == -1)
274 return s_aDamageManagerData.Insert(new SCR_DamageManagerData());
275 else
276 {
277 int returnIndex = s_iFirstFreeDamageManagerData;
278 SCR_DamageManagerData data = s_aDamageManagerData[returnIndex];
279 s_iFirstFreeDamageManagerData = data.m_iNextFreeIndex;
280 data.m_iNextFreeIndex = -1;
281 return returnIndex;
282 }
283 }
284
285 //------------------------------------------------------------------------------------------------
286 private void FreeScriptedDamageManagerData(int index)
287 {
288 s_aDamageManagerData[index].Reset();
289 s_aDamageManagerData[index].m_iNextFreeIndex = s_iFirstFreeDamageManagerData;
290 s_iFirstFreeDamageManagerData = index;
291 }
292
293 //------------------------------------------------------------------------------------------------
294 ScriptInvoker GetOnDamage()
295 {
297 }
298 //------------------------------------------------------------------------------------------------
299 ScriptInvoker GetOnDamageOverTimeAdded()
300 {
302 }
303
304 //------------------------------------------------------------------------------------------------
305 ScriptInvoker GetOnDamageOverTimeRemoved()
306 {
308 }
309
310 //------------------------------------------------------------------------------------------------
311 ScriptInvoker GetOnDamageStateChanged()
312 {
314 }
315
316 //------------------------------------------------------------------------------------------------
317 override protected void OnDamage(notnull BaseDamageContext damageContext)
318 {
319 if (!s_aDamageManagerData.IsIndexValid(m_iDamageManagerDataIndex))
320 return;
321
322 ScriptInvoker invoker = s_aDamageManagerData[m_iDamageManagerDataIndex].GetOnDamage(false);
323 if (invoker)
324 invoker.Invoke(damageContext);
325 }
326
327 //---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
328 // TODO: Move to Character Damage Manager, use simplified instigator tracking for everything else
329 //------------------------------------------------------------------------------------------------
336 protected override bool ShouldOverrideInstigator(notnull Instigator currentInstigator, notnull Instigator newInstigator)
337 {
338 //If time difference since last instigator set is small, this kill was a suicide, and the previous instigator was an enemy, do not override
339 int currentTimeTick = System.GetTickCount();
340
341 if (m_iPlayerId == 0)
342 {
343 m_iPlayerId = GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(GetOwner());
344 }
345
346 SCR_FactionManager factionManager = SCR_FactionManager.Cast(GetGame().GetFactionManager());
347 if (m_iPlayerId <= 0 || !factionManager)
348 {
349 m_iTimetickInstigator = currentTimeTick;
350 return true;
351 }
352
353 int newId = newInstigator.GetInstigatorPlayerID();
354 int oldId = currentInstigator.GetInstigatorPlayerID();
355
356 Faction factionKiller = factionManager.GetPlayerFaction(newId);
357 if (!factionKiller)
358 {
359 m_iTimetickInstigator = currentTimeTick;
360 return true;
361 }
362
363 Faction factionPrevInstigator = factionManager.GetPlayerFaction(oldId);
364 if (!factionPrevInstigator)
365 {
366 m_iTimetickInstigator = currentTimeTick;
367 return true;
368 }
369 Faction factionPlayer = factionManager.GetPlayerFaction(m_iPlayerId);
370 if (!factionPlayer)
371 {
372 m_iTimetickInstigator = currentTimeTick;
373 return true;
374 }
375
376 if (newId == m_iPlayerId && (currentTimeTick - m_iTimetickInstigator) < m_iTimeThresholdInstigatorReplacement && !factionPrevInstigator.IsFactionFriendly(factionPlayer))
377 {
378 return false;
379 }
380
381 m_iTimetickInstigator = currentTimeTick;
382 return true;
383 }
384 //---- REFACTOR NOTE END ----
385
386 //------------------------------------------------------------------------------------------------
388 {
390 FreeScriptedDamageManagerData(m_iDamageManagerDataIndex);
391 }
392
393 //------------------------------------------------------------------------------------------------
399 static SCR_DamageManagerComponent GetDamageManager(notnull IEntity owner)
400 {
401 ChimeraCharacter character = ChimeraCharacter.Cast(owner);
402 if (character)
403 return character.GetDamageManager();
404
405 BaseVehicle vehicle = BaseVehicle.Cast(owner);
406 if (vehicle)
407 return vehicle.GetDamageManager();
408
409 return SCR_DamageManagerComponent.Cast(owner.FindComponent(SCR_DamageManagerComponent));
410 }
411
412 //------------------------------------------------------------------------------------------------
418 int GetHitZonesOfGroup(EHitZoneGroup hitZoneGroup, out notnull array<HitZone> groupHitZones, bool clearArray = true)
419 {
420 if (clearArray)
421 groupHitZones.Clear();
422
423 array<HitZone> allHitZones = {};
424 GetAllHitZonesInHierarchy(allHitZones);
425 SCR_HitZone scrHitZone;
426
427 foreach (HitZone hitZone : allHitZones)
428 {
429 scrHitZone = SCR_HitZone.Cast(hitZone);
430 if (scrHitZone && scrHitZone.GetHitZoneGroup() == hitZoneGroup)
431 groupHitZones.Insert(hitZone);
432 }
433
434 return groupHitZones.Count();
435 }
436
437 //------------------------------------------------------------------------------------------------
443 int GetHitZonesOfGroupFromOwner(EHitZoneGroup hitZoneGroup, out notnull array<HitZone> groupHitZones, bool clearArray = true)
444 {
445 if (clearArray)
446 groupHitZones.Clear();
447
449 array<int> groupedHitZoneIds = data.GetGroupHitZoneIds(hitZoneGroup);
450 if (!groupedHitZoneIds)
451 return -1;
452
453 GetHitZonesByID(groupHitZones, groupedHitZoneIds);
454
455 return groupHitZones.Count();
456 }
457
458 //------------------------------------------------------------------------------------------------
463 int GetHitZonesOfGroups(notnull array<EHitZoneGroup> hitZoneGroups, out notnull array<HitZone> groupHitZones)
464 {
465 groupHitZones.Clear();
466
467 if (hitZoneGroups.IsEmpty())
468 return 0;
469
470 array<HitZone> allHitZones = {};
471 GetAllHitZonesInHierarchy(allHitZones);
472 SCR_HitZone scrHitZone;
473
474 foreach (HitZone hitZone : allHitZones)
475 {
476 scrHitZone = SCR_HitZone.Cast(hitZone);
477 if (scrHitZone && hitZoneGroups.Contains(scrHitZone.GetHitZoneGroup()))
478 groupHitZones.Insert(hitZone);
479 }
480
481 return groupHitZones.Count();
482 }
483
484 //------------------------------------------------------------------------------------------------
489 int GetHitZonesOfGroupsFromOwner(notnull array<EHitZoneGroup> hitZoneGroups, out notnull array<HitZone> groupHitZones)
490 {
491 groupHitZones.Clear();
492
493 if (hitZoneGroups.IsEmpty())
494 return 0;
495
497 array<EHitZoneGroup> groupedHitZoneIds = {};
498 array<EHitZoneGroup> individualHitZoneGroupIds;
499 foreach (EHitZoneGroup hitZoneGroup : hitZoneGroups)
500 {
501 individualHitZoneGroupIds = data.GetGroupHitZoneIds(hitZoneGroup);
502 if (individualHitZoneGroupIds)
503 groupedHitZoneIds.InsertAll(individualHitZoneGroupIds);
504 }
505
506 GetHitZonesByID(groupHitZones, groupedHitZoneIds);
507
508 return groupHitZones.Count();
509 }
510
511 //------------------------------------------------------------------------------------------------
519 {
520 float totalGroupDamage;
521 array<HitZone> groupedHitZones = {};
522 GetHitZonesOfGroup(hitZoneGroup, groupedHitZones);
523
524 foreach (HitZone hitzone : groupedHitZones)
525 {
526 totalGroupDamage += hitzone.GetDamageOverTime(damageType);
527 }
528
529 return totalGroupDamage;
530 }
531
532 //------------------------------------------------------------------------------------------------
536 void Kill(notnull Instigator instigator)
537 {
538 IEntity owner = GetOwner();
539 if (!owner)
540 return;
541
542 vector hitPosDirNorm[3];
543
544 HitZone hitZone = GetDefaultHitZone();
545 SCR_DamageContext damageContext = new SCR_DamageContext(EDamageType.TRUE, hitZone.GetMaxHealth(), hitPosDirNorm, owner, hitZone, instigator, null, -1, -1);
546 if (instigator.GetInstigatorType() == InstigatorType.INSTIGATOR_GM)
547 damageContext.damageEffect = new SCR_GameMasterActionDamageEffect();
548
549 HandleDamage(damageContext);
550 }
551
552 //------------------------------------------------------------------------------------------------
562 void DamageRandomHitZones(float damage, EDamageType type, notnull Instigator instigator, bool onlyPhysical = true, vector outMat[3] = {}, bool damageDefault = false)
563 {
564 array<HitZone> hitZones = {};
565
566 if (onlyPhysical)
567 GetPhysicalHitZones(hitZones);
568 else
569 GetAllHitZonesInHierarchy(hitZones);
570
571 if (!damageDefault)
572 hitZones.RemoveItem(GetDefaultHitZone());
573
574 HitZone hitZone;
575 DamageManagerComponent damageManager;
576 float hitZoneDamage;
577
578 while (damage > 0 && !hitZones.IsEmpty())
579 {
580 hitZone = hitZones.GetRandomElement();
581 if (!hitZone)
582 {
583 hitZones.RemoveItem(hitZone);
584 continue;
585 }
586
587 damageManager = DamageManagerComponent.Cast(hitZone.GetHitZoneContainer());
588 if (!damageManager)
589 {
590 hitZones.RemoveItem(hitZone);
591 continue;
592 }
593
594 // Check actual damage that will be dealt
595 SCR_DamageContext hitZoneContext = new SCR_DamageContext(type, damage, outMat, damageManager.GetOwner(), hitZone, instigator, null, -1, -1);
596 hitZoneDamage = Math.Min(hitZone.ComputeEffectiveDamage(hitZoneContext, false), hitZone.GetHealth());
597
598 // Remove hit zones that cannot be damaged with this loop
599 if (hitZoneDamage <= 0 || float.AlmostEqual(hitZoneDamage, 0))
600 {
601 hitZones.RemoveItem(hitZone);
602 continue;
603 }
604
605 //damage is the remaining amount of damage to split between future hit zones
606 damage -= hitZoneDamage;
607
608 damageManager.HandleDamage(hitZoneContext);
609 }
610 }
611
612 //------------------------------------------------------------------------------------------------
615 bool CanBeHealed(bool ignoreHealingDOT = true)
616 {
617 // Any damage to default hitzone
618 if (GetDefaultHitZone().GetDamageState() == EDamageState.UNDAMAGED)
619 return true;
620
621 // Check if has damage over time
622 array<EDamageType> damageTypes = {};
623 SCR_Enum.GetEnumValues(EDamageType, damageTypes);
624
625 foreach (EDamageType type : damageTypes)
626 {
627 if (!ignoreHealingDOT && HEALING_DAMAGE_TYPES.Contains(type))
628 continue;
629
630 if (IsDamagedOverTime(type))
631 return true;
632 }
633
634 // No need to check fire on characters
635 if (SCR_ChimeraCharacter.Cast(GetOwner()))
636 return false;
637
638 // Check if any hitzone is damaged
639 array<HitZone> hitZones = {};
640 GetAllHitZonesInHierarchy(hitZones);
641 SCR_FlammableHitZone flammableHitZone;
642 foreach (HitZone hitZone : hitZones)
643 {
644 if (hitZone && hitZone.GetDamageState() != EDamageState.UNDAMAGED)
645 return true;
646
647 // Flammable hitzone may be smoking
648 flammableHitZone = SCR_FlammableHitZone.Cast(hitZone);
649 if (flammableHitZone && IsOnFire(flammableHitZone))
650 return true;
651 }
652
653 return false;
654 }
655
656 //------------------------------------------------------------------------------------------------
658 void FullHeal(bool ignoreHealingDOT = true)
659 {
660 array<HitZone> hitZones = {};
661 GetAllHitZonesInHierarchy(hitZones);
662
663 // Extinguish flammable hitzones
664 SCR_FlammableHitZone flammableHitZone;
665 foreach (HitZone hitZone : hitZones)
666 {
667 // Put out fire and smoke
668 flammableHitZone = SCR_FlammableHitZone.Cast(hitZone);
669 if (flammableHitZone)
670 flammableHitZone.SetFireRate(0);
671 }
672
673 // Heal remaining damage over time
674 array<EDamageType> damageTypes = {};
675 SCR_Enum.GetEnumValues(EDamageType, damageTypes);
676
677 foreach (EDamageType type : damageTypes)
678 {
679 // Prevent removing of healing DOTs so morphine and saline effects aren't stopped by healing action
680 if (ignoreHealingDOT && (type == EDamageType.REGENERATION || type == EDamageType.HEALING))
681 continue;
682
683 if (IsDamagedOverTime(type))
684 RemoveDamageOverTime(type);
685 }
686
687 // Fix hitzones
688 foreach (HitZone hitZone : hitZones)
689 {
690 if (hitZone && hitZone.GetDamageState() != EDamageState.UNDAMAGED)
691 hitZone.SetHealthScaled(1);
692 }
693 }
694
695 //------------------------------------------------------------------------------------------------
702 float HealHitZones(float healthToDistribute, bool sequential = false, float maxHealThresholdScaled = 1, array<HitZone> alternativeHitZones = null)
703 {
704 if (healthToDistribute <= 0)
705 return healthToDistribute;
706
707 if (maxHealThresholdScaled < 0 || maxHealThresholdScaled > 1)
708 maxHealThresholdScaled = 1;
709
710 array<HitZone> targetHitZones = {};
711 if (alternativeHitZones)
712 targetHitZones.Copy(alternativeHitZones);
713 else
714 GetPhysicalHitZones(targetHitZones);
715
716 if (sequential)
717 healthToDistribute = HealHitZonesInSequence(healthToDistribute, maxHealThresholdScaled, targetHitZones);
718 else // if in Parallel
719 healthToDistribute = HealHitZonesInParallel(healthToDistribute, maxHealThresholdScaled, targetHitZones);
720
721 ReduceSmoke();
722 return healthToDistribute;
723 }
724
725 //------------------------------------------------------------------------------------------------
726 protected float HealHitZonesInSequence(float healthToDistribute, float maxHealThresholdScaled, array<HitZone> targetHitZones)
727 {
728 foreach (HitZone hitZone : targetHitZones)
729 {
730 if (healthToDistribute <= 0)
731 break;
732
733 // If hitzone is undamaged, go onto the next one
734 float healthToAdd = (hitZone.GetMaxHealth() * maxHealThresholdScaled) - hitZone.GetHealth();
735 if (healthToAdd <= 0)
736 continue;
737
738 // If health to distribute runs out, heal hitzone with whats left and exit
739 if (healthToAdd > healthToDistribute)
740 {
741 hitZone.HandleDamage(-healthToDistribute, EDamageType.HEALING, null);
742 healthToDistribute = 0;
743 break;
744 }
745
746 // Heal hitZone and substract distributable health value
747 hitZone.HandleDamage(-healthToAdd, EDamageType.HEALING, null);
748 healthToDistribute -= healthToAdd;
749 }
750
751 return healthToDistribute;
752 }
753
754 //------------------------------------------------------------------------------------------------
755 protected float HealHitZonesInParallel(float healthToDistribute, float maxHealThresholdScaled, array<HitZone> targetHitZones)
756 {
757 array<HitZone> damagedHitZones = {};
758
759 while (healthToDistribute > 0)
760 {
761 foreach (HitZone hitZone : targetHitZones)
762 {
763 if (hitZone.GetHealth() < (hitZone.GetMaxHealth() * maxHealThresholdScaled))
764 damagedHitZones.Insert(hitZone);
765 }
766
767 if (damagedHitZones.IsEmpty())
768 break;
769
770 float healthToDistributeHitZone = healthToDistribute / damagedHitZones.Count();
771 foreach (HitZone hitZone : damagedHitZones)
772 {
773 if (healthToDistribute <= 0)
774 break;
775
776 // If hitzone is undamaged, go onto the next one
777 float healthToAdd = (hitZone.GetMaxHealth() * maxHealThresholdScaled) - hitZone.GetHealth();
778 if (healthToAdd <= 0)
779 continue;
780
781 // If health to distribute is more than needed, apply what's needed and save whats' left
782 if (healthToDistributeHitZone > healthToAdd)
783 {
784 hitZone.HandleDamage(-healthToAdd, EDamageType.HEALING, null);
785 healthToDistribute -= healthToAdd;
786 continue;
787 }
788 else// If health to distribute is less than needed, reduce healthToDistribute by health applied and continue
789 {
790 hitZone.HandleDamage(-healthToDistributeHitZone, EDamageType.HEALING, null);
791 healthToDistribute -= healthToDistributeHitZone;
792 continue;
793 }
794 }
795
796 damagedHitZones.Clear();
797 }
798
799 return healthToDistribute;
800 }
801
802 //------------------------------------------------------------------------------------------------
805 {
806 if (IsOnFire())
807 return;
808
810 if (!prefabData)
811 return;
812
813 HitZone defaultHZ = GetDefaultHitZone();
814
815 array<HitZone> hitZones = {};
816 GetAllHitZones(hitZones);
817
818 float averageHP;
819 int numberOfValidHZ;
820 foreach (HitZone hz : hitZones)
821 {
822 if (hz == defaultHZ)
823 continue;
824
825 numberOfValidHZ++;
826 averageHP += hz.GetHealthScaled();
827 }
828
829 if (numberOfValidHZ > 0)
830 {
831 averageHP /= numberOfValidHZ;
832 if (averageHP > defaultHZ.GetHealthScaled())
833 averageHP = defaultHZ.GetHealthScaled();
834 }
835 else
836 {
837 averageHP = defaultHZ.GetHealthScaled();
838 }
839
840 SCR_EBurningState desiredState;
841 if (!prefabData.GetBurnStateForHealth(averageHP, desiredState))
842 return;
843
844 SCR_FlammableHitZone flammableHZ;
845 foreach (HitZone hz : hitZones)
846 {
847 flammableHZ = SCR_FlammableHitZone.Cast(hz);
848 if (!flammableHZ)
849 continue;
850
851 //make sure that we are not going to make it worse than it is now
852 if (flammableHZ.GetFireState() <= desiredState)
853 continue;
854
855 flammableHZ.SetFireState(desiredState);
856 }
857 }
858
859 //------------------------------------------------------------------------------------------------
864 float GetHitZonesDamage(float untilThresholdScaled = 1, array<HitZone> alternativeHitZones = null)
865 {
866 array<HitZone> hitZones = {};
867 if (!alternativeHitZones || alternativeHitZones.IsEmpty())
868 GetPhysicalHitZones(hitZones);
869 else
870 hitZones.Copy(alternativeHitZones);
871
872 if (!hitZones)
873 return 0;
874
875 float totalDamage, addedDamage;
876
877 foreach (HitZone hitZone : hitZones)
878 {
879 //~ Ignore undamaged
880 if (hitZone.GetDamageState() == EDamageState.UNDAMAGED)
881 continue;
882
883 addedDamage = (hitZone.GetMaxHealth() * untilThresholdScaled) - hitZone.GetHealth();
884 if (addedDamage > 0)
885 totalDamage += addedDamage;
886 }
887
888 return totalDamage;
889 }
890
891 //------------------------------------------------------------------------------------------------
895 float GetHitZonesHealthScaled(array<HitZone> alternativeHitZones = null)
896 {
897 array<HitZone> hitZones = {};
898 if (!alternativeHitZones || alternativeHitZones.IsEmpty())
899 GetPhysicalHitZones(hitZones);
900 else
901 hitZones.Copy(alternativeHitZones);
902
903 //~ No hitzones so health is full
904 if (!hitZones || hitZones.IsEmpty())
905 return 1;
906
907 float totalHealthScaled;
908
909 foreach (HitZone hitZone : hitZones)
910 {
911 if (hitZone.GetDamageState() == EDamageState.UNDAMAGED)
912 {
913 totalHealthScaled += 1;
914 continue;
915 }
916
917 totalHealthScaled += hitZone.GetHealthScaled();
918 }
919
920 return totalHealthScaled / hitZones.Count();
921 }
922
923 //------------------------------------------------------------------------------------------------
928 float GetSingleHitZonesHealthScaled(array<HitZone> alternativeHitZones = null, bool getLowestHealth = true)
929 {
930 array<HitZone> hitZones = {};
931 if (!alternativeHitZones || alternativeHitZones.IsEmpty())
932 GetPhysicalHitZones(hitZones);
933 else
934 hitZones.Copy(alternativeHitZones);
935
936 //~ No hitzones so health is full
937 if (!hitZones || hitZones.IsEmpty())
938 return 1;
939
940 float returnValue = -1;
941 float healthScaled;
942
943 foreach (HitZone hitZone : hitZones)
944 {
945 if (returnValue < 0)
946 {
947 if (hitZone.GetDamageState() == EDamageState.UNDAMAGED)
948 returnValue = 1;
949 else
950 returnValue = hitZone.GetHealthScaled();
951
952 continue;
953 }
954
955 if (hitZone.GetDamageState() == EDamageState.UNDAMAGED)
956 healthScaled = 1;
957 else
958 healthScaled = hitZone.GetHealthScaled();
959
960 if ((getLowestHealth && returnValue > healthScaled) || (!getLowestHealth && returnValue < healthScaled))
961 returnValue = healthScaled;
962 }
963
964 return returnValue;
965 }
966
967 //------------------------------------------------------------------------------------------------
969 ResourceName GetSecondaryExplosion(float value, SCR_ESecondaryExplosionType explosionType, EResourceType resourceType = EResourceType.SUPPLIES, bool fire = false, out bool hasData = false)
970 {
972 if (!prefabData)
973 return ResourceName.Empty;
974
975 SCR_SecondaryExplosions secondaries;
976 if (fire)
977 secondaries = prefabData.GetSecondaryFires();
978 else
979 secondaries = prefabData.GetSecondaryExplosions();
980
981 if (!secondaries)
982 return ResourceName.Empty;
983
984 hasData = true;
985 return secondaries.GetExplosionPrefab(value, explosionType, resourceType);
986 }
987
988 //------------------------------------------------------------------------------------------------
990 SCR_SecondaryExplosion GetSecondaryExplosionForScale(SCR_ESecondaryExplosionScale scale, SCR_ESecondaryExplosionType explosionType, EResourceType resourceType = EResourceType.SUPPLIES)
991 {
993 if (!prefabData)
994 return null;
995
996 SCR_SecondaryExplosions secondaries = prefabData.GetSecondaryFires();
997 if (!secondaries)
998 return null;
999
1000 return secondaries.GetSecondaryExplosionForScale(scale, explosionType, resourceType);
1001 }
1002
1003 //------------------------------------------------------------------------------------------------
1005 SCR_ESecondaryExplosionScale GetSecondaryExplosionScale(float value, SCR_ESecondaryExplosionType explosionType, EResourceType resourceType = EResourceType.SUPPLIES)
1006 {
1008 if (!prefabData)
1009 return SCR_ESecondaryExplosionScale.NONE;
1010
1011 SCR_SecondaryExplosions secondaries = prefabData.GetSecondaryFires();
1012 if (!secondaries)
1013 return SCR_ESecondaryExplosionScale.NONE;
1014
1015 return secondaries.GetSecondaryExplosionScale(value, explosionType, resourceType);
1016 }
1017
1018 //------------------------------------------------------------------------------------------------
1021 {
1023 if (!prefabData)
1024 return ResourceName.Empty;
1025
1026 SCR_SecondaryExplosions secondaries = prefabData.GetSecondaryFires();
1027 if (!secondaries)
1028 return ResourceName.Empty;
1029
1030 return secondaries.GetFireParticles(value, explosionType, resourceType);
1031 }
1032
1033 //------------------------------------------------------------------------------------------------
1036 bool IsOnFire(HitZone hitZone = null)
1037 {
1038 if (!hitZone)
1039 return IsOnFire(new array<HitZone>);
1040
1041 SCR_FlammableHitZone flammableHZ = SCR_FlammableHitZone.Cast(hitZone);
1042 if (!flammableHZ)
1043 return false;
1044
1045 return flammableHZ.GetFireState() >= m_iMinimumBurningState;
1046 }
1047
1048 //------------------------------------------------------------------------------------------------
1051 bool IsOnFire(notnull array<HitZone> hitZones)
1052 {
1053 if (hitZones.IsEmpty())
1054 {
1055 GetAllHitZones(hitZones);
1056 if (hitZones.IsEmpty())
1057 return false;
1058 }
1059
1060 SCR_FlammableHitZone flammableHZ;
1061 foreach (HitZone hz : hitZones)
1062 {
1063 flammableHZ = SCR_FlammableHitZone.Cast(hz);
1064 if (!flammableHZ)
1065 continue;
1066
1067 if (flammableHZ.GetFireState() >= m_iMinimumBurningState)
1068 return true;
1069 }
1070
1071 return false;
1072 }
1073
1074 //------------------------------------------------------------------------------------------------
1076 void SecondaryExplosion(ResourceName prefabName, notnull Instigator instigator, notnull EntitySpawnParams spawnParams)
1077 {
1078 if (GetDefaultHitZone() && GetDefaultHitZone().IsProxy())
1079 return;
1080
1081 Resource secondaryResource = Resource.Load(prefabName);
1082 if (!secondaryResource.IsValid())
1083 return;
1084
1085 if (!spawnParams.Parent)
1086 spawnParams.Parent = GetOwner();
1087
1088 IEntity explosion = GetGame().SpawnEntityPrefab(secondaryResource, spawnParams.Parent.GetWorld(), spawnParams);
1089 if (!explosion)
1090 return;
1091
1092 // Set instigator on trigger component
1094 if (!trigger)
1095 return;
1096
1097 trigger.SetInstigator(GetInstigator());
1098 // Ignore own vehicle
1099 array<IEntity> ignoreList = {GetOwner().GetRootParent()};
1100
1101 // Ignore all hierarchy members as well
1102 SCR_EntityHelper.GetHierarchyEntityList(GetOwner().GetRootParent(), ignoreList);
1103
1104 // Remove possible character entites from ignorelist
1105 SCR_BaseCompartmentManagerComponent baseCompartment = SCR_BaseCompartmentManagerComponent.Cast(GetOwner().FindComponent(SCR_BaseCompartmentManagerComponent));
1106 if (baseCompartment)
1107 {
1108 array<IEntity> vehicleOccupants = {};
1109 baseCompartment.GetOccupants(vehicleOccupants);
1110 foreach (IEntity entity : vehicleOccupants)
1111 {
1112 ignoreList.RemoveItem(entity);
1113 }
1114 }
1115
1116 array<BaseProjectileEffect> explosionContainers = {};
1117 trigger.GetProjectileEffects(ExplosionDamageContainer, explosionContainers);
1118 foreach (BaseProjectileEffect effect : explosionContainers)
1119 {
1120 ExplosionDamageContainer.Cast(effect).SetIgnoreList(ignoreList);
1121 }
1122 }
1123
1124 //------------------------------------------------------------------------------------------------
1126 {
1127 IEntity owner = GetOwner();
1128 if (!owner)
1129 return null;
1130
1131 SCR_ResourceComponent resourceComponent = SCR_ResourceComponent.FindResourceComponent(owner);
1132 if (!resourceComponent)
1133 return null;
1134
1135 SCR_ResourceContainer container = resourceComponent.GetContainer(suppliesType);
1136 if (!container)
1137 return null;
1138
1139 return container.GetResourceEncapsulator();
1140 }
1141
1142 //------------------------------------------------------------------------------------------------
1144 void SupplySecondaryExplosion(notnull Instigator instigator)
1145 {
1147 if (!encapsulator)
1148 return;
1149
1150 // First check, if there are any supplies at all
1151 // If there is no explosion, then do not spend time trying to figure out where it should be originated from
1152 float resourceValue = encapsulator.GetAggregatedResourceValue();
1153 if (resourceValue <= 0)
1154 return;
1155
1156 IEntity owner = encapsulator.GetOwner();
1157 if (!owner)
1158 owner = GetOwner();
1159
1160 if (!owner)
1161 return;
1162
1163 bool hasData;
1164 ResourceName secondaryExplosionPrefab = GetSecondaryExplosion(resourceValue, SCR_ESecondaryExplosionType.RESOURCE, EResourceType.SUPPLIES, false, hasData);
1165 if (!hasData)
1166 return;
1167
1168 SCR_ResourceContainerQueueBase containerQueue = encapsulator.GetContainerQueue();
1169 int containerCount = encapsulator.GetContainerCount();
1170 SCR_ResourceContainer container;
1171 EntitySpawnParams spawnParams = new EntitySpawnParams();
1172
1173 // Get the weighed average position of explosion relative to encapsulator
1174 // Only calculate if we actually have an explosion to spawn
1175 if (!secondaryExplosionPrefab.IsEmpty())
1176 {
1177 float weight;
1179 vector averagePosition = owner.CoordToLocal(encapsulator.GetOwnerOrigin());
1180 spawnParams.Parent = owner;
1181
1182 for (int i; i < containerCount; i++)
1183 {
1184 container = containerQueue.GetContainerAt(i);
1185 if (!container)
1186 continue;
1187
1188 // Determine secondary explosion position
1189 weight = container.GetResourceValue() / resourceValue;
1190 if (weight <= 0)
1191 continue;
1192
1193 position = owner.CoordToLocal(container.GetOwnerOrigin());
1194 averagePosition += position * weight;
1195 }
1196 spawnParams.Transform[3] = averagePosition;
1197 }
1198
1199
1200 // Destroy the resources and deny further use
1201 for (int i; i < containerCount; i++)
1202 {
1203 container = containerQueue.GetContainerAt(i);
1204 if (!container)
1205 continue;
1206
1207 container.SetResourceValue(0);
1208 container.SetResourceRights(EResourceRights.NONE);
1209 }
1210
1211 // Spawn explosion if prefab is available
1212 if (!secondaryExplosionPrefab.IsEmpty())
1213 SecondaryExplosion(secondaryExplosionPrefab, instigator, spawnParams);
1214 }
1215
1216 //------------------------------------------------------------------------------------------------
1218 vector GetSecondaryExplosionPosition(typename hitZoneType, out float totalWeight = 0)
1219 {
1220 IEntity owner = GetOwner();
1221 if (!owner)
1222 return vector.Zero;
1223
1224 array<HitZone> hitZones = {};
1225 GetAllHitZonesInHierarchy(hitZones);
1226 SCR_DestructibleHitzone destructibleHitZone;
1227 PointInfo explosionPoint;
1229 vector weighedAveragePosition;
1230 vector averagePosition;
1231 Physics physics = owner.GetPhysics();
1232 float weight;
1233 int validHitZones;
1234
1235 // Get weighed average position of fuel tanks if defined in their hitzones
1236 foreach (HitZone hitZone : hitZones)
1237 {
1238 destructibleHitZone = SCR_DestructibleHitzone.Cast(hitZone);
1239 if (!destructibleHitZone || !destructibleHitZone.Type().IsInherited(hitZoneType))
1240 continue;
1241
1242 explosionPoint = destructibleHitZone.GetSecondaryExplosionPoint();
1243 if (!explosionPoint && destructibleHitZone != GetDefaultHitZone())
1244 continue;
1245
1246 if (explosionPoint)
1247 position = owner.CoordToLocal(explosionPoint.GetWorldTransformAxis(3));
1248 else if (physics)
1249 position = physics.GetCenterOfMass();
1250
1251 validHitZones++;
1252 averagePosition += position;
1253 weight = destructibleHitZone.GetSecondaryExplosionScale();
1254 if (weight < 0 || float.AlmostEqual(weight, 0))
1255 continue;
1256
1257 weighedAveragePosition += position * weight;
1258 totalWeight += weight;
1259 }
1260
1261 if (totalWeight > 0)
1262 return weighedAveragePosition / totalWeight;
1263 else if (validHitZones > 0)
1264 return averagePosition / validHitZones;
1265 else if (physics)
1266 return physics.GetCenterOfMass();
1267
1268 return vector.Zero;
1269 }
1270
1271 //------------------------------------------------------------------------------------------------
1273 void FuelSecondaryExplosion(notnull Instigator instigator)
1274 {
1275 float totalFuel;
1276 vector explosionPosition = GetSecondaryExplosionPosition(SCR_FuelHitZone, totalFuel);
1277 EntitySpawnParams spawnParams = new EntitySpawnParams();
1278 spawnParams.Transform[3] = explosionPosition;
1279 ResourceName secondaryExplosionPrefab = GetSecondaryExplosion(totalFuel, SCR_ESecondaryExplosionType.FUEL);
1280 SecondaryExplosion(secondaryExplosionPrefab, instigator, spawnParams);
1281 }
1282
1283 //------------------------------------------------------------------------------------------------
1284 void UpdateFireDamage(float timeSlice);
1285
1286 //------------------------------------------------------------------------------------------------
1293 void UpdateFireParticles(vector position, out ParticleEffectEntity particles, SCR_ESecondaryExplosionScale state, SCR_ESecondaryExplosionType fireType, EResourceType resourceType = EResourceType.SUPPLIES)
1294 {
1295 if (particles)
1296 {
1298 particles = null;
1299 }
1300
1301 SCR_SecondaryExplosion secondaryFire = GetSecondaryExplosionForScale(state, fireType, resourceType);
1302 if (!secondaryFire)
1303 return;
1304
1305 ResourceName fireParticles = secondaryFire.m_sSecondaryFireParticles;
1306 if (fireParticles.IsEmpty())
1307 return;
1308
1310 params.FollowParent = GetOwner();
1311 params.Transform[3] = position;
1312 params.PlayOnSpawn = true;
1313 params.DeleteWhenStopped = true;
1314 params.UseFrameEvent = true;
1315
1316 particles = ParticleEffectEntity.SpawnParticleEffect(fireParticles, params);
1317 }
1318
1319 //------------------------------------------------------------------------------------------------
1321 {
1322 World world = GetOwner().GetWorld();
1323 FireDamageSystem system = FireDamageSystem.Cast(world.FindSystem(FireDamageSystem));
1324 if (system)
1325 system.Register(this);
1326 }
1327
1328 //------------------------------------------------------------------------------------------------
1330 {
1331 World world = GetOwner().GetWorld();
1332 FireDamageSystem system = FireDamageSystem.Cast(world.FindSystem(FireDamageSystem));
1333 if (system)
1334 system.Unregister(this);
1335 }
1336
1337 //------------------------------------------------------------------------------------------------
1339 protected override void OnDamageStateChanged(EDamageState newState, EDamageState previousDamageState, bool isJIP)
1340 {
1341 super.OnDamageStateChanged(newState, previousDamageState, isJIP);
1342
1343 if (m_iDamageManagerDataIndex != -1)
1344 {
1345 ScriptInvoker invoker = s_aDamageManagerData[m_iDamageManagerDataIndex].GetOnDamageStateChanged(false);
1346 if (invoker)
1347 invoker.Invoke(newState);
1348 }
1349
1350 // Only main hitzone can explode supplies
1351 if (newState == EDamageState.DESTROYED)
1352 {
1353 Instigator instigator = GetInstigator();
1354 SupplySecondaryExplosion(instigator);
1355 FuelSecondaryExplosion(instigator);
1356 }
1357 }
1358
1359 //------------------------------------------------------------------------------------------------
1363 override void OnDamageOverTimeAdded(EDamageType dType, float dps, HitZone hz)
1364 {
1365 super.OnDamageOverTimeAdded(dType, dps, hz);
1366
1367 if (m_iDamageManagerDataIndex != -1)
1368 {
1369 ScriptInvoker invoker = s_aDamageManagerData[m_iDamageManagerDataIndex].GetOnDamageOverTimeAdded(false);
1370 if (invoker)
1371 invoker.Invoke(dType, dps, hz);
1372 }
1373
1374 RplComponent rpl = RplComponent.Cast(GetOwner().FindComponent(RplComponent));
1375 if (rpl && rpl.IsProxy())
1376 return;
1377
1378 if (dType == EDamageType.FIRE)
1380 }
1381
1382 //------------------------------------------------------------------------------------------------
1387 {
1388 super.OnDamageOverTimeRemoved(dType, hz);
1389
1390 if (m_iDamageManagerDataIndex != -1)
1391 {
1392 ScriptInvoker invoker = s_aDamageManagerData[m_iDamageManagerDataIndex].GetOnDamageOverTimeRemoved(false);
1393 if (invoker)
1394 invoker.Invoke(dType, hz);
1395 }
1396
1397 RplComponent rpl = RplComponent.Cast(GetOwner().FindComponent(RplComponent));
1398 if (rpl && rpl.IsProxy())
1399 return;
1400
1401 if (dType == EDamageType.FIRE && !IsDamagedOverTime(dType))
1403 }
1404
1405 //------------------------------------------------------------------------------------------------
1406 override void OnPostInit(IEntity owner)
1407 {
1408 if (GetGame().GetWorld() != owner.GetWorld())
1409 return; // ignore entities which are in a different world, like preview world, or preload manager world
1410
1412 data.InitPrefabData(owner, this);
1413 }
1414
1415 //------------------------------------------------------------------------------------------------
1423 */
1424 override bool HijackDamageHandling(notnull BaseDamageContext damageContext)
1425 {
1426 SCR_HitZone hitZone = SCR_HitZone.Cast(damageContext.struckHitZone);
1427 if (hitZone)
1428 hitZone.ApplyDamagePassRules(damageContext);
1429
1430 SCR_FlammableHitZone flammableHitZone = SCR_FlammableHitZone.Cast(damageContext.struckHitZone);
1431 if (flammableHitZone && damageContext.damageType == EDamageType.INCENDIARY)
1432 flammableHitZone.HandleIncendiaryDamage(damageContext);
1433
1434 return false;
1435 }
1436
1437#ifdef WORKBENCH
1438
1439 //------------------------------------------------------------------------------------------------
1440 override int _WB_GetAfterWorldUpdateSpecs(IEntity owner, IEntitySource src)
1441 {
1442 return EEntityFrameUpdateSpecs.CALL_WHEN_ENTITY_VISIBLE;
1443 }
1444
1445 //---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
1446 // TODO: DrawDebug should only run when toggled on by user
1447 //------------------------------------------------------------------------------------------------
1448 protected override void _WB_AfterWorldUpdate(IEntity owner, float timeSlice)
1449 {
1450 super._WB_AfterWorldUpdate(owner, timeSlice);
1451
1452 GenericEntity entity = GenericEntity.Cast(owner);
1453 if (!entity)
1454 return;
1455
1456 WorldEditorAPI api = entity._WB_GetEditorAPI();
1457 if (!api || !api.IsEntitySelected(api.EntityToSource(owner)))
1458 return;
1459
1461 array<HitZone> hitZones = {};
1462 GetAllHitZones(hitZones);
1463
1464 SCR_HitZone hitzone;
1465 foreach (HitZone hitZone : hitZones)
1466 {
1467 hitzone = SCR_HitZone.Cast(hitZone);
1468 if (hitzone)
1469 hitzone.DrawDebug();
1470 }
1471 }
1472 //---- REFACTOR NOTE END ----
1473#endif
1474}
vector scale
EHitZoneGroup
ArmaReforgerScripted GetGame()
Definition game.c:1398
override bool HijackDamageHandling(notnull BaseDamageContext damageContext)
We hijack damage on armor, and use it to damage the character. Always return true on the hijack to en...
override bool FilterContact(IEntity owner, IEntity other, Contact contact)
Armor doesn't take collisiondamage.
override bool HandleDamage(BaseDamageContext damageContext, IEntity owner)
SCR_CharacterBloodHitZone OnDamage
Resilience - incapacitation or death, depending on game mode settings.
SCR_CharacterSoundComponentClass GetComponentData()
bool IsOnFire(HitZone hitZone=null)
float HealHitZonesInParallel(float healthToDistribute, float maxHealThresholdScaled, array< HitZone > targetHitZones)
void UpdateFireParticles(vector position, out ParticleEffectEntity particles, SCR_ESecondaryExplosionScale state, SCR_ESecondaryExplosionType fireType, EResourceType resourceType=EResourceType.SUPPLIES)
float HealHitZonesInSequence(float healthToDistribute, float maxHealThresholdScaled, array< HitZone > targetHitZones)
void SupplySecondaryExplosion(notnull Instigator instigator)
Spawn supply secondary explosion when vehicle becomes destroyed.
const float SIMULATION_IMPRECISION_MULTIPLIER
SCR_SecondaryExplosion GetSecondaryExplosionForScale(SCR_ESecondaryExplosionScale scale, SCR_ESecondaryExplosionType explosionType, EResourceType resourceType=EResourceType.SUPPLIES)
Determine secondary explosion prefab based on explosion scale, type and resource type if defined.
int GetHitZonesOfGroupsFromOwner(notnull array< EHitZoneGroup > hitZoneGroups, out notnull array< HitZone > groupHitZones)
void GetRegeneratingHitZones(out notnull array< SCR_RegeneratingHitZone > regeneratingHitZones)
Return hit zones with passive regeneration enabled.
float GetHitZonesDamage(float untilThresholdScaled=1, array< HitZone > alternativeHitZones=null)
float GetSingleHitZonesHealthScaled(array< HitZone > alternativeHitZones=null, bool getLowestHealth=true)
notnull SCR_DamageManagerData GetScriptedDamageManagerData()
ResourceName GetSecondaryExplosion(float value, SCR_ESecondaryExplosionType explosionType, EResourceType resourceType=EResourceType.SUPPLIES, bool fire=false, out bool hasData=false)
Determine secondary explosion prefab based on explosion value, type and resource type if defined.
int GetHitZonesOfGroupFromOwner(EHitZoneGroup hitZoneGroup, out notnull array< HitZone > groupHitZones, bool clearArray=true)
vector GetSecondaryExplosionPosition(typename hitZoneType, out float totalWeight=0)
Get weighed average position of explosion for hitzones of specified type.
void GetPhysicalHitZones(out notnull array< HitZone > physicalHitZones)
Return hit zones with colliders assigned.
void FuelSecondaryExplosion(notnull Instigator instigator)
Spawn fuel secondary explosion when vehicle becomes destroyed.
void ConnectToFireDamageSystem()
void SecondaryExplosion(ResourceName prefabName, notnull Instigator instigator, notnull EntitySpawnParams spawnParams)
Spawn secondary explosion.
void DamageRandomHitZones(float damage, EDamageType type, notnull Instigator instigator, bool onlyPhysical=true, vector outMat[3]={}, bool damageDefault=false)
void ~SCR_DamageManagerComponent()
void Kill(notnull Instigator instigator)
SCR_ResourceEncapsulator GetResourceEncapsulator(EResourceType suppliesType=EResourceType.SUPPLIES)
void ReduceSmoke()
Reduce smoke output based on the total health of hit zones.
int m_iTimetickInstigator
int m_iTimeThresholdInstigatorReplacement
ResourceName GetSecondaryFireParticle(float value, SCR_ESecondaryExplosionType explosionType, EResourceType resourceType=EResourceType.SUPPLIES)
Determine secondary explosion prefab based on explosion value, type and resource type if defined.
int GetHitZonesOfGroups(notnull array< EHitZoneGroup > hitZoneGroups, out notnull array< HitZone > groupHitZones)
void DisconnectFromFireDamageSystem()
void RpcDo_SetFireState(int hitZoneIndex, SCR_EBurningState fireState)
float GetGroupDamageOverTime(ECharacterHitZoneGroup hitZoneGroup, EDamageType damageType)
float GetHitZonesHealthScaled(array< HitZone > alternativeHitZones=null)
float GetMinDestroyDamage(EDamageType damageType, array< HitZone > hitzones)
int m_iDamageManagerDataIndex
int GetHitZonesOfGroup(EHitZoneGroup hitZoneGroup, out notnull array< HitZone > groupHitZones, bool clearArray=true)
float HealHitZones(float healthToDistribute, bool sequential=false, float maxHealThresholdScaled=1, array< HitZone > alternativeHitZones=null)
void RpcDo_SetFireState_(int hitZoneIndex, SCR_EBurningState fireState)
SCR_DestructibleEntityClass MIN_MOMENTUM_RESPONSE_INDEX
EDamageType type
vector position
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
Get all prefabs that have the spawner data
void SCR_FactionManager(IEntitySource src, IEntity parent)
SCR_EBurningState
override float GetSecondaryExplosionScale()
override void OnDamageStateChanged(EDamageState newState, EDamageState previousDamageState, bool isJIP)
void ParticleEffectEntity(IEntitySource src, IEntity parent)
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
override bool ShouldOverrideInstigator(notnull Instigator currentInstigator, notnull Instigator newInstigator)
SCR_ESecondaryExplosionType
Exploding material type.
override void FullHeal(bool ignoreHealingDOT=true)
override bool CanBeHealed(bool ignoreHealingDOT=true)
Return true if there is damage that can be repaired.
override void UpdateFireDamage(float timeSlice)
int GetSurroundingHitzones(vector position, notnull Physics physics, float maxDistance, EDamageType damageType, out notnull array< HitZone > outHitZones, out float hitZonesDistancePercentSum=0, out map< HitZone, float > outHitZoneDistanceProcentageMap=null)
void OnDamageOverTimeRemoved(EDamageType dType, HitZone hz)
void OnDamageOverTimeAdded(EDamageType dType, float dps, HitZone hz)
enum EVehicleType IEntity
SCR_VehicleDamageManagerComponent GetDamageManager()
void Unregister(SCR_DamageManagerComponent component)
void Register(SCR_DamageManagerComponent component)
proto external WorldEditorAPI _WB_GetEditorAPI()
This returns world editor API, which is safe to use from editor events bellow.
event float ComputeEffectiveDamage(notnull BaseDamageContext damageContext, bool isDOT)
proto external Managed FindComponent(typename typeName)
proto external Physics GetPhysics()
proto external BaseWorld GetWorld()
proto external vector CoordToLocal(vector coord)
proto external IEntity GetRootParent()
Definition Math.c:13
PointInfo - allows to define position.
Definition PointInfo.c:9
Object holding reference to resource. In destructor release the resource.
Definition Resource.c:25
SCR_SecondaryExplosions GetSecondaryExplosions()
ref SCR_SecondaryExplosions m_SecondaryExplosions
ref map< EHitZoneGroup, ref array< int > > m_mHitZoneGroupMap
bool GetBurnStateForHealth(float health, out SCR_EBurningState state)
array< int > GetGroupHitZoneIds(EHitZoneGroup hitZoneGroup)
void InitPrefabData(notnull IEntity owner, notnull SCR_DamageManagerComponent dmgManager)
SCR_SecondaryExplosions GetSecondaryFires()
ref SCR_SecondaryExplosions m_SecondaryFires
ScriptInvoker GetOnDamageOverTimeRemoved(bool createNew=true)
ScriptInvoker GetOnDamageStateChanged(bool createNew=true)
ScriptInvoker GetOnDamageOverTimeAdded(bool createNew=true)
ScriptInvoker GetOnDamage(bool createNew=true)
float GetSecondaryExplosionScale()
Get secondary explosion desired scale. It will determine the prefab retrieved from secondary explosio...
PointInfo GetSecondaryExplosionPoint()
Get secondary explosion desired scale. It will determine the prefab retrieved from secondary explosio...
void ApplyDamagePassRules(notnull BaseDamageContext damageContext)
EHitZoneGroup GetHitZoneGroup()
Definition SCR_HitZone.c:12
static void StopParticleEmissionAndLights(notnull ParticleEffectEntity particleEntity, int lightEmitterID=0)
bool SetResourceValue(float value, bool notifyChange=true)
SCR_ResourceEncapsulator GetResourceEncapsulator()
SCR_ResourceContainer GetContainerAt(int index)
override float GetAggregatedResourceValue()
override SCR_ResourceContainerQueueBase GetContainerQueue()
Definition World.c:16
Definition Types.c:486
void EntitySpawnParams()
Definition gameLib.c:130
IEntity GetOwner()
Owner entity of the fuel tank.
InstigatorType
SCR_FieldOfViewSettings Attribute
EDamageType
Definition EDamageType.c:13
EDamageState
proto external EParticleEffectState GetState()
BaseProjectileComponentClass GameComponentClass GetInstigator()
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
ScriptInvokerBase< func > ScriptInvoker
Definition tools.c:134