Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_DestructibleHitzone.c
Go to the documentation of this file.
1 #define ENABLE_BASE_DESTRUCTION
2 //------------------------------------------------------------------------------------------------
4 {
5  [Attribute("0", UIWidgets.Slider, "Scale of damage passed to parent default hitzone\nIgnores base damage multiplier, reduction and threshold\nDamage type multipliers are applied", "0 100 0.001")]
6  protected float m_fPassDamageToParentScale;
7 
8  [Attribute(desc: "Rules for passing damage to parent and root damage managers")]
9  protected ref array<ref SCR_DamagePassRule> m_aDamagePassRules;
10 
11  [Attribute(desc: "Secondary explosion reference point", category: "Secondary damage")]
12  protected ref PointInfo m_SecondaryExplosionPoint;
13 
14  [Attribute("", UIWidgets.Auto, desc: "Destruction Handler")]
15  protected ref SCR_DestructionBaseHandler m_pDestructionHandler;
16 
17  [Attribute(desc: "Destruction sound event name", category: "Effects")]
18  protected string m_sDestructionSoundEvent;
19 
20  [Attribute(desc: "Particle effect for destruction", params: "ptc", category: "Effects")]
21  protected ResourceName m_sDestructionParticle;
22 
23  [Attribute(uiwidget: UIWidgets.Coords, "Position of the effect in model space", category: "Effects")]
24  protected vector m_vParticleOffset;
25 
26  protected ParticleEffectEntity m_DstParticle; // Destruction particle
27  protected SCR_DamageManagerComponent m_ParentDamageManager; // Damage manager of the direct parent
28  protected SCR_DamageManagerComponent m_RootDamageManager;
29  protected SCR_BaseCompartmentManagerComponent m_CompartmentManager; // The part may have occupants that we want to damage
30 
31 #ifdef ENABLE_BASE_DESTRUCTION
32  //------------------------------------------------------------------------------------------------
33  ref SCR_DestructionBaseHandler GetDestructionHandler()
34  {
35  return m_pDestructionHandler;
36  }
37 
38  //------------------------------------------------------------------------------------------------
39  override void OnInit(IEntity pOwnerEntity, GenericComponent pManagerComponent)
40  {
41  super.OnInit(pOwnerEntity, pManagerComponent);
42 
43  m_CompartmentManager = SCR_BaseCompartmentManagerComponent.Cast(pOwnerEntity.FindComponent(SCR_BaseCompartmentManagerComponent));
44 
45  // Parent damage manager
46  IEntity parent = pOwnerEntity.GetParent();
47  if (parent)
48  m_ParentDamageManager = SCR_DamageManagerComponent.Cast(parent.FindComponent(SCR_DamageManagerComponent));
49 
50  // Root damage manager
51  IEntity root = pOwnerEntity.GetRootParent();
52  if (root)
53  m_RootDamageManager = SCR_DamageManagerComponent.Cast(root.FindComponent(SCR_DamageManagerComponent));
54 
55  if (m_pDestructionHandler)
56  m_pDestructionHandler.Init(pOwnerEntity, this);
57 
58  if (m_SecondaryExplosionPoint)
59  m_SecondaryExplosionPoint.Init(pOwnerEntity);
60  }
61 
62  //------------------------------------------------------------------------------------------------
78  override float ComputeEffectiveDamage(notnull BaseDamageContext damageContext, bool isDOT)
79  {
80  vector hitTransform[3] = {damageContext.hitPosition, damageContext.hitDirection, damageContext.hitNormal};
81 
82  // Forward non-DOT damage to parent, ignoring own base damage multiplier
83  if (!isDOT && m_fPassDamageToParentScale != 0)
84  PassDamageToParent(damageContext.damageType, damageContext.damageValue, damageContext.instigator, hitTransform, damageContext.material);
85 
86  // Forward non-DOT damage to root or parent default hitzone, ignoring own base damage multiplier
88  foreach (SCR_DamagePassRule rule : m_aDamagePassRules)
89  {
90  if (isDOT && !rule.m_bAllowDOT)
91  continue;
92 
93  // If damage types are defined, only allow passing specified damage types
94  if (!rule.m_aSourceDamageTypes.IsEmpty() && !rule.m_aSourceDamageTypes.Contains(damageContext.damageType))
95  continue;
96 
97  // If damage states are defined, only allow passing while damage state is allowed
98  if (!rule.m_aDamageStates.IsEmpty() && !rule.m_aDamageStates.Contains(GetDamageState()))
99  continue;
100 
101  if (rule.m_eOutputDamageType == EDamageType.TRUE)
102  type = damageContext.damageType;
103  else
104  type = rule.m_eOutputDamageType;
105 
106  if (rule.m_bPassToRoot)
107  PassDamageToRoot(damageContext.damageType, damageContext.damageValue * rule.m_fMultiplier, damageContext.instigator, hitTransform, damageContext.material);
108 
109  if (rule.m_bPassToParent)
110  PassDamageToParent(damageContext.damageType, damageContext.damageValue * rule.m_fMultiplier, damageContext.instigator, hitTransform, damageContext.material);
111 
112  if (rule.m_bPassToDefaultHitZone)
113  PassDamageToDefaultHitZone(damageContext.damageType, damageContext.damageValue * rule.m_fMultiplier, damageContext.instigator, hitTransform, damageContext.material);
114  }
115 
116  return super.ComputeEffectiveDamage(damageContext, isDOT);
117  }
118 
119  //------------------------------------------------------------------------------------------------
128  void PassDamageToParent(EDamageType type, float damage, notnull Instigator instigator, inout vector transform[3], SurfaceProperties surface = null)
129  {
130  if (!m_ParentDamageManager)
131  return;
132 
133  if (damage == 0)
134  return;
135 
136  SCR_DamageContext damageContext = new SCR_DamageContext(type, damage, transform, m_ParentDamageManager.GetOwner(), m_ParentDamageManager.GetDefaultHitZone(), instigator, surface, -1, -1);
137 
138  m_ParentDamageManager.HandleDamage(damageContext);
139  }
140 
141  //------------------------------------------------------------------------------------------------
150  void PassDamageToRoot(EDamageType type, float damage, notnull Instigator instigator, inout vector transform[3], SurfaceProperties surface = null)
151  {
152  if (!m_RootDamageManager)
153  return;
154 
155  if (damage == 0)
156  return;
157 
158  HitZone defaultHZ = m_RootDamageManager.GetDefaultHitZone();
159  if (defaultHZ != this)
160  {
161  SCR_DamageContext damageContext = new SCR_DamageContext(type, damage, transform, m_RootDamageManager.GetOwner(), defaultHZ, instigator, surface, -1, -1);
162 
163  m_RootDamageManager.HandleDamage(damageContext);
164  }
165  }
166 
167  //------------------------------------------------------------------------------------------------
176  void PassDamageToDefaultHitZone(EDamageType type, float damage, notnull Instigator instigator, inout vector transform[3], SurfaceProperties surface = null)
177  {
178  SCR_DamageManagerComponent damageManager = SCR_DamageManagerComponent.Cast(GetHitZoneContainer());
179  if (!damageManager || !damageManager.GetDefaultHitZone())
180  return;
181 
182  if (damage == 0)
183  return;
184 
185  HitZone defaultHZ = damageManager.GetDefaultHitZone();
186  if (defaultHZ != this)
187  {
188  SCR_DamageContext damageContext = new SCR_DamageContext(type, damage, transform, damageManager.GetOwner(), defaultHZ, instigator, surface, -1, -1);
189  damageManager.HandleDamage(damageContext);
190  }
191  }
192 
193  //------------------------------------------------------------------------------------------------
195  float GetSecondaryExplosionScale()
196  {
197  return GetMaxHealth();
198  }
199 
200  //------------------------------------------------------------------------------------------------
202  PointInfo GetSecondaryExplosionPoint()
203  {
204  return m_SecondaryExplosionPoint;
205  }
206 
207  //------------------------------------------------------------------------------------------------
209  override void OnDamageStateChanged()
210  {
211  super.OnDamageStateChanged();
212 
213  EDamageState state = GetDamageState();
214 
215  // Restrict AI from accessing this parts compartments
217  m_CompartmentManager.SetCompartmentsAccessibleForAI(state != EDamageState.DESTROYED);
218 
219  // Change from destroyed can only mean repair
220  if (GetPreviousDamageState() == EDamageState.DESTROYED)
221  {
222  StopDestruction();
223  return;
224  }
225 
226  if (state == EDamageState.DESTROYED)
227  StartDestruction();
228 
229  PlayDestructionSound(state);
230  PlayDestructionParticle(state);
231  }
232 
233  //------------------------------------------------------------------------------------------------
235  void StartDestruction(bool immediate = false)
236  {
237  SCR_VehicleDamageManagerComponent parentDamageManager = FindParentVehicleDamageManager();
238 
239  // Kill and eject occupants
240  // Only main hitzone should deal damage to occupants.
241  // TODO: Make passengers suffer random fire and bleeding instead, and let them get out if they are conscious.
242  // TODO: Depends on ability to move the occupants to proper positions inside wrecks.
243  HitZoneContainerComponent hitZoneContainer = GetHitZoneContainer();
244  if (hitZoneContainer && hitZoneContainer.GetDefaultHitZone() == this && m_CompartmentManager && !IsProxy())
245  {
246  SCR_DamageManagerComponent damageManager = parentDamageManager;
247  if (!damageManager)
248  damageManager = SCR_DamageManagerComponent.Cast(GetHitZoneContainer());
249 
250  Instigator instigator;
251  if (damageManager)
252  instigator = damageManager.GetInstigator();
253 
254  m_CompartmentManager.KillOccupants(instigator, true);
255  }
256 
257  if (m_pDestructionHandler)
258  m_pDestructionHandler.StartDestruction(immediate);
259  }
260 
261  //------------------------------------------------------------------------------------------------
263  protected void StopDestruction()
264  {
265  // Must not change model outside frame
266  if (m_pDestructionHandler)
267  GetGame().GetCallqueue().CallLater(m_pDestructionHandler.OnRepair);
268  }
269 
270  //------------------------------------------------------------------------------------------------
271  protected SCR_VehicleDamageManagerComponent FindParentVehicleDamageManager()
272  {
273  // Futile if there is no hitzonecontainer anymore
274  HitZoneContainerComponent hitZoneContainer = GetHitZoneContainer();
275  if (!hitZoneContainer)
276  return null;
277 
278  SCR_VehicleDamageManagerComponent damageManager = SCR_VehicleDamageManagerComponent.Cast(hitZoneContainer);
279  if (damageManager)
280  return damageManager;
281 
282  damageManager = SCR_VehicleDamageManagerComponent.Cast(m_ParentDamageManager);
283  if (damageManager)
284  return damageManager;
285 
286  IEntity parent = GetOwner().GetParent();
287  while (parent)
288  {
289  damageManager = SCR_VehicleDamageManagerComponent.Cast(parent.FindComponent(SCR_VehicleDamageManagerComponent));
290  if (damageManager)
291  return damageManager;
292 
293  parent = parent.GetParent();
294  }
295 
296  return damageManager;
297  }
298 
299  //------------------------------------------------------------------------------------------------
301  protected void PlayDestructionSound(EDamageState damageState)
302  {
303  // Sounds are only relevant for non-dedicated clients
304  if (System.IsConsoleApp())
305  return;
306 
307  if (damageState != EDamageState.DESTROYED)
308  return;
309 
310  if (m_sDestructionSoundEvent.IsEmpty())
311  return;
312 
313  IEntity owner = GetOwner();
314  if (!owner)
315  return;
316 
317  // Play destruction effects only if not streaming in
318  SCR_DamageManagerComponent hitZoneContainer = SCR_DamageManagerComponent.Cast(GetHitZoneContainer());
319  if (IsProxy() && hitZoneContainer && !hitZoneContainer.IsRplReady())
320  return;
321 
322  IEntity mainParent = SCR_EntityHelper.GetMainParent(owner);
323  if (mainParent)
324  {
325  // Get position offset for slotted entities
326  vector mins;
327  vector maxs;
328  owner.GetBounds(mins, maxs);
329  vector center = vector.Lerp(mins, maxs, 0.5);
330 
331  // Add bone offset
332  EntitySlotInfo slotInfo = EntitySlotInfo.GetSlotInfo(owner);
333  if (slotInfo)
334  {
335  vector mat[4];
336  slotInfo.GetModelTransform(mat);
337  center = center + mat[3];
338  }
339 
340  SoundComponent soundComponent = SoundComponent.Cast(mainParent.FindComponent(SoundComponent));
341  if (!soundComponent)
342  return;
343 
344  soundComponent.SoundEventOffset(m_sDestructionSoundEvent, center);
345  }
346  else
347  {
348  SoundComponent soundComponent = SoundComponent.Cast(owner.FindComponent(SoundComponent));
349  if (!soundComponent)
350  return;
351 
352  soundComponent.SoundEvent(m_sDestructionSoundEvent);
353  }
354  }
355 
356  //------------------------------------------------------------------------------------------------
358  void PlayDestructionParticle(EDamageState state)
359  {
360  // Particles are only relevant for non-dedicated clients
361  if (System.IsConsoleApp())
362  return;
363 
364  if (state == EDamageState.DESTROYED && !m_DstParticle && !m_sDestructionParticle.IsEmpty())
365  {
366  ParticleEffectEntitySpawnParams spawnParams();
367  spawnParams.Transform[3] = m_vParticleOffset;
368  spawnParams.Parent = GetOwner();
369  spawnParams.UseFrameEvent = true;
370  m_DstParticle = ParticleEffectEntity.SpawnParticleEffect(m_sDestructionParticle, spawnParams);
371  }
372  }
373 #endif
374 }
BaseDamageContext
Definition: BaseDamageContext.c:12
SCR_EntityHelper
Definition: SCR_EntityHelper.c:1
GetMaxHealth
float GetMaxHealth()
Definition: SCR_DestructibleEntity.c:122
m_RootDamageManager
protected SCR_VehicleDamageManagerComponent m_RootDamageManager
Definition: SCR_RotorDamageManagerComponent.c:8
HitZone
Definition: HitZone.c:12
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
SCR_VehicleDamageManagerComponent
void SCR_VehicleDamageManagerComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
Definition: SCR_VehicleDamageManagerComponent.c:1720
SCR_DestructibleHitzone
Definition: SCR_DestructibleHitzone.c:3
EDamageState
EDamageState
Definition: EDamageState.c:12
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
Instigator
Definition: Instigator.c:6
EntitySlotInfo
Adds ability to attach an object to a slot.
Definition: EntitySlotInfo.c:8
HitZoneContainerComponent
Definition: HitZoneContainerComponent.c:12
IsProxy
protected bool IsProxy()
Definition: SCR_CampaignBuildingCompositionComponent.c:456
Attribute
typedef Attribute
Post-process effect of scripted camera.
SCR_DestructionBaseHandler
Definition: SCR_DestructionBaseHandler.c:7
m_CompartmentManager
protected SCR_BaseCompartmentManagerComponent m_CompartmentManager
Definition: SCR_VehicleDamageManagerComponent.c:191
GetOwner
IEntity GetOwner()
Owner entity of the fuel tank.
Definition: SCR_FuelNode.c:128
SCR_HitZone
Definition: SCR_HitZone.c:1
SCR_DamageContext
Definition: SCR_DamageContext.c:7
type
EDamageType type
Definition: SCR_DestructibleTreeV2.c:32
EDamageType
EDamageType
Definition: EDamageType.c:12
params
Configs ServerBrowser KickDialogs params
Definition: SCR_NotificationSenderComponent.c:24
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180
SCR_DamagePassRule
Definition: SCR_DamagePassRule.c:3