Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_DestructibleBuildingComponent.c
Go to the documentation of this file.
2 {
3  [Attribute()]
4  ref array<ref SCR_TimedEffect> m_aEffects;
5 
6  [Attribute("0", "Delay in seconds between damage and the beginning of the building transition")]
7  float m_fDelay;
8 
9  [Attribute("1", "Meters per second")]
10  float m_fSinkingSpeed;
11 
12  [Attribute("150", "This speeds up the sinking gradually % per second.", params: "0 10000 1")]
13  float m_fSinkingSpeedGradualMultiplier;
14 
15  [Attribute("0.1", "Degrees per second")]
16  float m_fRotationSpeed;
17 
18  [Attribute("0.8", "Time between rotation changes when building is collapsing in seconds")]
19  float m_fRotationTime;
20 
21  [Attribute("50", "Rotation time randomizer in % - can both shorten/prolong the time", params: "0 10000 1")]
22  float m_fRotationTimeRandom;
23 
24  [Attribute("1", "Max rotations count while sinking")]
25  int m_iMaxRotations;
26 
27  [Attribute(vector.Zero.ToString(), "This vector defines offset for the final position after destruction.")]
28  vector m_vSinkVector;
29 
30  [Attribute("", UIWidgets.Auto, desc: "Slow down event audio source configuration")]
31  ref SCR_AudioSourceConfiguration m_AudioSourceConfiguration;
32 
33  [Attribute(uiwidget: UIWidgets.GraphDialog)]
34  ref Curve m_CameraShakeCurve;
35 
36  [Attribute(uiwidget: UIWidgets.Flags, enums: ParamEnumArray.FromEnum(SCR_EDestructionRotationEnum))]
37  SCR_EDestructionRotationEnum m_eAllowedRotations;
38 }
39 
40 enum SCR_EDestructionRotationEnum
41 {
42  NONE = 0,
43  ROTATION_X = 1,
44  ROTATION_Y = 2,
45  ROTATION_Z = 4
46 }
47 
48 class SCR_BuildingDestructionCameraShakeProgress : SCR_NoisyCameraShakeProgress
49 {
50  protected const float MAX_MULTIPLIER = 1.5;
51  protected float m_fMaxDistance = 50;
52  protected float m_fSizeMultiplier = 1;
53 
54  protected ref Curve m_CameraShakeCurve;
55  protected vector m_vStartOrigin;
56 
57  //------------------------------------------------------------------------------------------------
58  override void Update(IEntity owner, float timeSlice)
59  {
60  if (!IsRunning())
61  return;
62 
63  super.Update(owner, timeSlice);
64 
65  CameraBase camera = GetGame().GetCameraManager().CurrentCamera();
66  if (!camera)
67  return;
68 
69  float distanceSq = vector.DistanceSqXZ(m_vStartOrigin, camera.GetOrigin());
70  float multiplier = 1 - Math.Clamp(distanceSq / (m_fMaxDistance * m_fMaxDistance * m_fSizeMultiplier), 0, 1);
71  float curveMultiplier = Math3D.Curve(ECurveType.CatmullRom, 1 - multiplier, m_CameraShakeCurve)[1];
72 
73  m_vTranslation *= Math.Min(multiplier * m_fSizeMultiplier * curveMultiplier, MAX_MULTIPLIER);
74  m_vRotation *= Math.Min(multiplier * m_fSizeMultiplier * curveMultiplier, MAX_MULTIPLIER);
75  }
76 
77  //------------------------------------------------------------------------------------------------
79  void SetStartOrigin(vector startOrigin)
80  {
81  m_vStartOrigin = startOrigin
82  }
83 
84  //------------------------------------------------------------------------------------------------
86  void SetCurve(Curve curve)
87  {
88  m_CameraShakeCurve = curve;
89  }
90 
91  //------------------------------------------------------------------------------------------------
93  void SetSizeMultiplier(float sizeMultiplier)
94  {
95  m_fSizeMultiplier = sizeMultiplier;
96  }
97 }
98 
99 [BaseContainerProps(namingConvention: NamingConvention.NC_MUST_HAVE_NAME)]
100 class SCR_TimedDebris : SCR_TimedEffect
101 {
102  [Attribute("0 0 0", UIWidgets.Coords, desc: "Positional offset (in local space to the destructible)")]
103  protected vector m_vOffsetPosition;
104 
105  [Attribute("0 0 0", UIWidgets.Coords, desc: "Yaw, pitch & roll offset (in local space to the destructible)")]
106  protected vector m_vOffsetRotation;
107 
108  [Attribute(ResourceName.Empty, UIWidgets.ResourcePickerThumbnail, "Debris model prefabs to spawn (spawns ALL of them)", "et xob")]
109  ref array<ResourceName> m_ModelPrefabs;
110 
111  [Attribute("10", UIWidgets.Slider, "Mass of the debris", "0.01 1000 0.01")]
112  float m_fMass;
113 
114  [Attribute("5", UIWidgets.Slider, "Minimum lifetime value for the debris (in s)", "0 3600 0.5")]
115  float m_fLifetimeMin;
116 
117  [Attribute("10", UIWidgets.Slider, "Maximum lifetime value for the debris (in s)", "0 3600 0.5")]
118  float m_fLifetimeMax;
119 
120  [Attribute("200", UIWidgets.Slider, "Maximum distance from camera above which the debris is not spawned (in m)", "0 3600 0.5")]
121  float m_fDistanceMax;
122 
123  [Attribute("0", UIWidgets.Slider, "Higher priority overrides lower priority if at or over debris limit", "0 100 1")]
124  int m_fPriority;
125 
126  [Attribute("0.1", UIWidgets.Slider, "Damage received to physics impulse (speed / mass) multiplier", "0 10000 0.01")]
127  float m_fDamageToImpulse;
128 
129  [Attribute("2", UIWidgets.Slider, "Damage to speed multiplier, used when objects get too much damage to impulse", "0 10000 0.01")]
131 
132  [Attribute("0.5", UIWidgets.Slider, "Random linear velocity multiplier (m/s)", "0 200 0.1")]
134 
135  [Attribute("180", UIWidgets.Slider, "Random angular velocity multiplier (deg/s)", "0 3600 0.1")]
137 
138  [Attribute("0", uiwidget: UIWidgets.ComboBox, "Type of material for debris sound", "", ParamEnumArray.FromEnum(SCR_EMaterialSoundTypeDebris))]
140 
141  //------------------------------------------------------------------------------------------------
146  void GetSpawnTransform(IEntity owner, out vector outMat[4], bool localCoords = false)
147  {
148  if (localCoords)
149  {
150  Math3D.AnglesToMatrix(m_vOffsetRotation, outMat);
151  // TODO: Remove hotfix for sleeping/static object
152  if (m_vOffsetPosition == vector.Zero)
153  outMat[3] = vector.Up * 0.001;
154  else
155  outMat[3] = m_vOffsetPosition;
156  }
157  else
158  {
159  vector localMat[4], parentMat[4];
160  owner.GetWorldTransform(parentMat);
161  Math3D.AnglesToMatrix(m_vOffsetRotation, localMat);
162  localMat[3] = m_vOffsetPosition;
163 
164  Math3D.MatrixMultiply4(parentMat, localMat, outMat);
165  }
166  }
167 
168  //------------------------------------------------------------------------------------------------
173  override void ExecuteEffect(IEntity owner, SCR_HitInfo hitInfo, inout notnull SCR_BuildingDestructionData data)
174  {
175  int numModelPrefabs = 0;
176  if (m_ModelPrefabs)
177  numModelPrefabs = m_ModelPrefabs.Count();
178 
179  SCR_DestructionDamageManagerComponent destructionComponent;
180  for (int i = 0; i < numModelPrefabs; i++)
181  {
182  ResourceName prefabPath = m_ModelPrefabs[i];
183 
184  ResourceName modelPath;
185  string remap;
186  SCR_Global.GetModelAndRemapFromResource(prefabPath, modelPath, remap);
187 
188  if (modelPath == ResourceName.Empty)
189  continue;
190 
191  vector spawnMat[4];
192  GetSpawnTransform(owner, spawnMat);
193 
194  destructionComponent = SCR_DestructionDamageManagerComponent.Cast(owner.FindComponent(SCR_DestructionDamageManagerComponent));
195 
196  float dmgSpeed = Math.Clamp(hitInfo.m_HitDamage * m_fDamageToImpulse / m_fMass, 0, m_fMaxDamageToSpeedMultiplier);
197 
198  vector linearVelocity = hitInfo.m_HitDirection * Math.RandomFloat(0, 1);
199  linearVelocity += Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * m_fRandomVelocityLinear;
200  linearVelocity *= dmgSpeed;
201  vector angularVelocity = Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * Math.RandomFloat(0.25, 4) * m_fRandomVelocityAngular;
202  angularVelocity *= dmgSpeed;
203 
204  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);
205  }
206  }
207 }
208 
209 [BaseContainerProps(namingConvention: NamingConvention.NC_MUST_HAVE_NAME)]
210 class SCR_TimedEffect : Managed
211 {
212  [Attribute("0", UIWidgets.Slider, "Set time in % of sinking the building. 0 = Immediately, can happen before the sinking starts if delay is used", "0 1 0.01")]
213  float m_fSpawnTime;
214 
215  [Attribute()]
216  bool m_bSnapToTerrain;
217 
218  [Attribute()]
219  bool m_bAttachToParent;
220 
221  [Attribute("0", desc: "Does this effect remain after destruction? F. E. ruins.")]
222  bool m_bPersistent;
223 
224  //------------------------------------------------------------------------------------------------
226  void SnapToTerrain(inout vector origin, IEntity owner)
227  {
228  if (!m_bSnapToTerrain)
229  return;
230 
231  float y = SCR_TerrainHelper.GetTerrainY(origin, owner.GetWorld());
232  origin[1] = y;
233  }
234 
235  //------------------------------------------------------------------------------------------------
237  void ExecuteEffect(IEntity owner, SCR_HitInfo hitInfo, inout notnull SCR_BuildingDestructionData data)
238  {
239  }
240 }
241 
242 [BaseContainerProps(namingConvention: NamingConvention.NC_MUST_HAVE_NAME)]
243 class SCR_TimedSound : SCR_TimedEffect
244 {
245  [Attribute("", UIWidgets.Auto, desc: "Audio Source Configuration")]
246  protected ref SCR_AudioSourceConfiguration m_AudioSourceConfiguration;
247 
248  //------------------------------------------------------------------------------------------------
250  override void ExecuteEffect(IEntity owner, SCR_HitInfo hitInfo, inout notnull SCR_BuildingDestructionData data)
251  {
252  super.ExecuteEffect(owner, hitInfo, data);
253 
254  SCR_SoundManagerEntity soundManagerEntity = GetGame().GetSoundManagerEntity();
255  if (!soundManagerEntity || !m_AudioSourceConfiguration || !m_AudioSourceConfiguration.IsValid())
256  return;
257 
258  SCR_DestructibleBuildingComponent destructibleComponent = SCR_DestructibleBuildingComponent.Cast(owner.FindComponent(SCR_DestructibleBuildingComponent));
259  if (!destructibleComponent)
260  return;
261 
262  SCR_AudioSource audioSource = soundManagerEntity.CreateAudioSource(owner, m_AudioSourceConfiguration);
263  if (!audioSource)
264  return;
265 
266  destructibleComponent.SetAudioSource(audioSource);
267  soundManagerEntity.PlayAudioSource(audioSource, data.m_vStartMatrix);
268  }
269 }
270 
271 [BaseContainerProps(namingConvention: NamingConvention.NC_MUST_HAVE_NAME)]
272 class SCR_TimedPrefab : SCR_TimedEffect
273 {
274  [Attribute("", "Defines what remains after the building is destroyed.", params: "et")]
275  protected ResourceName m_sRuinsPrefab;
276 
277  //------------------------------------------------------------------------------------------------
279  override void ExecuteEffect(IEntity owner, SCR_HitInfo hitInfo, inout notnull SCR_BuildingDestructionData data)
280  {
281  super.ExecuteEffect(owner, hitInfo, data);
282 
283  Resource resource = Resource.Load(m_sRuinsPrefab);
284  if (!resource || !resource.IsValid())
285  return;
286 
287  vector mat[4];
288  mat = data.m_vStartMatrix;
289 
290  if (m_bSnapToTerrain)
291  {
292  vector origin = mat[3];
293  SnapToTerrain(origin, owner);
294  mat[3] = origin;
295  }
296 
297  EntitySpawnParams params = new EntitySpawnParams();
298  params.Transform = mat;
299  params.TransformMode = ETransformMode.WORLD;
300 
301  if (m_bAttachToParent)
302  params.Parent = owner;
303 
304  IEntity spawnedEntity = GetGame().SpawnEntityPrefab(resource, owner.GetWorld(), params);
305  if (!spawnedEntity)
306  {
307  Debug.Error("Could not spawn prefab in SCR_TimedPrefab.ExecuteEffect()");
308  return;
309  }
310 
311  data.m_aExcludeList.Insert(spawnedEntity);
312  }
313 }
314 
315 [BaseContainerProps(namingConvention: NamingConvention.NC_MUST_HAVE_NAME)]
316 class SCR_TimedParticle : SCR_TimedEffect
317 {
318  [Attribute()]
319  protected ref SCR_ParticleSpawnable m_Particle;
320 
321  [Attribute("1")]
322  protected float m_fParticlesMultiplier;
323 
324  //------------------------------------------------------------------------------------------------
326  override void ExecuteEffect(IEntity owner, SCR_HitInfo hitInfo, inout notnull SCR_BuildingDestructionData data)
327  {
328  super.ExecuteEffect(owner, hitInfo, data);
329 
330  ParticleEffectEntity emitter;
331  if (m_bAttachToParent)
332  emitter = m_Particle.SpawnAsChild(owner, hitInfo, m_bSnapToTerrain);
333  else
334  emitter = ParticleEffectEntity.Cast(m_Particle.Spawn(owner, owner.GetPhysics(), hitInfo, m_bSnapToTerrain));
335 
336  if (!emitter)
337  {
338  Debug.Error("No emitter was spawned in SCR_TimedParticle.ExecuteEffect()");
339  return;
340  }
341 
342  SetParticleParams(emitter, data);
343 
344  data.m_aExcludeList.Insert(emitter);
345  }
346 
347  //------------------------------------------------------------------------------------------------
350  void SetParticleParams(ParticleEffectEntity emitter, inout notnull SCR_BuildingDestructionData data)
351  {
352  Particles particles = emitter.GetParticles();
353  if (!particles)
354  return;
355 
356  particles.MultParam(-1, EmitterParam.BIRTH_RATE, Math.Clamp(data.m_fSizeMultiplier, 0.5, 2) * m_fParticlesMultiplier);
357  particles.MultParam(-1, EmitterParam.BIRTH_RATE_RND, Math.Clamp(data.m_fSizeMultiplier, 0.5, 2) * m_fParticlesMultiplier);
358  particles.MultParam(-1, EmitterParam.SIZE, Math.Clamp(data.m_fSizeMultiplier, 0.5, 1));
359  particles.MultParam(-1, EmitterParam.VELOCITY, Math.Clamp(data.m_fSizeMultiplier, 0.5, 2) * m_fParticlesMultiplier);
360  particles.MultParam(-1, EmitterParam.VELOCITY_RND, Math.Clamp(data.m_fSizeMultiplier, 0.5, 2) * m_fParticlesMultiplier);
361  }
362 }
363 
364 class SCR_DestructibleBuildingComponent : SCR_DamageManagerComponent
365 {
366  // In project settings you can see the physics response indices & their interactions matrix
367  protected static const int NO_COLLISION_RESPONSE_INDEX = 11;
368  protected static const int MAX_CHECKS_PER_FRAME = 20;
369  protected static const float BUILDING_SIZE = 5000;
370  protected static const vector TRACE_DIRECTIONS[3] = { vector.Right, vector.Up, vector.Forward };
371 
372  private int m_iDataIndex = -1;
373 
374  protected bool m_bDestroyed = false;
375 
376  //------------------------------------------------------------------------------------------------
378  protected SCR_BuildingDestructionData GetData()
379  {
380  SCR_BuildingDestructionManagerComponent manager = GetGame().GetBuildingDestructionManager();
381  if (!manager)
382  {
383  Print("SCR_BuildingDestructionManagerComponent not found! Building destruction won't work.", LogLevel.ERROR);
384  return null;
385  }
386 
387  return manager.GetData(m_iDataIndex);
388  }
389 
390  //------------------------------------------------------------------------------------------------
392  protected void FreeData()
393  {
394  SCR_BuildingDestructionManagerComponent manager = GetGame().GetBuildingDestructionManager();
395  if (!manager)
396  {
397  Print("SCR_BuildingDestructionManagerComponent not found! Building destruction won't work.", LogLevel.ERROR);
398  return;
399  }
400 
401  manager.FreeData(m_iDataIndex);
402  m_iDataIndex = -1;
403  }
404 
405  //------------------------------------------------------------------------------------------------
407  protected float GetSpeedGradualMultiplier()
408  {
409  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_fSinkingSpeedGradualMultiplier;
410  }
411 
412  //------------------------------------------------------------------------------------------------
413  protected float GetRotationTimeRandomizer()
414  {
415  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_fRotationTimeRandom;
416  }
417 
418  //------------------------------------------------------------------------------------------------
419  protected float GetRotationSpeed()
420  {
421  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_fRotationSpeed;
422  }
423 
424  //------------------------------------------------------------------------------------------------
425  protected float GetRotationTime()
426  {
427  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_fRotationTime;
428  }
429 
430  //------------------------------------------------------------------------------------------------
431  protected int GetMaxRotations()
432  {
433  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_iMaxRotations;
434  }
435 
436  //------------------------------------------------------------------------------------------------
438  protected float GetSpeed()
439  {
440  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_fSinkingSpeed;
441  }
442 
443  //------------------------------------------------------------------------------------------------
444  protected vector GetSinkVector()
445  {
446  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_vSinkVector;
447  }
448 
449  //------------------------------------------------------------------------------------------------
451  protected float GetDelay()
452  {
453  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_fDelay;
454  }
455 
456  //------------------------------------------------------------------------------------------------
457  protected bool GetAllowRotationX()
458  {
459  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_eAllowedRotations & SCR_EDestructionRotationEnum.ROTATION_X;
460  }
461 
462  //------------------------------------------------------------------------------------------------
463  protected bool GetAllowRotationY()
464  {
465  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_eAllowedRotations & SCR_EDestructionRotationEnum.ROTATION_Y;
466  }
467 
468  //------------------------------------------------------------------------------------------------
469  protected bool GetAllowRotationZ()
470  {
471  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_eAllowedRotations & SCR_EDestructionRotationEnum.ROTATION_Z;
472  }
473 
474  //------------------------------------------------------------------------------------------------
475  protected Curve GetCameraShakeCurve()
476  {
477  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_CameraShakeCurve;
478  }
479 
480  //------------------------------------------------------------------------------------------------
482  protected array<ref SCR_TimedEffect> GetEffects()
483  {
484  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_aEffects;
485  }
486 
487  //------------------------------------------------------------------------------------------------
488  protected SCR_AudioSourceConfiguration GetSlowDownAudioSourceConfiguration()
489  {
490  return SCR_DestructibleBuildingComponentClass.Cast(GetComponentData(GetOwner())).m_AudioSourceConfiguration;
491  }
492 
493  //------------------------------------------------------------------------------------------------
495  void SetAudioSource(SCR_AudioSource audioSource)
496  {
497  SCR_BuildingDestructionData data = GetData();
498  if (!data)
499  return;
500 
501  if (data.m_AudioSource)
502  {
503  // Kill previous sound
504  SCR_SoundManagerEntity soundManagerEntity = GetGame().GetSoundManagerEntity();
505  if (soundManagerEntity)
506  soundManagerEntity.TerminateAudioSource(data.m_AudioSource);
507  }
508 
509  data.m_AudioSource = audioSource;
510 
511  if (audioSource)
512  data.m_AudioSource.SetSignalValue(SCR_AudioSource.ENTITY_SIZE_SIGNAL_NAME, data.m_fBuildingVolume);
513  }
514 
515  //------------------------------------------------------------------------------------------------
517  SCR_AudioSource GetAudioSource()
518  {
519  SCR_BuildingDestructionData data = GetData();
520  if (!data)
521  return null;
522 
523  return data.m_AudioSource;
524  }
525 
526  //------------------------------------------------------------------------------------------------
527  protected void SetSeed(int seed)
528  {
529  SCR_BuildingDestructionData data = GetData();
530  if (!data)
531  return;
532 
533  data.m_RandomGenerator.SetSeed(seed);
534  }
535 
536  //------------------------------------------------------------------------------------------------
539  protected override void OnDamageStateChanged(EDamageState state)
540  {
541  super.OnDamageStateChanged(state);
542 
543  if (IsProxy())
544  return;
545 
546  // Already destroyed
547  if (m_bDestroyed)
548  return;
549 
550  // Called only on the server
551  if (state == EDamageState.DESTROYED)
552  {
553  Math.Randomize(-1);
554  int seed = Math.RandomInt(int.MIN, int.MAX);
555  StoreNavmeshData();
556  RPC_GoToDestroyedState(seed);
557  Rpc(RPC_GoToDestroyedState, seed);
558  }
559  }
560 
561  //------------------------------------------------------------------------------------------------
564  [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
565  protected void RPC_GoToDestroyedState(int seed)
566  {
567  SetSeed(seed);
568  DestroyInteriorInit(false);
569  CalculateAndStoreVolume();
570  SpawnEffects(0, GetOwner(), false);
571  GetGame().GetCallqueue().CallLater(GoToDestroyedState, 1000 * GetDelay(), param1: false);
572  }
573 
574  //------------------------------------------------------------------------------------------------
577  protected void DestroyInteriorInit(bool immediate)
578  {
579  SCR_BuildingDestructionData data = GetData();
580  if (!data)
581  return;
582 
583  //exclude spawned effects
584  IEntity owner = GetOwner();
585  BaseWorld world = owner.GetWorld();
586  vector mins, maxs;
587 
588  owner.GetWorldBounds(mins, maxs);
589  owner.GetTransform(data.m_vStartMatrix);
590 
591  data.m_aQueriedEntities = {};
592 
593  // Caches objects inside
594  world.QueryEntitiesByAABB(mins, maxs, AddEntityCallback);
595  }
596 
597  //------------------------------------------------------------------------------------------------
598  // Uses data queried by DestroyInteriorInit method
599  // \param[in] immediate
600  protected void DestroyInterior(bool immediate)
601  {
602  SCR_BuildingDestructionData data = GetData();
603  if (!data)
604  return;
605 
606  int count = data.m_aQueriedEntities.Count();
607  int i = count - 1;
608  SCR_DestructibleEntity destructibleEntity;
609  SCR_DestructionDamageManagerComponent destructionComponent;
610  vector hitPosDirNorm[3];
611  RplComponent rplComponent;
612  IEntity childEntity;
613  array<IEntity> handledEntities = {};
614  while (count > 0)
615  {
616  if (i < 0)
617  i = count - 1;
618 
619  if (!data.m_aQueriedEntities[i])
620  {
621  data.m_aQueriedEntities.Remove(i);
622  i--;
623  count--;
624  continue;
625  }
626 
627  //Has children, will be handled later
628  childEntity = data.m_aQueriedEntities[i].GetChildren();
629  if (childEntity)
630  {
631  // Child entity was not queried for some reason && has not been handled yet, add it to the list of queried entities
632  if (!data.m_aQueriedEntities.Contains(childEntity) && !handledEntities.Contains(childEntity))
633  {
634  data.m_aQueriedEntities.Insert(childEntity);
635  count++;
636  }
637 
638  // If child was already handled, we can consider this entity a non-parent
639  if (!handledEntities.Contains(childEntity))
640  {
641  i--;
642  continue;
643  }
644  }
645 
646  // Following order of operations is crucial, so we don't end up with null pointers at some point!
647 
648  // Any entity that reaches this point is perceived as handled
649  handledEntities.Insert(data.m_aQueriedEntities[i]);
650 
651  // Ignore entities outside the building
652  data.m_iChecksThisFrame++;
653  if (data.m_iChecksThisFrame >= MAX_CHECKS_PER_FRAME)
654  {
655  data.m_iChecksThisFrame = 0;
656  // Callqueue used here, because it shouldn't rely on running EOnFrame
657  GetGame().GetCallqueue().CallLater(DestroyInterior, param1: immediate);
658  return;
659  }
660 
661  // Interior check for the object
662  // Disabled for now, this check now happens under ground, so it's pointless here
663  /*if (!IsInside(data.m_aQueriedEntities[i]))
664  {
665  data.m_aQueriedEntities.Remove(i);
666  i--;
667  count--;
668 
669  continue;
670  }*/
671 
672  destructibleEntity = SCR_DestructibleEntity.Cast(data.m_aQueriedEntities[i]);
673  destructionComponent = SCR_DestructionDamageManagerComponent.Cast(data.m_aQueriedEntities[i].FindComponent(SCR_DestructionDamageManagerComponent));
674 
675  // Non-destructible object, just delete it later, so destruction happens on frame
676  if (!destructibleEntity && !destructionComponent)
677  {
678  rplComponent = RplComponent.Cast(data.m_aQueriedEntities[i].FindComponent(RplComponent));
679  // Don't delete replicated objects for now TODO: Solve this properly in the future
680  if (!rplComponent)
681  delete data.m_aQueriedEntities[i];
682  /*if (rplComponent)
683  RplComponent.DeleteRplEntity(data.m_aQueriedEntities[i], false);
684  else
685  delete data.m_aQueriedEntities[i];*/
686  }
687 
688  // Is destructible entity
689  if (destructibleEntity)
690  destructibleEntity.HandleDamage(EDamageType.TRUE, destructibleEntity.GetCurrentHealth() * 11, hitPosDirNorm);
691 
692  // Uses destruction component
693  if (destructionComponent)
694  destructionComponent.DeleteDestructible();
695 
696  data.m_aQueriedEntities.Remove(i);
697  i--;
698  count--;
699  }
700 
701  FinishDestruction();
702  }
703 
704  //------------------------------------------------------------------------------------------------
706  protected void FinishDestruction()
707  {
708  SCR_BuildingDestructionData data = GetData();
709  if (!data)
710  return;
711 
712  //data.m_CameraShake.Stop();
713  data.m_CameraShake.SetParams(0.15, 0.15, 0.01, 0.3, 0.24);
714  data.m_CameraShake = null;
715  data.m_aQueriedEntities = null;
716  FreeData();
717  }
718 
719  //------------------------------------------------------------------------------------------------
720  protected bool PerformTrace(notnull TraceParam param, vector start, vector direction, notnull BaseWorld world, float lengthMultiplier = 1)
721  {
722  param.Start = start - direction * lengthMultiplier;
723  param.End = start + direction * lengthMultiplier;
724  world.TraceMove(param, TraceFilter);
725 
726  return param.TraceEnt != null;
727  }
728 
729  //------------------------------------------------------------------------------------------------
732  protected bool IsInside(notnull IEntity entity)
733  {
734  IEntity owner = GetOwner();
735  BaseWorld world = owner.GetWorld();
736  vector start = entity.GetOrigin();
737 
738  TraceParam param = new TraceParam();
739  param.Flags = TraceFlags.ENTS;
740  param.LayerMask = EPhysicsLayerDefs.Projectile;
741  param.Include = owner; // Include only the building for performance reasons
742 
743  bool result;
744  for (int i = 0; i < 3; i++)
745  {
746  float lengthMultiplier = 1;
747  if (i == 1)
748  lengthMultiplier = 100; // Vertical traces can and must be long to detect roof, where there is no floor, also they are internally optimized
749 
750  result = PerformTrace(param, start, TRACE_DIRECTIONS[i], world, lengthMultiplier);
751 
752  if (result)
753  return true;
754  }
755 
756  return false;
757  }
758 
759  //------------------------------------------------------------------------------------------------
764  protected bool TraceFilter(notnull IEntity e, vector start = "0 0 0", vector dir = "0 0 0")
765  {
766  return e == GetOwner();
767  }
768 
769  //------------------------------------------------------------------------------------------------
772  protected bool AddEntityCallback(IEntity e)
773  {
774  SCR_BuildingDestructionData data = GetData();
775  if (!data)
776  return true;
777 
778  if (e.FindComponent(SCR_DestructibleBuildingComponent))
779  return true;
780 
781  IEntity owner = GetOwner();
782  IEntity entityParent = e.GetParent();
783 
784  // Exclude the owner && children of other objects
785  if (e == owner || (entityParent && entityParent != owner))
786  return true;
787 
788  // Exclude entities in exclude list
789  // Disabled for now, because it might not be necessary
790  // Keeping it for later if we decide to use it in some other way than originally planned
791  /*if (data.m_aExcludeList.Contains(e))
792  return true;*/
793 
794  vector hitPosDirNorm[3];
795 
796  // Exclude chimera character, vehicles
797  if (ChimeraCharacter.Cast(e) || Vehicle.Cast(e))
798  {
799  // The character is outside the building
800  if (!IsInside(e))
801  return true;
802 
803  DamageManagerComponent damageManager = DamageManagerComponent.Cast(e.FindComponent(DamageManagerComponent));
804  if (damageManager)
805  {
806  SCR_DamageContext damageContext = new SCR_DamageContext(EDamageType.TRUE, 100000, hitPosDirNorm, e, null, null, null, -1, -1);
807  damageManager.HandleDamage(damageContext);
808  }
809 
810  return true;
811  }
812 
813  // All children of chimera character
814  IEntity mainParent = SCR_EntityHelper.GetMainParent(e);
815  if (ChimeraCharacter.Cast(mainParent) || Vehicle.Cast(mainParent))
816  return true;
817 
818  if (SCR_EntityHelper.GetMainParent(e) != owner)
819  owner.AddChild(e, -1, EAddChildFlags.AUTO_TRANSFORM | EAddChildFlags.RECALC_LOCAL_TRANSFORM);
820 
821  data.m_aQueriedEntities.Insert(e);
822  return true;
823  }
824 
825  //------------------------------------------------------------------------------------------------
827  void GoToDestroyedStateLoad()
828  {
829  StoreNavmeshData();
830  GoToDestroyedState(true);
831  }
832 
833  //------------------------------------------------------------------------------------------------
835  void CalculateAndStoreVolume()
836  {
837  SCR_BuildingDestructionData data = GetData();
838  if (!data)
839  return;
840 
841  vector mins, maxs;
842  GetOwner().GetBounds(mins, maxs);
843 
844  float x = Math.AbsFloat(mins[0]) + maxs[0];
845  float y = Math.AbsFloat(mins[1]) + maxs[1];
846  float z = Math.AbsFloat(mins[2]) + maxs[2];
847 
848  data.m_fBuildingVolume = x * y * z;
849  data.m_fSizeMultiplier = data.m_fBuildingVolume / BUILDING_SIZE; // BUILDING_SIZE constant is value for the average building size
850  }
851 
852  //------------------------------------------------------------------------------------------------
857  protected void GoToDestroyedState(bool immediate)
858  {
859  SCR_BuildingDestructionData data = GetData();
860  if (!data)
861  return;
862 
863  m_bDestroyed = true;
864  GetGame().GetBuildingDestructionManager().RegisterDestroyedBuilding(this);
865 
866  IEntity owner = GetOwner();
867 
868  vector mins, maxs;
869  owner.GetBounds(mins, maxs);
870 
871  maxs[0] = 0;
872  maxs[2] = 0;
873 
874  vector sinkVector = GetSinkVector();
875  if (sinkVector == vector.Zero)
876  sinkVector = -maxs;
877 
878  data.m_vTargetOrigin = owner.GetOrigin() + sinkVector;
879  data.m_vStartAngles = owner.GetAngles();
880 
881  StaticModelEntity.Cast(owner).DestroyOccluders();
882 
883  // Don't animate, JIP happened
884  if (immediate)
885  {
886  DestroyInteriorInit(immediate);
887  FinishLerp(owner, immediate);
888  }
889  else // Animate sinking, play particles, sounds etc...
890  {
891  owner.GetPhysics().SetResponseIndex(NO_COLLISION_RESPONSE_INDEX);
892  data.m_CameraShake.SetParams(0.15, 0.15, 0.01, 400, 0.24);
893  data.m_CameraShake.SetCurve(GetCameraShakeCurve());
894  data.m_CameraShake.SetStartOrigin(data.m_vStartMatrix[3]);
895  data.m_CameraShake.SetSizeMultiplier(data.m_fSizeMultiplier);
896  SCR_CameraShakeManagerComponent.AddCameraShake(data.m_CameraShake);
897  SetEventMask(owner, EntityEvent.FRAME);
898  }
899  }
900 
901  //------------------------------------------------------------------------------------------------
907  protected void SpawnEffects(float percentDone, IEntity owner, bool immediateDestruction)
908  {
909  SCR_BuildingDestructionData data = GetData();
910  if (!data)
911  return;
912 
913  if (!data.m_aExcludeList)
914  data.m_aExcludeList = {};
915 
916  SCR_HitInfo hitInfo = new SCR_HitInfo();
917  hitInfo.m_DamageType = EDamageType.KINETIC; // Todo properly store damage type
918 
919  array<ref SCR_TimedEffect> effects = GetEffects();
920  SCR_TimedEffect currentEffect;
921  for (int i = effects.Count() - 1; i >= 0; i--)
922  {
923  if (data.m_aExecutedEffectIndices && data.m_aExecutedEffectIndices.Contains(i))
924  continue;
925 
926  currentEffect = effects[i]; // Store it, because each effects[i] is effects.Get(i) call internally
927 
928  if (immediateDestruction && !currentEffect.m_bPersistent)
929  continue; // Skip because destruction happened immediately & effect isn't persistent
930 
931  if (currentEffect.m_fSpawnTime <= percentDone)
932  {
933  currentEffect.ExecuteEffect(owner, hitInfo, data);
934 
935  // Create the set if it doesn't exist yet
936  if (!data.m_aExecutedEffectIndices)
937  {
938  data.m_aExecutedEffectIndices = new set<int>();
939  // Max size of the set is known beforehand, because m_aEffects is in prefab data
940  data.m_aExecutedEffectIndices.Reserve(effects.Count());
941  }
942 
943  data.m_aExecutedEffectIndices.Insert(i);
944  }
945  }
946  }
947 
948  //------------------------------------------------------------------------------------------------
955  protected void FinishLerp(IEntity owner, bool immediate)
956  {
957  owner.SetObject(null, ""); // Hide the building
958  ClearEventMask(owner, EntityEvent.FRAME);
959 
960  SpawnEffects(1, owner, immediate); // Ensure all effects get played
961 
962  SCR_BuildingDestructionData data = GetData();
963  if (!data)
964  return;
965 
966  owner.SetOrigin(data.m_vTargetOrigin);
967  owner.Update();
968  RegenerateNavmesh();
969  DestroyInterior(immediate);
970  }
971 
972  //------------------------------------------------------------------------------------------------
974  protected void RegenerateNavmesh()
975  {
976  SCR_BuildingDestructionData data = GetData();
977  if (!data)
978  return;
979 
980  SCR_AIWorld aiWorld = SCR_AIWorld.Cast(GetGame().GetAIWorld());
981  if (!aiWorld)
982  return;
983 
984  aiWorld.RequestNavmeshRebuildAreas(data.m_aNavmeshAreas, data.m_aRedoRoads);
985  }
986 
987  //------------------------------------------------------------------------------------------------
989  protected void StoreNavmeshData()
990  {
991  if (Replication.IsClient())
992  return;
993 
994  SCR_BuildingDestructionData data = GetData();
995  if (!data)
996  return;
997 
998  SCR_AIWorld aiWorld = SCR_AIWorld.Cast(GetGame().GetAIWorld());
999  if (!aiWorld)
1000  return;
1001 
1002  data.m_aNavmeshAreas = {};
1003  data.m_aRedoRoads = {};
1004  aiWorld.GetNavmeshRebuildAreas(GetOwner(), data.m_aNavmeshAreas, data.m_aRedoRoads); // Get area with current phase
1005  }
1006 
1007  //------------------------------------------------------------------------------------------------
1008  protected void ClampVector(inout vector currentOrigin, vector startOrigin, vector endOrigin)
1009  {
1010  bool targetSmaller;
1011  for (int i = 0; i < 3; i++)
1012  {
1013  targetSmaller = endOrigin[i] < startOrigin[i];
1014  if (targetSmaller)
1015  {
1016  if (currentOrigin[i] < endOrigin[i])
1017  currentOrigin[i] = endOrigin[i];
1018  }
1019  else
1020  {
1021  if (currentOrigin[i] > endOrigin[i])
1022  currentOrigin[i] = endOrigin[i];
1023  }
1024  }
1025  }
1026 
1027  //------------------------------------------------------------------------------------------------
1028  protected void LerpRotation(IEntity owner, float timeSlice)
1029  {
1030  SCR_BuildingDestructionData data = GetData();
1031  if (!data)
1032  return;
1033 
1034  // When it's time to reset the target rotation
1035  if (data.m_iRotationStart + data.m_iRotationTime < owner.GetWorld().GetWorldTime() && data.m_iRotatedTimes < GetMaxRotations())
1036  {
1037  // Generate next rotation time offset
1038  float rotationTimeRandomizer = GetRotationTimeRandomizer() * 0.01; // * 0.01 to 0-1 range
1039  data.m_iRotationTime = GetRotationTime() * (1 + data.m_RandomGenerator.RandFloatXY(0, rotationTimeRandomizer)) * 1000; // * 1000 = to ms
1040 
1041  // Slow down the sinking to make it seem like it crashed into something
1042  data.m_fSpeedMultiplier *= 0.05;
1043 
1044  // Only call OnSlowDown if it's not initial rotation setting
1045  if (data.m_iRotatedTimes != 0)
1046  OnSlowDown();
1047 
1048  bool allowRotationX = GetAllowRotationX();
1049  bool allowRotationY = GetAllowRotationY();
1050  bool allowRotationZ = GetAllowRotationZ();
1051 
1052  // Generate new random angles
1053  vector newTargetAngles = {
1054  data.m_RandomGenerator.RandFloatXY(5, 20) * allowRotationX * data.m_iRotationMultiplier + data.m_vStartAngles[0],
1055  data.m_RandomGenerator.RandFloatXY(5, 20) * allowRotationY * data.m_iRotationMultiplier + data.m_vStartAngles[1],
1056  data.m_RandomGenerator.RandFloatXY(5, 20) * allowRotationZ * data.m_iRotationMultiplier + data.m_vStartAngles[2]
1057  };
1058 
1059  // This ensures the rotation will always be going to the opposite side of the previous one
1060  data.m_iRotationMultiplier *= -1;
1061 
1062  // Reset the speed multiplier
1063  data.m_fRotationSpeedMultiplier = 0.5;
1064 
1065  // Save the new target angles
1066  data.m_vTargetAngles = newTargetAngles;
1067 
1068  // Cache world
1069  BaseWorld world = owner.GetWorld();
1070 
1071  int pauseTime = data.m_RandomGenerator.RandIntInclusive(0, 500);
1072 
1073  // Save the current timestamp as the rotation start
1074  // Add the pause time to it
1075  data.m_iRotationStart = world.GetWorldTime() + pauseTime;
1076 
1077  // Set pause time to stop the building for a while
1078  data.m_iPauseTime = world.GetWorldTime() + pauseTime;
1079 
1080  data.m_iRotatedTimes++;
1081  }
1082 
1083  // This is the actual lerp
1084  data.m_fRotationSpeedMultiplier += timeSlice;
1085  //vector newAngles = vector.Lerp(owner.GetAngles(), data.m_vTargetAngles, timeSlice * Math.Pow(data.m_fRotationSpeedMultiplier, 3));
1086  vector newAngles = LerpAngles(data.m_vStartAngles, owner.GetAngles(), data.m_vTargetAngles, GetRotationSpeed(), timeSlice, data);
1087  owner.SetAngles(newAngles);
1088  }
1089 
1090  //------------------------------------------------------------------------------------------------
1091  protected void PlaySlowDownSound()
1092  {
1093  SCR_SoundManagerEntity soundManagerEntity = GetGame().GetSoundManagerEntity();
1094  if (!soundManagerEntity)
1095  return;
1096 
1097  SCR_AudioSourceConfiguration audioSourceConfiguration = GetSlowDownAudioSourceConfiguration();
1098  if (!audioSourceConfiguration || !audioSourceConfiguration.IsValid())
1099  return;
1100 
1101  SCR_AudioSource audioSource = soundManagerEntity.CreateAudioSource(GetOwner(), audioSourceConfiguration);
1102  if (!audioSource)
1103  return;
1104 
1105  SetAudioSource(audioSource);
1106  soundManagerEntity.PlayAudioSource(audioSource, GetData().m_vStartMatrix);
1107  }
1108 
1109  //------------------------------------------------------------------------------------------------
1110  protected void OnSlowDown()
1111  {
1112  PlaySlowDownSound();
1113  }
1114 
1115  //------------------------------------------------------------------------------------------------
1116  protected vector LerpAngles(vector start, vector current, vector target, float rotationSpeed, float timeSlice, notnull SCR_BuildingDestructionData data)
1117  {
1118  if (target == vector.Zero)
1119  return vector.Zero;
1120 
1121  float percent = timeSlice / (data.m_iRotationTime * 0.001);
1122  vector diff = target - start;
1123  vector nextRotation = current + percent * diff * rotationSpeed * data.m_fRotationSpeedMultiplier;
1124 
1125  ClampVector(nextRotation, start, target);
1126  return nextRotation;
1127  }
1128 
1129  //------------------------------------------------------------------------------------------------
1134  protected void LerpPosition(IEntity owner, float timeSlice)
1135  {
1136  SCR_BuildingDestructionData data = GetData();
1137  if (!data)
1138  return;
1139 
1140  vector currentOrigin = owner.GetOrigin();
1141  vector direction = (data.m_vTargetOrigin - currentOrigin).Normalized();
1142 
1143  data.m_fSpeedMultiplier += (GetSpeedGradualMultiplier() * timeSlice) * 0.01;
1144  vector mat[4];
1145  owner.GetTransform(mat);
1146  vector newOrigin = currentOrigin + direction * GetSpeed() * timeSlice * data.m_fSpeedMultiplier;
1147 
1148  ClampVector(newOrigin, data.m_vStartMatrix[3], data.m_vTargetOrigin);
1149 
1150  float difY = data.m_vTargetOrigin[1] - data.m_vStartMatrix[3][1];
1151  float curY = newOrigin[1] - data.m_vStartMatrix[3][1];
1152  float percentDone = curY/difY;
1153  SpawnEffects(percentDone, owner, false);
1154 
1155  if (float.AlmostEqual(newOrigin[0], data.m_vTargetOrigin[0]) && float.AlmostEqual(newOrigin[1], data.m_vTargetOrigin[1]) && float.AlmostEqual(newOrigin[2], data.m_vTargetOrigin[2]))
1156  FinishLerp(owner, false);
1157 
1158  owner.SetOrigin(newOrigin);
1159  owner.Update();
1160  }
1161 
1162  //------------------------------------------------------------------------------------------------
1165  protected override event bool OnRplSave(ScriptBitWriter writer)
1166  {
1167  super.OnRplSave(writer);
1168 
1169  writer.WriteBool(m_bDestroyed);
1170 
1171  return true;
1172  }
1173 
1174  //------------------------------------------------------------------------------------------------
1177  protected override event bool OnRplLoad(ScriptBitReader reader)
1178  {
1179  super.OnRplLoad(reader);
1180 
1181  reader.ReadBool(m_bDestroyed);
1182 
1183  if (m_bDestroyed)
1184  {
1185  // Need to remove it from callqueue in case it was queued by OnDamageStateChanged
1186  GetGame().GetCallqueue().Remove(GoToDestroyedState);
1187  GoToDestroyedState(true);
1188  }
1189 
1190  return true;
1191  }
1192 
1193  //------------------------------------------------------------------------------------------------
1198  override bool OnContact(IEntity owner, IEntity other, Contact contact)
1199  {
1200  if (IsProxy())
1201  return false;
1202 
1203  if (GetHealth() <= 0)
1204  return false;
1205 
1206  if (other && other.IsInherited(SCR_DebrisSmallEntity)) // Ignore impacts from debris
1207  return false;
1208 
1209  // Get the physics of the dynamic object (if owner is static, then we use the other object instead)
1210  Physics physics = contact.Physics1;
1211  int responseIndex = physics.GetResponseIndex();
1212  float ownerMass = physics.GetMass();
1213  float otherMass;
1214  if (!physics.IsDynamic())
1215  {
1216  physics = contact.Physics2;
1217  if (!physics)
1218  return false; // This only happens with ragdolls, other objects do have physics here, as collision only happens between physical objects
1219 
1220  otherMass = physics.GetMass();
1221  }
1222  else
1223  {
1224  Physics otherPhysics = other.GetPhysics();
1225  if (!otherPhysics)
1226  return false; // This only happens with ragdolls, other objects do have physics here, as collision only happens between physical objects
1227 
1228  otherMass = otherPhysics.GetMass();
1229  }
1230 
1231  float momentum = CalculateMomentum(contact, ownerMass, otherMass);
1232 
1233  vector outMat[3];
1234  vector relVel = contact.VelocityBefore2 - contact.VelocityBefore1;
1235  outMat[0] = contact.Position; // Hit position
1236  outMat[1] = relVel.Normalized(); // Hit direction
1237  outMat[2] = contact.Normal; // Hit normal
1238 
1239  float damage = momentum * 0.05; // Todo replace with attribute
1240 
1241  // Send damage to damage handling
1242  SCR_DamageContext damageContext = new SCR_DamageContext(EDamageType.COLLISION, damage, outMat, GetOwner(), null, Instigator.CreateInstigator(other), null, -1, -1);
1243  HandleDamage(damageContext);
1244 
1245  return true;
1246  }
1247 
1248  //------------------------------------------------------------------------------------------------
1252  protected override void OnFrame(IEntity owner, float timeSlice)
1253  {
1254  LerpPosition(owner, timeSlice);
1255  SCR_BuildingDestructionData data = GetData();
1256 
1257  if (!data || data.m_iRotatedTimes <= GetMaxRotations())
1258  LerpRotation(owner, timeSlice);
1259  }
1260 
1261  //------------------------------------------------------------------------------------------------
1262  override void OnPostInit(IEntity owner)
1263  {
1264  super.OnPostInit(owner);
1265  SetEventMask(owner, EntityEvent.CONTACT);
1266  }
1267 
1268 #ifdef BUILDING_DESTRUCTION_SAVING
1269  //------------------------------------------------------------------------------------------------
1270  override event void _WB_OnDelete(IEntity owner, IEntitySource src)
1271  {
1272  SCR_BuildingDestructionManagerComponent.UnregisterBuildingId(this);
1273  }
1274 
1275  //------------------------------------------------------------------------------------------------
1276  override event void _WB_OnInit(IEntity owner, inout vector mat[4], IEntitySource src)
1277  {
1278  int id = GetBuildingId();
1279  if (id != 0 && !SCR_BuildingDestructionManagerComponent.IsIdTaken(id, this))
1280  return;
1281 
1283  src.Set("m_iId", id);
1284  SCR_BuildingDestructionManagerComponent.RegisterBuildingId(this, id);
1285  }
1286 #endif
1287  //------------------------------------------------------------------------------------------------
1289  int GetBuildingId()
1290  {
1292  if (ent)
1293  return ent.GetBuildingId();
1294 
1295  return 0;
1296  }
1297 
1298  //------------------------------------------------------------------------------------------------
1299  // constructor
1303  void SCR_DestructibleBuildingComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
1304  {
1305 #ifdef BUILDING_DESTRUCTION_SAVING
1306  if (!SCR_DestructibleBuildingEntity.Cast(ent))
1307  Print("SCR_DestructibleBuildingComponent not attached to SCR_DestructibleBuildingEntity!", LogLevel.WARNING);
1308  else
1309  {
1310  int id = GetBuildingId();
1311  if (id != 0)
1312  SCR_BuildingDestructionManagerComponent.RegisterBuildingId(this, id);
1313  }
1314 #endif
1315  }
1316 
1317  //------------------------------------------------------------------------------------------------
1318  // destructor
1319  void ~SCR_DestructibleBuildingComponent()
1320  {
1321 #ifdef BUILDING_DESTRUCTION_SAVING
1322  SCR_BuildingDestructionManagerComponent.UnregisterBuildingId(this);
1323 #endif
1324  }
1325 
1326  //------------------------------------------------------------------------------------------------
1328  protected bool IsProxy()
1329  {
1330  RplComponent rplComponent = RplComponent.Cast(GetOwner().FindComponent(RplComponent));
1331  return rplComponent && rplComponent.IsProxy();
1332  }
1333 }
SCR_TerrainHelper
Definition: SCR_TerrainHelper.c:1
SCR_AudioSource
Definition: SCR_AudioSource.c:1
direction
vector direction
Definition: SCR_DestructibleTreeV2.c:31
ROTATION_Z
SCR_DestructibleBuildingEntityClass ROTATION_Z
m_ModelPrefabs
ref array< ResourceName > m_ModelPrefabs
Definition: SCR_DestructionBaseComponent.c:698
SCR_EntityHelper
Definition: SCR_EntityHelper.c:1
m_fSizeMultiplier
float m_fSizeMultiplier
Definition: SCR_BuildingDestructionManagerComponent.c:30
OnFrame
event protected void OnFrame(IEntity owner, float timeSlice)
SCR_DestructibleBuildingEntity
Definition: SCR_DestructibleBuildingEntity.c:47
SCR_NoisyCameraShakeProgress
Definition: SCR_NoisyCameraShakeProgress.c:4
OnContact
override bool OnContact(IEntity owner, IEntity other, Contact contact)
Definition: SCR_RotorDamageManagerComponent.c:207
m_fDistanceMax
float m_fDistanceMax
Definition: SCR_DestructionBaseComponent.c:710
CalculateMomentum
float CalculateMomentum(Contact contact, float ownerMass, float otherMass)
Definition: SCR_DestructibleEntity.c:346
m_fPriority
int m_fPriority
Definition: SCR_DestructionBaseComponent.c:713
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
SCR_EMaterialSoundTypeDebris
SCR_EMaterialSoundTypeDebris
Definition: SCR_DestructionMultiPhaseComponent.c:3
SCR_DestructibleEntity
void SCR_DestructibleEntity(IEntitySource src, IEntity parent)
Definition: SCR_DestructibleEntity.c:464
EDamageState
EDamageState
Definition: EDamageState.c:12
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
RplRpc
SCR_AchievementsHandlerClass ScriptComponentClass RplRpc(RplChannel.Reliable, RplRcver.Owner)] void UnlockOnClient(AchievementId achievement)
Definition: SCR_AchievementsHandler.c:11
SCR_SoundManagerEntity
Definition: SCR_SoundManagerEntity.c:17
Instigator
Definition: Instigator.c:6
ROTATION_Y
SCR_DestructibleBuildingComponentClass ROTATION_Y
SCR_HitInfo
Class to temporarily store information about the last hit that dealt damage.
Definition: SCR_DestructionBaseComponent.c:659
SCR_AIWorld
Definition: SCR_AIWorld.c:23
m_Particle
ResourceName m_Particle
Definition: SCR_ParticleContactComponent.c:12
IsProxy
protected bool IsProxy()
Definition: SCR_CampaignBuildingCompositionComponent.c:456
GetHealth
float GetHealth()
Definition: SCR_FuelNode.c:196
Attribute
typedef Attribute
Post-process effect of scripted camera.
SCR_DamageManagerComponentClass
enum ECharacterHitZoneGroup SCR_DamageManagerComponentClass
Update
override void Update(float timeSlice)
Definition: SCR_CampaignBuildingGadgetToolComponent.c:28
SCR_DebrisSmallEntity
Definition: DebrisSmallEntity.c:14
OnPostInit
override void OnPostInit(IEntity owner)
Called on PostInit when all components are added.
Definition: SCR_AIConfigComponent.c:72
OnDamageStateChanged
SCR_CharacterBloodHitZone OnDamageStateChanged
Resilience - incapacitation or death, depending on game mode settings.
Definition: SCR_CharacterHitZone.c:439
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.
OnRplLoad
event protected bool OnRplLoad(ScriptBitReader r)
Definition: RespawnSystemComponent.c:36
OnRplSave
event protected bool OnRplSave(ScriptBitWriter w)
Definition: RespawnSystemComponent.c:31
GetData
Managed GetData()
Definition: SCR_ModularButtonComponent.c:171
SCR_DamageContext
Definition: SCR_DamageContext.c:7
SCR_Global
Definition: Functions.c:6
ROTATION_X
SCR_DestructibleBuildingComponentClass ROTATION_X
SCR_BuildingDestructionManagerComponent
Definition: SCR_BuildingDestructionManagerComponent.c:60
m_AudioSourceConfiguration
ref SCR_AudioSourceConfiguration m_AudioSourceConfiguration
Definition: SCR_ParticleContactComponent.c:3
m_fDamageToImpulse
float m_fDamageToImpulse
Definition: SCR_DestructionBaseComponent.c:716
EDamageType
EDamageType
Definition: EDamageType.c:12
data
Get all prefabs that have the spawner data
Definition: SCR_EntityCatalogManagerComponent.c:305
params
Configs ServerBrowser KickDialogs params
Definition: SCR_NotificationSenderComponent.c:24
TraceFilter
protected bool TraceFilter(notnull IEntity e)
Definition: SCR_RotorDamageManagerComponent.c:183
m_fLifetimeMax
float m_fLifetimeMax
Definition: SCR_DestructionBaseComponent.c:707
NONE
SCR_DestructibleBuildingComponentClass NONE
DamageManagerComponent
Definition: DamageManagerComponent.c:12
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
m_vStartMatrix
vector m_vStartMatrix[4]
Definition: SCR_BuildingDestructionManagerComponent.c:11
BaseContainerProps
SCR_AIGoalReaction_Follow BaseContainerProps
Handles insects that are supposed to be spawned around selected prefabs defined in prefab names array...
Definition: SCR_AIGoalReaction.c:468
SCR_DestructibleBuildingComponentClass
Definition: SCR_DestructibleBuildingComponent.c:1
m_fRandomVelocityAngular
float m_fRandomVelocityAngular
Definition: SCR_DestructionBaseComponent.c:725