Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_DestructionBaseComponent.c
Go to the documentation of this file.
1 #define ENABLE_BASE_DESTRUCTION
3 {
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")]
5  float m_fBaseHealth;
6  [Attribute("50", UIWidgets.Slider, "Relative contact force to damage multiplier", "0.01 50000 0.01", category: "Destruction Setup")]
7  float m_fForceToDamageScale;
8  [Attribute("0.05", UIWidgets.Slider, "Contact momentum to damage multiplier", "0.01 10 0.01", category: "Destruction Setup")]
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 
19  [Attribute("", UIWidgets.Object, "List of objects (particles, debris, etc) to spawn on destruction of the object", category: "Destruction FX")]
20  ref array<ref SCR_BaseSpawnable> m_DestroySpawnObjects;
21 }
22 
24 class SCR_DestructionDamageManagerComponent : SCR_DamageManagerComponent
25 {
26 #ifdef ENABLE_BASE_DESTRUCTION
27  static protected ref ScriptInvoker s_OnDestructibleDestroyed = new ScriptInvoker();
28  protected static bool s_bReadingInit = false; //Used to determine whether we are in gameplay or synchronization state
29 
30 #ifdef WORKBENCH
31  protected static bool s_bPrintMissingComponent;
32  protected static bool s_bPrintMissingPlayerController;
33  protected static bool s_bPrintInitializationFailed;
34 #endif
35 
36  private static int s_iFirstFreeDestructionBaseData = -1;
37  private static ref array<ref SCR_DestructionBaseData> s_aDestructionBaseData = {};
38 
39  private int m_iDestructionBaseDataIndex = -1;
40 
41  //------------------------------------------------------------------------------------------------
43  static ScriptInvoker GetOnDestructibleDestroyedInvoker()
44  {
46  }
47 
48  //------------------------------------------------------------------------------------------------
51  static bool GetReadingInit(bool readingInit)
52  {
53  return s_bReadingInit;
54  }
55 
56  //------------------------------------------------------------------------------------------------
58  static void SetReadingInit(bool readingInit)
59  {
60  s_bReadingInit = readingInit;
61  }
62 
63  //------------------------------------------------------------------------------------------------
65  {
68 
69  return s_aDestructionBaseData[m_iDestructionBaseDataIndex];
70  }
71 
72  //------------------------------------------------------------------------------------------------
74  {
75  if (s_iFirstFreeDestructionBaseData == -1)
76  {
77  return s_aDestructionBaseData.Insert(new SCR_DestructionBaseData());
78  }
79  else
80  {
81  int returnIndex = s_iFirstFreeDestructionBaseData;
82  SCR_DestructionBaseData data = s_aDestructionBaseData[returnIndex];
83  s_iFirstFreeDestructionBaseData = data.m_iNextFreeIndex;
84  data.m_iNextFreeIndex = -1;
85  return returnIndex;
86  }
87  }
88 
89  //------------------------------------------------------------------------------------------------
90  private void FreeDestructionBaseData(int index)
91  {
92  s_aDestructionBaseData[index].Reset();
93  s_aDestructionBaseData[index].m_iNextFreeIndex = s_iFirstFreeDestructionBaseData;
94  s_iFirstFreeDestructionBaseData = index;
95  }
96 
97  //------------------------------------------------------------------------------------------------
99  ScriptInvoker GetOnDamageInvoker()
100  {
101  return GetDestructionBaseData().GetOnDamage();
102  }
103 
104  //------------------------------------------------------------------------------------------------
107  SCR_DestructionHitInfo GetDestructionHitInfo(bool createNew = false)
108  {
109  if (m_iDestructionBaseDataIndex == -1 && !createNew)
110  return null;
111 
112  return GetDestructionBaseData().GetHitInfo(createNew);
113  }
114 
115  //------------------------------------------------------------------------------------------------
118  {
120  return prefabData && prefabData.m_bDestroyParentWhenDestroyed;
121  }
122 
123  //------------------------------------------------------------------------------------------------
126  {
127  return true;
128  }
129 
130  //------------------------------------------------------------------------------------------------
133  {
134  if (m_iDestructionBaseDataIndex == -1)
135  return GetHealth() == 1;
136 
137  return !GetDestructionBaseData().GetHitInfo(false) && GetHealth() == 1;
138  }
139 
140  //------------------------------------------------------------------------------------------------
143  {
144  if (m_iDestructionBaseDataIndex == -1)
145  return GetHealth() <= 0;
146 
147  return GetDestructionBaseData().GetHitInfo(false) || GetHealth() <= 0;
148  }
149 
150  //------------------------------------------------------------------------------------------------
152  [RplRpc(RplChannel.Unreliable, RplRcver.Broadcast)]
154  {
156 
157  IEntity child = GetOwner().GetChildren();
158  while (child)
159  {
160  SCR_DestructionDamageManagerComponent destructible = SCR_DestructionDamageManagerComponent.Cast(child.FindComponent(SCR_DestructionDamageManagerComponent));
161  if (destructible)
162  destructible.SpawnDestroyObjects(new SCR_HitInfo());
163 
164  child = child.GetSibling();
165  }
166  }
167 
168  //------------------------------------------------------------------------------------------------
171  {
172  if (GetDestructionBaseData().GetDestructionQueued())
173  return; // Destruction queued already, don't do this.
174 
177 
179  }
180 
181  //------------------------------------------------------------------------------------------------
184  {
185  if (ShouldDestroyParent())
186  {
187  IEntity parent = GetOwner().GetParent();
188  if (parent)
189  {
190  SCR_DestructionDamageManagerComponent destructible = SCR_DestructionDamageManagerComponent.Cast(parent.FindComponent(SCR_DestructionDamageManagerComponent));
191  if (destructible)
192  {
193  destructible.DeleteParentWithEffects();
194  return;
195  }
196  }
197  }
198 
199  GetDestructionBaseData().SetDestructionQueued(true);
201  RplComponent.DeleteRplEntity(GetOwner(), false);
202  }
203 
204  //------------------------------------------------------------------------------------------------
208  void SetHitZoneHealth(float baseHealth, bool clearDamage = true)
209  {
210  HitZone hitZone = GetDefaultHitZone();
211  if (!hitZone)
212  return;
213 
214  hitZone.SetMaxHealth(baseHealth, ESetMaxHealthFlags.FULLHEAL);
215  }
216 
217  //------------------------------------------------------------------------------------------------
220  void SetHitZoneDamage(float damage)
221  {
222  HitZone hitZone = GetDefaultHitZone();
223  if (!hitZone)
224  return;
225 
226  hitZone.SetHealth(hitZone.GetMaxHealth() - damage);
227  }
228 
229  //------------------------------------------------------------------------------------------------
238  void CreateDestructionHitInfo(bool totalDestruction, float lastHealth, float hitDamage, EDamageType damageType, vector hitPosition, vector hitDirection, vector hitNormal)
239  {
240  SCR_DestructionHitInfo hitInfo = GetDestructionBaseData().GetHitInfo();
241 
242  hitInfo.m_TotalDestruction = totalDestruction;
243  hitInfo.m_LastHealth = lastHealth;
244  hitInfo.m_HitDamage = hitDamage;
245  hitInfo.m_DamageType = damageType;
246  hitInfo.m_HitPosition = hitPosition;
247  hitInfo.m_HitDirection = hitDirection;
248  hitInfo.m_HitNormal = hitNormal;
249  }
250 
251  //------------------------------------------------------------------------------------------------
254  {
255  return true;
256  }
257 
258  //------------------------------------------------------------------------------------------------
261  {
262  }
263 
264  //------------------------------------------------------------------------------------------------
268  {
269  Physics ownerPhysics = GetOwner().GetPhysics();
270 
271  array<ref SCR_BaseSpawnable> destroySpawnObjects = SCR_DestructionDamageManagerComponentClass.Cast(GetComponentData(GetOwner())).m_DestroySpawnObjects;
272  int numSpawnOnDestroy = destroySpawnObjects.Count();
273  for (int i = 0; i < numSpawnOnDestroy; i++)
274  {
275  SCR_BaseSpawnable spawnObject = destroySpawnObjects[i];
276  if (m_iDestructionBaseDataIndex != -1)
277  spawnObject.Spawn(GetOwner(), ownerPhysics, GetDestructionBaseData().GetHitInfo(false));
278  else
279  spawnObject.Spawn(GetOwner(), ownerPhysics, null);
280  }
281  }
282 
283  //------------------------------------------------------------------------------------------------
286  {
287  if (Replication.IsClient())
288  return;
289 
290  SCR_AIWorld aiWorld = SCR_AIWorld.Cast(GetGame().GetAIWorld());
291 
292  if (!aiWorld)
293  return;
294 
295  array<ref Tuple2<vector, vector>> areas = {};
296  array<bool> redoRoads = {};
297  aiWorld.GetNavmeshRebuildAreas(GetOwner(), areas, redoRoads); // Get area with current phase
298  GetGame().GetCallqueue().CallLater(aiWorld.RequestNavmeshRebuildAreas, 1000, false, areas, redoRoads); // Rebuild later with new phase/when this object is destroyed
299  }
300 
301  //------------------------------------------------------------------------------------------------
304  {
305  if (GetOwner().IsDeleted())
306  return;
307 
308  SpawnDestroyObjects(null);
309  PlaySound();
311  }
312 
313  //------------------------------------------------------------------------------------------------
316  {
317  }
318 
319  //------------------------------------------------------------------------------------------------
326  void NetReceiveHitData(int hitIndex, EDamageType damageType, float damage, vector hitPosition, vector hitDirection)
327  {
328  }
329 
330  //------------------------------------------------------------------------------------------------
333  void NetReadInit(ScriptBitReader reader)
334  {
335  }
336 
337  //------------------------------------------------------------------------------------------------
340  void NetWriteInit(ScriptBitWriter writer)
341  {
342  }
343 
344  //------------------------------------------------------------------------------------------------
346  void PlaySound()
347  {
348  }
349 
350  //------------------------------------------------------------------------------------------------
353  void SetModel(ResourceName model)
354  {
355  Resource resource = Resource.Load(model);
356  VObject asset = null;
357  if (resource.IsValid())
358  {
359  BaseResourceObject resourceObject = resource.GetResource();
360  if (resourceObject)
361  asset = resourceObject.ToVObject();
362  }
363 
364  GetOwner().SetObject(asset, "");
365  GetOwner().Update();
366 
367  Physics phys = GetOwner().GetPhysics();
368  if (!phys)
369  return;
370 
371  // Update physics geometries after mesh change
372  if (!phys.UpdateGeometries())
373  phys.Destroy();// No geoms found, destroy physics
374  }
375 
376  //------------------------------------------------------------------------------------------------
379  void ReplicateDestructibleState(bool forceUpdate = false)
380  {
381  }
382 
383  //------------------------------------------------------------------------------------------------
385  [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
386  private void RPC_QueueDestroy(bool totalDestruction, float lastHealth, float hitDamage, EDamageType damageType, vector hitPosition, vector hitDirection, vector hitNormal)
387  {
389  CreateDestructionHitInfo(totalDestruction, lastHealth, hitDamage, damageType, hitPosition, hitDirection, hitNormal);
390  QueueDestroy();
391 
393  }
394 
395  //------------------------------------------------------------------------------------------------
396  protected RplComponent FindParentRplComponent()
397  {
398  IEntity parent = GetOwner().GetParent();
399  RplComponent currentRplComponent;
400  while (parent)
401  {
402  currentRplComponent = RplComponent.Cast(parent.FindComponent(RplComponent));
403  parent = parent.GetParent();
404  }
405 
406  return currentRplComponent;
407  }
408 
409  //------------------------------------------------------------------------------------------------
410  protected void PassDamageToChildren(notnull BaseDamageContext damageContext)
411  {
412  IEntity child = GetOwner().GetChildren();
413  while (child)
414  {
415  SCR_DestructionDamageManagerComponent destructionComponent = SCR_DestructionDamageManagerComponent.Cast(child.FindComponent(SCR_DestructionDamageManagerComponent));
416  if (!destructionComponent)
417  {
418  child = child.GetSibling();
419  continue;
420  }
421 
422  IEntity currentChild = child;
423  child = child.GetSibling();
424 
425  BaseDamageContext childContext = BaseDamageContext.Cast(damageContext.Clone());
426  childContext.hitEntity = currentChild;
427 
428  destructionComponent.HandleDamage(childContext);
429  }
430  }
431 
432  //------------------------------------------------------------------------------------------------
434  bool IsProxy()
435  {
436  RplComponent rplComponent = RplComponent.Cast(GetOwner().FindComponent(RplComponent));
437  return (rplComponent && rplComponent.IsProxy());
438  }
439 
440  //------------------------------------------------------------------------------------------------
443  {
444  Physics physics = GetOwner().GetPhysics();
445  int responseIndex = physics.GetResponseIndex();
446  if (responseIndex <= MIN_DESTRUCTION_RESPONSE_INDEX)
447  return; // Cannot go lower
448 
449  float healthPercentage = GetHealth() / GetMaxHealth();
450  int minMaxDiff = MAX_DESTRUCTION_RESPONSE_INDEX - MIN_DESTRUCTION_RESPONSE_INDEX + 1;
451 
452  responseIndex = Math.ClampInt(MIN_DESTRUCTION_RESPONSE_INDEX - 1 + Math.Ceil(minMaxDiff * healthPercentage), MIN_DESTRUCTION_RESPONSE_INDEX, responseIndex);
453  physics.SetResponseIndex(responseIndex);
454  }
455 
456  //------------------------------------------------------------------------------------------------
457  override bool OnContact(IEntity owner, IEntity other, Contact contact)
458  {
459  if (GetDestroyed())
460  return false;
461 
462  if (!GetCanBeDamaged())
463  return false;
464 
465  if (IsProxy())
466  return false;
467  if (other && other.IsInherited(SCR_DebrisSmallEntity)) // Ignore impacts from debris
468  return false;
469 
471  if (!componentData)
472  return false;
473 
474  // Get the physics of the dynamic object (if owner is static, then we use the other object instead)
475  Physics physics = contact.Physics1;
476  int responseIndex = physics.GetResponseIndex();
477  float ownerMass = physics.GetMass();
478  float otherMass;
479  int ownerReponseIndex = physics.GetResponseIndex();
480  int otherResponseIndex;
481  if (!physics.IsDynamic())
482  {
483  physics = contact.Physics2;
484  if (!physics)
485  return false; // This only happens with ragdolls, other objects do have physics here, as collision only happens between physical objects
486 
487  otherMass = physics.GetMass();
488  otherResponseIndex = physics.GetResponseIndex();
489  }
490  else
491  {
492  Physics otherPhysics = other.GetPhysics();
493  if (!otherPhysics)
494  return false; // This only happens with ragdolls, other objects do have physics here, as collision only happens between physical objects
495 
496  otherMass = otherPhysics.GetMass();
497  otherResponseIndex = otherPhysics.GetResponseIndex();
498  }
499 
500  float momentum = CalculateMomentum(contact, ownerMass, otherMass);
501 
502  // Now get the relative force, which is the impulse divided by the mass of the dynamic object
503  float relativeForce = 0;
504  if (physics.IsDynamic())
505  {
506  relativeForce = contact.Impulse / physics.GetMass();
507  //We divide the relative force by 20, because for some reason, objects with this response index receive ~20x bigger impulse
508  //TODO: investigate @matousvoj1
509  if (responseIndex >= MIN_DESTRUCTION_RESPONSE_INDEX && responseIndex <= MAX_DESTRUCTION_RESPONSE_INDEX)
510  relativeForce *= 0.05;
511  }
512 
513  if (relativeForce < componentData.m_fRelativeContactForceThresholdMinimum) // Below minimum threshold, ignore
514  return false;
515 
516  vector outMat[3];
517  vector relVel = contact.VelocityBefore2 - contact.VelocityBefore1;
518  outMat[0] = contact.Position; // Hit position
519  outMat[1] = relVel.Normalized(); // Hit direction
520  outMat[2] = contact.Normal; // Hit normal
521 
522  //If vehicle response index is the same or higher -> automatically destroy
523  if (otherResponseIndex - MIN_MOMENTUM_RESPONSE_INDEX >= ownerReponseIndex - MIN_DESTRUCTION_RESPONSE_INDEX)
524  {
525  SCR_DamageContext damageContext = new SCR_DamageContext(EDamageType.COLLISION, GetMaxHealth(), outMat, GetOwner(), null,Instigator.CreateInstigator(other), null, -1, -1);
526 
527  HandleDamage(damageContext); //Immediately destroy, otherwise the other object goes right through
528  }
529  else
530  {
531  //Vehicle response index is smaller -> just deal damage
532  //float damage = relativeForce * componentData.m_fForceToDamageScale;
533  float damage = momentum * componentData.m_fMomentumToDamageScale;
534 
535  SCR_DamageContext damageContext = new SCR_DamageContext(EDamageType.COLLISION, damage, outMat, GetOwner(), null,Instigator.CreateInstigator(other), null, -1, -1);
536 
537  // Send damage to damage handling
538  HandleDamage(damageContext);
539  }
540 
541  return true;
542  }
543 
544  //------------------------------------------------------------------------------------------------
545  override void OnDamage(notnull BaseDamageContext damageContext)
546  {
547  super.OnDamage(damageContext);
548 
550  if (!componentData)
551  return;
552 
553  if (componentData.m_bPassDamageToChildren)
554  PassDamageToChildren(damageContext);
555 
556  if (m_iDestructionBaseDataIndex != -1)
557  {
558  ScriptInvoker onDamage = GetDestructionBaseData().GetOnDamage(false);
559  if (onDamage)
560  onDamage.Invoke();
561  }
562 
563  if (IsProxy())
564  return;
565 
566  if (!GetDestroyed())
567  {
568  GetDestructionBaseData().SetPreviousHealth(GetHealth());
570  return;
571  }
572 
573  Physics physics = GetOwner().GetPhysics();
574  if (physics)
575  {
576  if (physics.IsDynamic() && !physics.IsActive()) // Wake the object up if sleeping
577  physics.ApplyImpulse(vector.Up * physics.GetMass() * 0.001); // Applying impulse instead of SetActive, as we don't want to override ActiveState.ALWAYS_ACTIVE if set
578 
579  // Should disable physics on destroy
581  physics.SetInteractionLayer(EPhysicsLayerDefs.VehicleCast);
582  }
583 
584  float previousHealth;
585  if (m_iDestructionBaseDataIndex != -1)
586  previousHealth = GetDestructionBaseData().GetPreviousHealth();
587 
588  CreateDestructionHitInfo(damageContext.damageValue >= componentData.m_fDamageThresholdMaximum, previousHealth, damageContext.damageValue, damageContext.damageType, damageContext.hitPosition, damageContext.hitDirection, damageContext.hitNormal);
589 
590  QueueDestroy();
591 
592  SCR_DestructionHitInfo destructionHitInfo = GetDestructionHitInfo();
593  if (!destructionHitInfo)
594  return;
595 
596  if (!IsDestructionQueued())
597  {
598  Rpc(RPC_QueueDestroy, destructionHitInfo.m_TotalDestruction, destructionHitInfo.m_LastHealth, destructionHitInfo.m_HitDamage, destructionHitInfo.m_DamageType, destructionHitInfo.m_HitPosition, destructionHitInfo.m_HitDirection, destructionHitInfo.m_HitNormal);
599 
600  GetGame().GetCallqueue().CallLater(HandleDestruction); // Replaces OnFrame call, prevents crash when damage is dealt async/from physics step
601  GetDestructionBaseData().SetDestructionQueued(true);
602  }
603  }
604 
605  //------------------------------------------------------------------------------------------------
608  {
609  return GetDestructionBaseData().GetDestructionQueued();
610  }
611 
612  //------------------------------------------------------------------------------------------------
615  {
617  if (!componentData)
618  return 3000;
619 
620  return componentData.m_fDamageThresholdMaximum;
621  }
622 
623  //------------------------------------------------------------------------------------------------
624  override void OnPostInit(IEntity owner)
625  {
626  super.OnPostInit(owner);
627  SetEventMask(owner, EntityEvent.CONTACT);
628 
629  if (!GetDefaultHitZone())
630  return;
631 
633  if (!componentData)
634  {
635  Print("Component data is null!", LogLevel.ERROR);
636  return;
637  }
638 
639  SetHitZoneHealth(componentData.m_fBaseHealth);
640  InitDestruction();
641  }
642 
643  //------------------------------------------------------------------------------------------------
645  {
646 #ifdef WORKBENCH
647  s_bPrintMissingComponent = false;
648  s_bPrintMissingPlayerController = false;
649  s_bPrintInitializationFailed = false;
650 #endif
651 
652  if (m_iDestructionBaseDataIndex != -1)
654  }
655 #endif
656 }
657 
660 {
661  float m_LastHealth;
662  float m_HitDamage;
663  EDamageType m_DamageType;
664  vector m_HitPosition;
665  vector m_HitDirection;
666  vector m_HitNormal;
667 }
668 
670 class SCR_DestructionHitInfo : SCR_HitInfo
671 {
672  bool m_TotalDestruction;
673 
674  //------------------------------------------------------------------------------------------------
679  static SCR_DestructionHitInfo FromHitInfo(SCR_HitInfo hitInfo, bool totalDestruction)
680  {
681  SCR_DestructionHitInfo destHitInfo = new SCR_DestructionHitInfo;
682  destHitInfo.m_TotalDestruction = totalDestruction;
683  destHitInfo.m_LastHealth = hitInfo.m_LastHealth;
684  destHitInfo.m_HitDamage = hitInfo.m_HitDamage;
685  destHitInfo.m_DamageType = hitInfo.m_DamageType;
686  destHitInfo.m_HitPosition = hitInfo.m_HitPosition;
687  destHitInfo.m_HitDirection = hitInfo.m_HitDirection;
688  destHitInfo.m_HitNormal = hitInfo.m_HitNormal;
689  return destHitInfo;
690  }
691 
692  //------------------------------------------------------------------------------------------------
696  static SCR_DestructionHitInfo FromDestructionData(SCR_DestructionData destructionData)
697  {
698  SCR_DestructionHitInfo destructionHitInfo = new SCR_DestructionHitInfo();
699  destructionHitInfo.m_TotalDestruction = destructionData.m_bTotalDestruction;
700  destructionHitInfo.m_HitDamage = destructionData.m_fHitDamage;
701  destructionHitInfo.m_DamageType = destructionData.m_eDamageType;
702  destructionHitInfo.m_HitPosition = destructionData.m_vHitPosition;
703  destructionHitInfo.m_HitDirection = destructionData.m_vHitDirection;
704  destructionHitInfo.m_HitNormal = destructionData.m_vHitNormal;
705  return destructionHitInfo;
706  }
707 }
708 
709 class SCR_Spawnable_SmallDebrisTitle : BaseContainerCustomTitle
710 {
711  override bool _WB_GetCustomTitle(BaseContainer source, out string title)
712  {
713  title = "Small Debris";
714  return true;
715  }
716 }
717 
718 class SCR_Spawnable_PrefabTitle : BaseContainerCustomTitle
719 {
720  override bool _WB_GetCustomTitle(BaseContainer source, out string title)
721  {
722  title = "Prefab";
723  return true;
724  }
725 }
726 
727 class SCR_Spawnable_ParticleTitle : BaseContainerCustomTitle
728 {
729  override bool _WB_GetCustomTitle(BaseContainer source, out string title)
730  {
731  title = "Particle Effect";
732  return true;
733  }
734 }
735 
737 class SCR_BaseSpawnable
738 {
739  [Attribute("0 0 0", UIWidgets.Coords, desc: "Positional offset (in local space to the destructible)")]
740  protected vector m_vOffsetPosition;
741  [Attribute("0 0 0", UIWidgets.Coords, desc: "Yaw, pitch & roll offset (in local space to the destructible)")]
742  protected vector m_vOffsetRotation;
743 
744 #ifdef WORKBENCH
745  //------------------------------------------------------------------------------------------------
750  void SetVariables(WorldEditorAPI api, IEntitySource source, array<ref ContainerIdPathEntry> path, int index)
751  {
752  if (source.GetResourceName().Contains("BrickWall_01/BrickWall_01_white_2m.et"))
753  Print("BROKEN");
754 
755  // Set all variables of the spawn object
756  api.SetVariableValue(source, path, "m_vOffsetPosition", string.Format("%1 %2 %3", m_vOffsetPosition[0], m_vOffsetPosition[1], m_vOffsetPosition[2]));
757  api.SetVariableValue(source, path, "m_vOffsetRotation", string.Format("%1 %2 %3", m_vOffsetRotation[0], m_vOffsetRotation[1], m_vOffsetRotation[2]));
758  }
759 
760  //------------------------------------------------------------------------------------------------
763  bool CompareAttributes(SCR_BaseSpawnable other)
764  {
765  if (other.m_vOffsetPosition != m_vOffsetPosition)
766  return false;
767 
768  if (other.m_vOffsetRotation != m_vOffsetRotation)
769  return false;
770 
771  return true;
772  }
773 
774  //------------------------------------------------------------------------------------------------
780  bool AlreadyExists(WorldEditorAPI api, IEntitySource source, int index)
781  {
782  array<ref BaseDestructionPhase> phases = {};
783  source.Get("DamagePhases", phases);
784 
785  if (phases && phases.IsIndexValid(index))
786  {
788  for (int i = phase.m_aPhaseDestroySpawnObjects.Count() - 1; i >= 0; i--)
789  {
790  if (phase.m_aPhaseDestroySpawnObjects[i].Type() == Type())
791  {
792  if (CompareAttributes(phase.m_aPhaseDestroySpawnObjects[i]))
793  return true;
794  }
795  }
796  }
797 
798  return false;
799  }
800 
801  //------------------------------------------------------------------------------------------------
808  bool CreateObject(WorldEditorAPI api, IEntitySource source, array<ref ContainerIdPathEntry> path, int index)
809  {
810  if (!AlreadyExists(api, source, index))
811  {
812  api.CreateObjectArrayVariableMember(source, path, "m_aPhaseDestroySpawnObjects", "SCR_BaseSpawnable", index);
813  return true;
814  }
815 
816  return false;
817  }
818 
819  //------------------------------------------------------------------------------------------------
826  void CopyToSource(WorldEditorAPI api, IEntitySource source, array<ref ContainerIdPathEntry> path, int index, string currentObjectName)
827  {
828  if (!CreateObject(api, source, path, index))
829  return;
830 
831  // Change the path to the current spawn object
832  int last = path.Insert(new ContainerIdPathEntry(currentObjectName, index));
833 
834  SetVariables(api, source, path, index);
835 
836  path.Remove(last);
837  }
838 #endif
839 
840  //------------------------------------------------------------------------------------------------
845  void GetSpawnTransform(IEntity owner, out vector outMat[4], bool localCoords = false)
846  {
847  if (localCoords)
848  {
849  Math3D.AnglesToMatrix(m_vOffsetRotation, outMat);
850  // TODO: Remove hotfix for sleeping/static object
851  if (m_vOffsetPosition == vector.Zero)
852  outMat[3] = vector.Up * 0.001;
853  else
854  outMat[3] = m_vOffsetPosition;
855  }
856  else
857  {
858  vector localMat[4], parentMat[4];
859  owner.GetWorldTransform(parentMat);
860  Math3D.AnglesToMatrix(m_vOffsetRotation, localMat);
861  localMat[3] = m_vOffsetPosition;
862 
863  Math3D.MatrixMultiply4(parentMat, localMat, outMat);
864  }
865  }
866 
867  //------------------------------------------------------------------------------------------------
874  IEntity Spawn(IEntity owner, Physics parentPhysics, SCR_HitInfo hitInfo, bool snapToTerrain = false)
875  {
876  return null;
877  }
878 }
879 
880 //------------------------------------------------------------------------------------------------
882 class SCR_DebrisSpawnable : SCR_BaseSpawnable
883 {
884  [Attribute(ResourceName.Empty, UIWidgets.ResourcePickerThumbnail, "Debris model prefabs to spawn (spawns ALL of them)", "et xob")]
885  ref array<ResourceName> m_ModelPrefabs;
886 
887  [Attribute("10", UIWidgets.Slider, "Mass of the debris", "0.01 1000 0.01")]
888  float m_fMass;
889 
890  [Attribute("5", UIWidgets.Slider, "Minimum lifetime value for the debris (in s)", "0 3600 0.5")]
891  float m_fLifetimeMin;
892 
893  [Attribute("10", UIWidgets.Slider, "Maximum lifetime value for the debris (in s)", "0 3600 0.5")]
894  float m_fLifetimeMax;
895 
896  [Attribute("200", UIWidgets.Slider, "Maximum distance from camera above which the debris is not spawned (in m)", "0 3600 0.5")]
897  float m_fDistanceMax;
898 
899  [Attribute("0", UIWidgets.Slider, "Higher priority overrides lower priority if at or over debris limit", "0 100 1")]
900  int m_fPriority;
901 
902  [Attribute("0.1", UIWidgets.Slider, "Damage received to physics impulse (speed / mass) multiplier", "0 10000 0.01")]
903  float m_fDamageToImpulse;
904 
905  [Attribute("2", UIWidgets.Slider, "Damage to speed multiplier, used when objects get too much damage to impulse", "0 10000 0.01")]
906  float m_fMaxDamageToSpeedMultiplier;
907 
908  [Attribute("0.5", UIWidgets.Slider, "Random linear velocity multiplier (m/s)", "0 200 0.1")]
909  float m_fRandomVelocityLinear;
910 
911  [Attribute("180", UIWidgets.Slider, "Random angular velocity multiplier (deg/s)", "0 3600 0.1")]
912  float m_fRandomVelocityAngular;
913 
914  [Attribute("0", uiwidget: UIWidgets.ComboBox, "Type of material for debris sound", "", ParamEnumArray.FromEnum(SCR_EMaterialSoundTypeDebris))]
915  SCR_EMaterialSoundTypeDebris m_eMaterialSoundType;
916 
917 #ifdef WORKBENCH
918  //------------------------------------------------------------------------------------------------
919  override bool CompareAttributes(SCR_BaseSpawnable other)
920  {
921  SCR_DebrisSpawnable otherDebris = SCR_DebrisSpawnable.Cast(other);
922 
923  if (!super.CompareAttributes(other))
924  return false;
925 
926  if (otherDebris.m_ModelPrefabs != m_ModelPrefabs)
927  return false;
928 
929  if (otherDebris.m_fLifetimeMin != m_fLifetimeMin)
930  return false;
931 
932  if (otherDebris.m_fLifetimeMax != m_fLifetimeMax)
933  return false;
934 
935  if (otherDebris.m_fDistanceMax != m_fDistanceMax)
936  return false;
937 
938  if (otherDebris.m_fPriority != m_fPriority)
939  return false;
940 
941  if (otherDebris.m_fDamageToImpulse != m_fDamageToImpulse)
942  return false;
943 
944  if (otherDebris.m_fMaxDamageToSpeedMultiplier != m_fMaxDamageToSpeedMultiplier)
945  return false;
946 
947  if (otherDebris.m_fRandomVelocityLinear != m_fRandomVelocityLinear)
948  return false;
949 
950  if (otherDebris.m_fRandomVelocityAngular != m_fRandomVelocityAngular)
951  return false;
952 
953  if (otherDebris.m_eMaterialSoundType != m_eMaterialSoundType)
954  return false;
955 
956  return true;
957  }
958 
959  //------------------------------------------------------------------------------------------------
960  override void SetVariables(WorldEditorAPI api, IEntitySource source, array<ref ContainerIdPathEntry> path, int index)
961  {
962  super.SetVariables(api, source, path, index);
963 
964  string prefabsArray = "";
965  // Set all variables of the spawn object
966  for (int i = 0, count = m_ModelPrefabs.Count(); i < count; i++)
967  {
968  prefabsArray += m_ModelPrefabs[i];
969 
970  if (i != count - 1) // Not last item
971  prefabsArray += ",";
972  }
973 
974  api.SetVariableValue(source, path, "m_ModelPrefabs", prefabsArray);
975 
976  api.SetVariableValue(source, path, "m_fMass", m_fMass.ToString());
977  api.SetVariableValue(source, path, "m_fLifetimeMin", m_fLifetimeMin.ToString());
978  api.SetVariableValue(source, path, "m_fLifetimeMax", m_fLifetimeMax.ToString());
979  api.SetVariableValue(source, path, "m_fDistanceMax", m_fDistanceMax.ToString());
980  api.SetVariableValue(source, path, "m_fPriority", m_fPriority.ToString());
981  api.SetVariableValue(source, path, "m_fDamageToImpulse", m_fDamageToImpulse.ToString());
982  api.SetVariableValue(source, path, "m_fMaxDamageToSpeedMultiplier", m_fMaxDamageToSpeedMultiplier.ToString());
983  api.SetVariableValue(source, path, "m_fRandomVelocityLinear", m_fRandomVelocityLinear.ToString());
984  api.SetVariableValue(source, path, "m_fRandomVelocityAngular", m_fRandomVelocityAngular.ToString());
985  api.SetVariableValue(source, path, "m_eMaterialSoundType", m_eMaterialSoundType.ToString());
986  }
987 
988  //------------------------------------------------------------------------------------------------
989  override bool CreateObject(WorldEditorAPI api, IEntitySource source, array<ref ContainerIdPathEntry> path, int index)
990  {
991  if (!AlreadyExists(api, source, index))
992  {
993  api.CreateObjectArrayVariableMember(source, path, "m_aPhaseDestroySpawnObjects", "SCR_DebrisSpawnable", index);
994  return true;
995  }
996 
997  return false;
998  }
999 #endif
1000 
1001  //------------------------------------------------------------------------------------------------
1002  override IEntity Spawn(IEntity owner, Physics parentPhysics, SCR_HitInfo hitInfo, bool snapToTerrain = false)
1003  {
1004  if (!hitInfo)
1005  return null;
1006 
1007  int numModelPrefabs = 0;
1008  if (m_ModelPrefabs)
1009  numModelPrefabs = m_ModelPrefabs.Count();
1010 
1011  for (int i = 0; i < numModelPrefabs; i++)
1012  {
1013  ResourceName prefabPath = m_ModelPrefabs[i];
1014 
1015  ResourceName modelPath;
1016  string remap;
1017  SCR_Global.GetModelAndRemapFromResource(prefabPath, modelPath, remap);
1018 
1019  if (modelPath == ResourceName.Empty)
1020  continue;
1021 
1022  vector spawnMat[4];
1023  GetSpawnTransform(owner, spawnMat);
1024 
1025  SCR_DestructionDamageManagerComponent destructionComponent = SCR_DestructionDamageManagerComponent.Cast(owner.FindComponent(SCR_DestructionDamageManagerComponent));
1026 
1027  float dmgSpeed = Math.Clamp(hitInfo.m_HitDamage * m_fDamageToImpulse / m_fMass, 0, m_fMaxDamageToSpeedMultiplier);
1028 
1029  vector linearVelocity = hitInfo.m_HitDirection * Math.RandomFloat(0, 1);
1030  linearVelocity += Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * m_fRandomVelocityLinear;
1031  linearVelocity *= dmgSpeed;
1032  vector angularVelocity = Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * Math.RandomFloat(0.25, 4) * m_fRandomVelocityAngular;
1033  angularVelocity *= dmgSpeed;
1034 
1035  if (parentPhysics)
1036  {
1037  linearVelocity += parentPhysics.GetVelocity();
1038  angularVelocity += parentPhysics.GetAngularVelocity();
1039  }
1040 #ifdef ENABLE_BASE_DESTRUCTION
1041  SCR_DebrisSmallEntity.SpawnDebris(owner.GetWorld(), spawnMat, modelPath, m_fMass, Math.RandomFloat(m_fLifetimeMin, m_fLifetimeMax), m_fDistanceMax, m_fPriority, linearVelocity, angularVelocity, remap, false, m_eMaterialSoundType);
1042 #endif
1043  }
1044 
1045  return null;
1046  }
1047 }
1048 
1049 [BaseContainerProps(), SCR_Spawnable_PrefabTitle()]
1050 class SCR_PrefabSpawnable : SCR_BaseSpawnable
1051 {
1052  [Attribute(ResourceName.Empty, UIWidgets.ResourcePickerThumbnail, "Prefabs to spawn (spawns ALL of them)", "et")]
1053  ref array<ResourceName> m_Prefabs;
1054 
1055  [Attribute("0.1", UIWidgets.Slider, "Damage received to physics impulse (speed / mass) multiplier", "0 10000 0.01")]
1056  float m_fDamageToImpulse;
1057 
1058  [Attribute("0.25", UIWidgets.Slider, "Random linear velocity multiplier (m/s)", "0 200 0.1")]
1060 
1061  [Attribute("45", UIWidgets.Slider, "Random angular velocity multiplier (deg/s)", "0 3600 0.1")]
1063 
1064  [Attribute("0", UIWidgets.CheckBox, "Whether the spawned prefabs should be set as children (sets auto-transform)")]
1065  bool m_bSpawnAsChildren;
1066 
1067 #ifdef WORKBENCH
1068  //------------------------------------------------------------------------------------------------
1069  override bool CompareAttributes(SCR_BaseSpawnable other)
1070  {
1071  SCR_PrefabSpawnable otherPrefab = SCR_PrefabSpawnable.Cast(other);
1072 
1073  if (!super.CompareAttributes(other))
1074  return false;
1075 
1076  int count = m_Prefabs.Count();
1077  if (otherPrefab.m_Prefabs.Count() != count)
1078  return false;
1079 
1080  for (int i = count - 1; i >= 0; i--)
1081  {
1082  if (otherPrefab.m_Prefabs[i] != m_Prefabs[i])
1083  return false;
1084  }
1085 
1086  if (otherPrefab.m_fDamageToImpulse != m_fDamageToImpulse)
1087  return false;
1088 
1089  if (otherPrefab.m_fRandomVelocityLinear != m_fRandomVelocityLinear)
1090  return false;
1091 
1092  if (otherPrefab.m_fRandomVelocityAngular != m_fRandomVelocityAngular)
1093  return false;
1094 
1095  if (otherPrefab.m_bSpawnAsChildren != m_bSpawnAsChildren)
1096  return false;
1097 
1098  return true;
1099  }
1100 
1101  //------------------------------------------------------------------------------------------------
1102  override void SetVariables(WorldEditorAPI api, IEntitySource source, array<ref ContainerIdPathEntry> path, int index)
1103  {
1104  super.SetVariables(api, source, path, index);
1105 
1106  string prefabsArray = "";
1107  // Set all variables of the spawn object
1108  for (int i = 0, count = m_Prefabs.Count(); i < count; i++)
1109  {
1110  prefabsArray += m_Prefabs[i];
1111 
1112  if (i != count - 1) // Not last item
1113  prefabsArray += ",";
1114  }
1115 
1116  api.SetVariableValue(source, path, "m_Prefabs", prefabsArray);
1117 
1118  api.SetVariableValue(source, path, "m_fDamageToImpulse", m_fDamageToImpulse.ToString());
1119  api.SetVariableValue(source, path, "m_fRandomVelocityLinear", m_fRandomVelocityLinear.ToString());
1120  api.SetVariableValue(source, path, "m_fRandomVelocityAngular", m_fRandomVelocityAngular.ToString());
1121  api.SetVariableValue(source, path, "m_bSpawnAsChildren", m_bSpawnAsChildren.ToString(true));
1122  }
1123 
1124  //------------------------------------------------------------------------------------------------
1125  override bool CreateObject(WorldEditorAPI api, IEntitySource source, array<ref ContainerIdPathEntry> path, int index)
1126  {
1127  if (!AlreadyExists(api, source, index))
1128  {
1129  api.CreateObjectArrayVariableMember(source, path, "m_aPhaseDestroySpawnObjects", "SCR_PrefabSpawnable", index);
1130  return true;
1131  }
1132 
1133  return false;
1134  }
1135 #endif
1136 
1137  //------------------------------------------------------------------------------------------------
1138  override IEntity Spawn(IEntity owner, Physics parentPhysics, SCR_HitInfo hitInfo, bool snapToTerrain = false)
1139  {
1140  if (!hitInfo)
1141  return null;
1142 
1143  int numModelPrefabs = 0;
1144  if (m_Prefabs)
1145  numModelPrefabs = m_Prefabs.Count();
1146 
1147  for (int i = 0; i < numModelPrefabs; i++)
1148  {
1149  ResourceName prefabPath = m_Prefabs[i];
1150 
1151  bool isPrefab;
1152  if (SCR_Global.GetResourceContainsComponent(prefabPath, "RplComponent", isPrefab) && RplSession.Mode() == RplMode.Client)
1153  continue;
1154 
1155  if (!isPrefab)
1156  continue;
1157 
1158  vector spawnMat[4];
1159  GetSpawnTransform(owner, spawnMat, m_bSpawnAsChildren);
1160 
1161  EntitySpawnParams prefabSpawnParams = EntitySpawnParams();
1162  prefabSpawnParams.Transform = spawnMat;
1163  IEntity spawnedPrefab = GetGame().SpawnEntityPrefab(Resource.Load(prefabPath), null, prefabSpawnParams);
1164  if (!spawnedPrefab)
1165  continue;
1166 
1167  if (m_bSpawnAsChildren)
1168  {
1169  owner.AddChild(spawnedPrefab, -1, EAddChildFlags.AUTO_TRANSFORM);
1170  continue;
1171  }
1172 
1173  Physics prefabPhysics = spawnedPrefab.GetPhysics();
1174  if (!prefabPhysics || !prefabPhysics.IsDynamic())
1175  continue;
1176 
1177  float dmgSpeed = hitInfo.m_HitDamage * m_fDamageToImpulse / prefabPhysics.GetMass();
1178 
1179  vector linearVelocity = hitInfo.m_HitDirection * Math.RandomFloat(0, 1);
1180  linearVelocity += Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * m_fRandomVelocityLinear;
1181  linearVelocity *= dmgSpeed;
1182  vector angularVelocity = Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * Math.RandomFloat(0.25, 4) * m_fRandomVelocityAngular;
1183  angularVelocity *= dmgSpeed;
1184 
1185  if (parentPhysics)
1186  {
1187  linearVelocity += parentPhysics.GetVelocity();
1188  angularVelocity += parentPhysics.GetAngularVelocity();
1189  }
1190 
1191  prefabPhysics.SetVelocity(linearVelocity);
1192  prefabPhysics.SetAngularVelocity(angularVelocity * Math.DEG2RAD);
1193  }
1194 
1195  return null; // We spawned multiple entities
1196  }
1197 }
1198 
1200 class SCR_ParticleSpawnable : SCR_BaseSpawnable
1201 {
1202  [Attribute(ResourceName.Empty, UIWidgets.ResourceNamePicker, "Particle effect to spawn", "ptc")]
1203  ResourceName m_Particle;
1204  [Attribute("1", UIWidgets.CheckBox, "If true, the particle effect will play at the object's bounding box instead of at its origin")]
1205  bool m_bAtCenter;
1206 
1207  [Attribute("1", desc: "If true, the particle effect will play rotated in the hit direction.")]
1208  bool m_bDirectional;
1209 
1210 #ifdef WORKBENCH
1211  //------------------------------------------------------------------------------------------------
1212  override bool CompareAttributes(SCR_BaseSpawnable other)
1213  {
1214  SCR_ParticleSpawnable otherParticle = SCR_ParticleSpawnable.Cast(other);
1215 
1216  if (!super.CompareAttributes(other))
1217  return false;
1218 
1219  if (otherParticle.m_Particle != m_Particle)
1220  return false;
1221 
1222  if (otherParticle.m_bAtCenter != m_bAtCenter)
1223  return false;
1224 
1225  if (otherParticle.m_bDirectional != m_bDirectional)
1226  return false;
1227 
1228  return true;
1229  }
1230  //------------------------------------------------------------------------------------------------
1231  override void SetVariables(WorldEditorAPI api, IEntitySource source, array<ref ContainerIdPathEntry> path, int index)
1232  {
1233  super.SetVariables(api, source, path, index);
1234 
1235  // Set all variables of the spawn object
1236  api.SetVariableValue(source, path, "m_Particle", m_Particle);
1237  api.SetVariableValue(source, path, "m_bAtCenter", m_bAtCenter.ToString(true));
1238  api.SetVariableValue(source, path, "m_bDirectional", m_bDirectional.ToString(true));
1239  }
1240 
1241  //------------------------------------------------------------------------------------------------
1242  override bool CreateObject(WorldEditorAPI api, IEntitySource source, array<ref ContainerIdPathEntry> path, int index)
1243  {
1244  if (!AlreadyExists(api, source, index))
1245  {
1246  api.CreateObjectArrayVariableMember(source, path, "m_aPhaseDestroySpawnObjects", "SCR_ParticleSpawnable", index);
1247  return true;
1248  }
1249 
1250  return false;
1251  }
1252 #endif
1253 
1254  //------------------------------------------------------------------------------------------------
1260  ParticleEffectEntity SpawnAsChild(IEntity owner, SCR_HitInfo hitInfo, bool snapToTerrain = false)
1261  {
1262  if (m_Particle == ResourceName.Empty)
1263  return null;
1264 
1265  vector spawnMat[4];
1266  GetSpawnTransform(owner, spawnMat);
1267 
1268  if (m_bAtCenter)
1269  {
1270  vector mins, maxs;
1271  owner.GetBounds(mins, maxs);
1272  vector center = (maxs - mins) * 0.5 + mins;
1273  spawnMat[3] = center.Multiply4(spawnMat);
1274  }
1275 
1276  vector position = spawnMat[3];
1277  if (snapToTerrain)
1278  {
1279  position[1] = SCR_TerrainHelper.GetTerrainY(position, owner.GetWorld());
1280  spawnMat[3] = position;
1281  }
1282 
1283  if (m_bDirectional)
1284  {
1285  vector newRight, newUp, newForward;
1286 
1287  newUp = -hitInfo.m_HitDirection;
1288  newRight = newUp * spawnMat[2];
1289  newForward = newUp * newRight;
1290 
1291  spawnMat[0] = newRight;
1292  spawnMat[1] = newUp;
1293  spawnMat[2] = newForward;
1294  }
1295 
1296  return SCR_DestructionCommon.PlayParticleEffect_Child(m_Particle, hitInfo.m_DamageType, owner, spawnMat);
1297  }
1298 
1299  //------------------------------------------------------------------------------------------------
1300  override IEntity Spawn(IEntity owner, Physics parentPhysics, SCR_HitInfo hitInfo, bool snapToTerrain = false)
1301  {
1302  if (!hitInfo || m_Particle == ResourceName.Empty)
1303  return null;
1304 
1305  vector spawnMat[4];
1306  GetSpawnTransform(owner, spawnMat);
1307 
1308  if (m_bAtCenter)
1309  {
1310  vector mins, maxs;
1311  owner.GetBounds(mins, maxs);
1312  vector center = (maxs - mins) * 0.5 + mins;
1313  spawnMat[3] = center.Multiply4(spawnMat);
1314  }
1315 
1316  vector position = spawnMat[3];
1317  if (snapToTerrain)
1318  {
1319  position[1] = SCR_TerrainHelper.GetTerrainY(position, owner.GetWorld());
1320  spawnMat[3] = position;
1321  }
1322 
1323  if (m_bDirectional)
1324  {
1325  vector newRight, newUp, newForward;
1326 
1327  newUp = -hitInfo.m_HitDirection;
1328  newRight = newUp * spawnMat[2];
1329  newForward = newUp * newRight;
1330 
1331  spawnMat[0] = newRight;
1332  spawnMat[1] = newUp;
1333  spawnMat[2] = newForward;
1334  }
1335 
1336  return SCR_DestructionCommon.PlayParticleEffect_Transform(m_Particle, hitInfo.m_DamageType, spawnMat);
1337  }
1338 }
SCR_TerrainHelper
Definition: SCR_TerrainHelper.c:1
RPC_QueueDestroy
private void RPC_QueueDestroy(bool totalDestruction, float lastHealth, float hitDamage, EDamageType damageType, vector hitPosition, vector hitDirection, vector hitNormal)
Queue destruction on clients.
Definition: SCR_DestructionBaseComponent.c:386
ReplicateDestructibleState
void ReplicateDestructibleState(bool forceUpdate=false)
Definition: SCR_DestructionBaseComponent.c:379
BaseDamageContext
Definition: BaseDamageContext.c:12
IsProxy
bool IsProxy()
Checks if this entity is locally owned.
Definition: SCR_DestructionBaseComponent.c:434
NetWriteInit
void NetWriteInit(ScriptBitWriter writer)
Definition: SCR_DestructionBaseComponent.c:340
m_ModelPrefabs
ref array< ResourceName > m_ModelPrefabs
Definition: SCR_DestructionBaseComponent.c:698
GetMaxHealth
float GetMaxHealth()
Definition: SCR_DestructibleEntity.c:122
FreeDestructionBaseData
private void FreeDestructionBaseData(int index)
Definition: SCR_DestructionBaseComponent.c:90
_WB_GetCustomTitle
SCR_Spawnable_SmallDebrisTitle BaseContainerCustomTitle _WB_GetCustomTitle(BaseContainer source, out string title)
Definition: SCR_DestructionBaseComponent.c:720
m_fDistanceMax
float m_fDistanceMax
Definition: SCR_DestructionBaseComponent.c:710
CalculateMomentum
float CalculateMomentum(Contact contact, float ownerMass, float otherMass)
Definition: SCR_DestructibleEntity.c:346
HitZone
Definition: HitZone.c:12
QueueDestroy
void QueueDestroy()
Called when the object should be destroyed and various effects or other things need to be performed (...
Definition: SCR_DestructionBaseComponent.c:260
ShouldDestroyParent
bool ShouldDestroyParent()
Definition: SCR_DestructionBaseComponent.c:117
m_fPriority
int m_fPriority
Definition: SCR_DestructionBaseComponent.c:713
SCR_BaseDestructionPhase
Definition: SCR_BaseDestructionPhase.c:1
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
RegenerateNavmeshDelayed
void RegenerateNavmeshDelayed()
Definition: SCR_DestructionBaseComponent.c:285
SCR_EMaterialSoundTypeDebris
SCR_EMaterialSoundTypeDebris
Definition: SCR_DestructionMultiPhaseComponent.c:3
OnDamage
override void OnDamage(notnull BaseDamageContext damageContext)
Definition: SCR_DestructionBaseComponent.c:545
GetDestructionBaseData
protected notnull SCR_DestructionBaseData GetDestructionBaseData()
Definition: SCR_DestructionBaseComponent.c:64
SpawnDestroyObjects
void SpawnDestroyObjects(SCR_HitInfo hitInfo)
Definition: SCR_DestructionBaseComponent.c:267
SetModel
void SetModel(ResourceName model)
Definition: SCR_DestructionBaseComponent.c:353
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
GetDestructionHitInfo
SCR_DestructionHitInfo GetDestructionHitInfo(bool createNew=false)
Definition: SCR_DestructionBaseComponent.c:107
SCR_DestructionBaseData
Definition: SCR_DestructionBaseData.c:2
PassDamageToChildren
protected void PassDamageToChildren(notnull BaseDamageContext damageContext)
Definition: SCR_DestructionBaseComponent.c:410
RplRpc
SCR_AchievementsHandlerClass ScriptComponentClass RplRpc(RplChannel.Reliable, RplRcver.Owner)] void UnlockOnClient(AchievementId achievement)
Definition: SCR_AchievementsHandler.c:11
NetReceiveHitData
void NetReceiveHitData(int hitIndex, EDamageType damageType, float damage, vector hitPosition, vector hitDirection)
Definition: SCR_DestructionBaseComponent.c:326
NetReadInit
void NetReadInit(ScriptBitReader reader)
Definition: SCR_DestructionBaseComponent.c:333
SCR_Spawnable_ParticleTitle
Definition: SCR_DestructionBaseComponent.c:727
Instigator
Definition: Instigator.c:6
SCR_HitInfo
Class to temporarily store information about the last hit that dealt damage.
Definition: SCR_DestructionBaseComponent.c:659
ESetMaxHealthFlags
ESetMaxHealthFlags
Definition: ESetMaxHealthFlags.c:12
AllocateDestructionBaseData
private int AllocateDestructionBaseData()
Definition: SCR_DestructionBaseComponent.c:73
SCR_AIWorld
Definition: SCR_AIWorld.c:23
m_TotalDestruction
class SCR_HitInfo m_TotalDestruction
Class to temporarily store information about the last hit that caused destruction.
SetHitZoneHealth
void SetHitZoneHealth(float baseHealth, bool clearDamage=true)
Definition: SCR_DestructionBaseComponent.c:208
RPC_DoSpawnAllDestroyEffects
void RPC_DoSpawnAllDestroyEffects()
Spawns destroy objects of children as well as own.
Definition: SCR_DestructionBaseComponent.c:153
Spawn
override IEntity Spawn(IEntity owner, Physics parentPhysics, SCR_HitInfo hitInfo, bool snapToTerrain=false)
Definition: SCR_DestructionBaseComponent.c:815
m_Particle
ResourceName m_Particle
Definition: SCR_ParticleContactComponent.c:12
GetHealth
float GetHealth()
Definition: SCR_FuelNode.c:196
~SCR_DestructionDamageManagerComponent
void ~SCR_DestructionDamageManagerComponent()
Definition: SCR_DestructionBaseComponent.c:644
Attribute
typedef Attribute
Post-process effect of scripted camera.
OnContact
override bool OnContact(IEntity owner, IEntity other, Contact contact)
Definition: SCR_DestructionBaseComponent.c:457
GetUndamaged
bool GetUndamaged()
Definition: SCR_DestructionBaseComponent.c:132
s_OnDestructibleDestroyed
SCR_DestructionDamageManagerComponentClass s_OnDestructibleDestroyed
Base destruction component, destruction types extend from this.
SCR_DamageManagerComponentClass
enum ECharacterHitZoneGroup SCR_DamageManagerComponentClass
BaseContainerProps
SCR_Spawnable_ParticleTitle BaseContainerCustomTitle BaseContainerProps()] class SCR_BaseSpawnable
Definition: SCR_DestructionBaseComponent.c:736
SCR_DebrisSmallEntity
Definition: DebrisSmallEntity.c:14
PlaySound
void PlaySound()
Plays sounds upon destruction.
Definition: SCR_DestructionBaseComponent.c:346
OnPostInit
override void OnPostInit(IEntity owner)
Called on PostInit when all components are added.
Definition: SCR_DestructionBaseComponent.c:624
destructible
SCR_DestructionDamageManagerComponent destructible
Definition: SCR_DestructionSynchronizationComponent.c:22
IsDestructionQueued
bool IsDestructionQueued()
Definition: SCR_DestructionBaseComponent.c:607
GetOnDamageInvoker
ScriptInvoker GetOnDamageInvoker()
Returns the on damage script invoker if one exists, otherwise creates one and returns it.
Definition: SCR_DestructionBaseComponent.c:99
SCR_DestructionDamageManagerComponentClass
Definition: SCR_DestructionBaseComponent.c:2
GetCanBeDamaged
bool GetCanBeDamaged()
Called when the object receives damage, return false if damage should be ignored.
Definition: SCR_DestructionBaseComponent.c:253
HandleDestruction
void HandleDestruction()
Handle destruction.
Definition: SCR_DestructionBaseComponent.c:303
DeleteParentWithEffects
void DeleteParentWithEffects()
Definition: SCR_DestructionBaseComponent.c:170
GetOwner
IEntity GetOwner()
Owner entity of the fuel tank.
Definition: SCR_FuelNode.c:128
m_fMaxDamageToSpeedMultiplier
float m_fMaxDamageToSpeedMultiplier
Definition: SCR_DestructionBaseComponent.c:719
m_fMass
SCR_HybridPhysicsComponentClass m_fMass
Class for storing physics setup info for SCR_HybridPhysicsComponent.
SetHitZoneDamage
void SetHitZoneDamage(float damage)
Definition: SCR_DestructionBaseComponent.c:220
FindParentRplComponent
protected RplComponent FindParentRplComponent()
Definition: SCR_DestructionBaseComponent.c:396
index
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
Definition: SCR_DestructionSynchronizationComponent.c:17
GetDestroyed
bool GetDestroyed()
Definition: SCR_DestructionBaseComponent.c:142
SCR_DamageContext
Definition: SCR_DamageContext.c:7
SCR_Global
Definition: Functions.c:6
CreateDestructionHitInfo
void CreateDestructionHitInfo(bool totalDestruction, float lastHealth, float hitDamage, EDamageType damageType, vector hitPosition, vector hitDirection, vector hitNormal)
Definition: SCR_DestructionBaseComponent.c:238
InitDestruction
void InitDestruction()
Initialise destruction.
Definition: SCR_DestructionBaseComponent.c:315
DeleteDestructible
void DeleteDestructible()
Used in cases where we don't care about effects or anything, e. g. building destruction.
Definition: SCR_DestructionBaseComponent.c:183
SCR_Spawnable_SmallDebrisTitle
Definition: SCR_DestructionBaseComponent.c:709
m_fDamageToImpulse
float m_fDamageToImpulse
Definition: SCR_DestructionBaseComponent.c:716
GetTotalDestructionThreshold
float GetTotalDestructionThreshold()
Definition: SCR_DestructionBaseComponent.c:614
EDamageType
EDamageType
Definition: EDamageType.c:12
UpdateResponseIndex
void UpdateResponseIndex()
Definition: SCR_DestructionBaseComponent.c:442
m_iDestructionBaseDataIndex
private int m_iDestructionBaseDataIndex
Definition: SCR_DestructionBaseComponent.c:39
data
Get all prefabs that have the spawner data
Definition: SCR_EntityCatalogManagerComponent.c:305
m_fLifetimeMax
float m_fLifetimeMax
Definition: SCR_DestructionBaseComponent.c:707
SCR_DebrisSpawnable
Definition: SCR_DestructionBaseComponent.c:882
position
vector position
Definition: SCR_DestructibleTreeV2.c:30
SCR_DestructionCommon
Class containing common functions between destructible classes.
Definition: SCR_DestructionCommon.c:7
m_fLifetimeMin
float m_fLifetimeMin
Definition: SCR_DestructionBaseComponent.c:704
m_fRandomVelocityLinear
float m_fRandomVelocityLinear
Definition: SCR_DestructionBaseComponent.c:722
m_eMaterialSoundType
SCR_EMaterialSoundTypeDebris m_eMaterialSoundType
Definition: SCR_DestructionBaseComponent.c:728
GetDisablePhysicsOnDestroy
bool GetDisablePhysicsOnDestroy()
Definition: SCR_DestructionBaseComponent.c:125
SCR_DestructionData
Definition: SCR_DestructibleEntity.c:16
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180
m_fRandomVelocityAngular
float m_fRandomVelocityAngular
Definition: SCR_DestructionBaseComponent.c:725