1#define ENABLE_BASE_DESTRUCTION
4 [
Attribute(
"100",
UIWidgets.Slider,
"Base health value of the object. Damage received above this value results in destruction (overrides HPMax in hit zone)",
"0.01 100000 0.01",
category:
"Destruction Setup")]
6 [
Attribute(
"50",
UIWidgets.Slider,
"Relative contact force to damage multiplier",
"0.01 50000 0.01",
category:
"Destruction Setup")]
7 float m_fForceToDamageScale;
9 float m_fMomentumToDamageScale;
10 [
Attribute(
"0.5",
UIWidgets.Slider,
"Minimum relative contact force (impulse / mass) threshold below which contacts are ignored",
"0 50000 0.01",
category:
"Destruction Setup")]
11 float m_fRelativeContactForceThresholdMinimum;
12 [
Attribute(
"3000",
UIWidgets.Slider,
"Maximum damage threshold above which the object is completely destroyed and no effects are played (eg: nuclear bomb damage)",
"0.01 50000 0.01",
category:
"Destruction Setup")]
13 float m_fDamageThresholdMaximum;
14 [
Attribute(
"0",
desc:
"Should children destructible objects also receive the damage dealt to this one?",
category:
"Destruction Setup")]
15 bool m_bPassDamageToChildren;
16 [
Attribute(
"0",
desc:
"Should the parent of this object also be destroyed when this object gets destroyed?",
category:
"Destruction Setup")]
17 bool m_bDestroyParentWhenDestroyed;
18 [
Attribute(
"0",
desc:
"Should the children of this object also be destroyed when this object gets destroyed?",
category:
"Destruction Setup")]
19 bool m_bDestroyChildrenWhenDestroyed;
21 [
Attribute(
"",
UIWidgets.Object,
"List of objects (particles, debris, etc) to spawn on destruction of the object",
category:
"Destruction FX")]
22 ref array<ref SCR_BaseSpawnable> m_DestroySpawnObjects;
26class SCR_DestructionDamageManagerComponent : SCR_DamageManagerComponent
28#ifdef ENABLE_BASE_DESTRUCTION
30 protected static bool s_bReadingInit =
false;
33 protected static bool s_bPrintMissingComponent;
34 protected static bool s_bPrintMissingPlayerController;
35 protected static bool s_bPrintInitializationFailed;
38 protected static int s_iFirstFreeDestructionBaseData = -1;
39 protected static ref array<ref SCR_DestructionBaseData> s_aDestructionBaseData = {};
45 static bool GetReadingInit(
bool readingInit)
47 return s_bReadingInit;
51 static void SetReadingInit(
bool readingInit)
53 s_bReadingInit = readingInit;
66 private int AllocateDestructionBaseData()
68 if (s_iFirstFreeDestructionBaseData == -1)
69 return s_aDestructionBaseData.Insert(
new SCR_DestructionBaseData());
72 int returnIndex = s_iFirstFreeDestructionBaseData;
73 SCR_DestructionBaseData
data = s_aDestructionBaseData[returnIndex];
74 s_iFirstFreeDestructionBaseData =
data.m_iNextFreeIndex;
75 data.m_iNextFreeIndex = -1;
81 private void FreeDestructionBaseData(
int index)
83 s_aDestructionBaseData[
index].Reset();
84 s_aDestructionBaseData[
index].m_iNextFreeIndex = s_iFirstFreeDestructionBaseData;
85 s_iFirstFreeDestructionBaseData =
index;
106 SCR_DestructionHitInfo GetDestructionHitInfo(
bool createNew =
false)
115 bool ShouldDestroyParent()
117 SCR_DestructionDamageManagerComponentClass prefabData = SCR_DestructionDamageManagerComponentClass.Cast(
GetComponentData(
GetOwner()));
118 return prefabData && prefabData.m_bDestroyParentWhenDestroyed;
122 bool ShouldDestroyChildren()
124 SCR_DestructionDamageManagerComponentClass prefabData = SCR_DestructionDamageManagerComponentClass.Cast(
GetComponentData(
GetOwner()));
125 return prefabData && prefabData.m_bDestroyChildrenWhenDestroyed;
130 bool GetDisablePhysicsOnDestroy()
158 void RPC_DoSpawnAllDestroyEffects()
160 SCR_DestructionDamageManagerComponentClass componentData = SCR_DestructionDamageManagerComponentClass.Cast(
GetComponentData(
GetOwner()));
161 SCR_DestructionUtility.SpawnDestroyObjects(
GetOwner(), componentData.m_DestroySpawnObjects,
new SCR_DestructionHitInfo());
166 SCR_DestructionDamageManagerComponent
destructible = SCR_DestructionDamageManagerComponent.Cast(child.
FindComponent(SCR_DestructionDamageManagerComponent));
173 SCR_DestructionDamageManagerComponentClass componentDataChild = SCR_DestructionDamageManagerComponentClass.Cast(
destructible.GetComponentData(child));
174 SCR_DestructionUtility.SpawnDestroyObjects(child, componentDataChild.m_DestroySpawnObjects,
new SCR_DestructionHitInfo());
181 void DeleteParentWithEffects()
186 RPC_DoSpawnAllDestroyEffects();
187 Rpc(RPC_DoSpawnAllDestroyEffects);
189 DeleteDestructibleDelayed();
194 void DeleteDestructibleDelayed()
203 GetGame().GetCallqueue().CallLater(DeleteDestructible);
208 void DeleteDestructibleChildrenDelayed(
bool withEffects =
true)
213 GetGame().GetCallqueue().CallLater(DeleteDestructibleChildren,
param1: withEffects);
219 private void DeleteDestructible()
224 if (ShouldDestroyParent())
229 SCR_DestructionDamageManagerComponent
destructible = SCR_DestructionDamageManagerComponent.Cast(parent.
FindComponent(SCR_DestructionDamageManagerComponent));
238 if (ShouldDestroyChildren())
239 DeleteDestructibleChildren();
241 SCR_DestructionUtility.RegenerateNavmeshDelayed(
GetOwner());
243 array<HitZone> outHitZones = {};
244 if (GetAllHitZones(outHitZones) < 1)
245 RplComponent.DeleteRplEntity(
GetOwner(),
false);
247 SCR_DestructibleHitzone destructibleHitZone;
248 foreach (HitZone hitZone : outHitZones)
250 destructibleHitZone = SCR_DestructibleHitzone.Cast(hitZone);
251 if (!destructibleHitZone)
258 RplComponent.DeleteRplEntity(
GetOwner(),
false);
264 private void DeleteDestructibleChildren(
bool withEffects =
true)
268 SCR_DestructionDamageManagerComponent childDestructionComponent;
275 childDestructionComponent = SCR_DestructionDamageManagerComponent.Cast(child.
FindComponent(SCR_DestructionDamageManagerComponent));
277 if (childDestructionComponent)
281 childDestructionComponent.DeleteParentWithEffects();
283 childDestructionComponent.DeleteDestructibleDelayed();
293 void SetHitZoneHealth(
float baseHealth,
bool clearDamage =
true)
295 HitZone hitZone = GetDefaultHitZone();
296 hitZone.SetMaxHealth(baseHealth);
297 hitZone.SetHealth(baseHealth);
302 void SetHitZoneDamage(
float damage)
304 HitZone hitZone = GetDefaultHitZone();
305 hitZone.SetHealth(hitZone.GetMaxHealth() - damage);
310 SCR_DestructionHitInfo CreateDestructionHitInfo(
bool totalDestruction,
float lastHealth,
float hitDamage,
EDamageType damageType, vector hitPosition, vector hitDirection, vector hitNormal)
314 hitInfo.m_TotalDestruction = totalDestruction;
315 hitInfo.m_LastHealth = lastHealth;
316 hitInfo.m_HitDamage = hitDamage;
317 hitInfo.m_DamageType = damageType;
318 hitInfo.m_HitPosition = hitPosition;
319 hitInfo.m_HitDirection = hitDirection;
320 hitInfo.m_HitNormal = hitNormal;
327 bool GetCanBeDamaged()
340 void HandleDestruction()
345 SCR_DestructionDamageManagerComponentClass componentData = SCR_DestructionDamageManagerComponentClass.Cast(
GetComponentData(
GetOwner()));
349 SCR_DestructionUtility.SpawnDestroyObjects(
GetOwner(), componentData.m_DestroySpawnObjects, GetDestructionHitInfo());
350 DeleteDestructibleDelayed();
355 void InitDestruction()
361 void NetReceiveHitData(
int hitIndex,
EDamageType damageType,
float damage, vector hitPosition, vector hitDirection)
367 void NetReadInit(ScriptBitReader reader)
373 void NetWriteInit(ScriptBitWriter writer)
385 private void RPC_QueueDestroy(
bool totalDestruction,
float lastHealth,
float hitDamage,
EDamageType damageType, vector hitPosition, vector hitDirection, vector hitNormal)
388 CreateDestructionHitInfo(totalDestruction, lastHealth, hitDamage, damageType, hitPosition, hitDirection, hitNormal);
398 RplComponent currentRplComponent;
401 currentRplComponent = RplComponent.Cast(parent.
FindComponent(RplComponent));
405 return currentRplComponent;
414 SCR_DestructionDamageManagerComponent destructionComponent = SCR_DestructionDamageManagerComponent.Cast(child.
FindComponent(SCR_DestructionDamageManagerComponent));
415 if (!destructionComponent)
425 childContext.hitEntity = currentChild;
426 childContext.struckHitZone = destructionComponent.GetDefaultHitZone();
428 destructionComponent.HandleDamage(childContext);
436 RplComponent rplComponent = RplComponent.Cast(
GetOwner().FindComponent(RplComponent));
437 return (rplComponent && rplComponent.IsProxy());
450 if(!contact.Physics2.IsDynamic())
457 if (!super.FilterContact(owner, other, contact))
461 if (GetDestroyed() || !GetCanBeDamaged())
464 if (other && other.IsInherited(SCR_DebrisSmallEntity))
473 float relativeForce = contact.Impulse / contact.Physics2.GetMass();
474 if (relativeForce < componentData.m_fRelativeContactForceThresholdMinimum)
478 int currentTime =
GetGame().GetWorld().GetWorldTime();
493 int ownerReponseIndex = ownerPhysics.GetResponseIndex();
494 int otherResponseIndex = otherPhysics.GetResponseIndex();
500 if (ownerReponseIndex < MIN_DESTRUCTION_RESPONSE_INDEX || otherResponseIndex -
MIN_MOMENTUM_RESPONSE_INDEX < ownerReponseIndex - MIN_DESTRUCTION_RESPONSE_INDEX)
504 damage = momentum * componentData.m_fMomentumToDamageScale;
509 vector relVel = contact.VelocityBefore2 - contact.VelocityBefore1;
510 outMat[0] = contact.Position;
511 outMat[1] = relVel.Normalized();
512 outMat[2] = contact.Normal;
522 super.OnDamage(damageContext);
528 if (componentData.m_bPassDamageToChildren)
551 if (physics.IsDynamic() && !physics.IsActive())
552 physics.ApplyImpulse(
vector.Up * physics.GetMass() * 0.001);
555 if (GetDisablePhysicsOnDestroy())
556 physics.SetInteractionLayer(EPhysicsLayerDefs.VehicleCast);
559 float previousHealth;
563 CreateDestructionHitInfo(damageContext.damageValue >= componentData.m_fDamageThresholdMaximum, previousHealth, damageContext.damageValue, damageContext.damageType, damageContext.hitPosition, damageContext.hitDirection, damageContext.hitNormal);
567 SCR_DestructionHitInfo destructionHitInfo = GetDestructionHitInfo();
568 if (!destructionHitInfo)
571 Rpc(RPC_QueueDestroy, destructionHitInfo.m_TotalDestruction, destructionHitInfo.m_LastHealth, destructionHitInfo.m_HitDamage, destructionHitInfo.m_DamageType, destructionHitInfo.m_HitPosition, destructionHitInfo.m_HitDirection, destructionHitInfo.m_HitNormal);
584 return data.GetDestructionQueued();
594 return componentData.m_fDamageThresholdMaximum;
600 super.OnPostInit(owner);
604 if (!GetDefaultHitZone())
610 SetHitZoneHealth(componentData.m_fBaseHealth);
619 s_bPrintMissingComponent =
false;
620 s_bPrintMissingPlayerController =
false;
621 s_bPrintInitializationFailed =
false;
ArmaReforgerScripted GetGame()
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()
SCR_DestructibleEntityClass MIN_MOMENTUM_RESPONSE_INDEX
float GetTotalDestructionThreshold()
SCR_DestructionDamageManagerComponentClass s_OnDestructibleDestroyed
Base destruction component, destruction types extend from this.
int m_iDestructionBaseDataIndex
notnull SCR_DestructionBaseData GetDestructionBaseData()
void PassDamageToChildren(notnull BaseDamageContext damageContext)
void ~SCR_DestructionDamageManagerComponent()
bool IsDestructionQueued()
RplComponent FindParentRplComponent()
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
destructible ReplicateDestructibleState()
SCR_DestructionDamageManagerComponent destructible
Get all prefabs that have the spawner data
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
override void OnFilteredContact(IEntity owner, IEntity other, Contact contact)
enum EVehicleType IEntity
proto external Managed FindComponent(typename typeName)
proto external Physics GetPhysics()
proto external IEntity GetChildren()
proto external IEntity GetParent()
proto external IEntity GetSibling()
ref SCR_DestructionBaseHandler GetDestructionHandler()
void SetDestructionQueued(bool destructionQueued)
ScriptInvoker GetOnDamage(bool createNew=true)
float GetPreviousHealth()
SCR_DestructionHitInfo GetHitInfo(bool createNew=true)
void SetPreviousHealth(float previousHealth)
static float CalculateMomentum(notnull Contact contact, float ownerMass, float otherMass)
static void UpdateResponseIndex(notnull Physics physics, float health, float maxHealth)
IEntity GetOwner()
Owner entity of the fuel tank.
SCR_FieldOfViewSettings Attribute
EntityEvent
Various entity events.
void RplRpc(RplChannel channel, RplRcver rcver, RplCondition condition=RplCondition.None, string customConditionName="")
RplChannel
Communication channel. Reliable is guaranteed to be delivered. Unreliable not.