Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_DestructibleBuildingEntity.c
Go to the documentation of this file.
1 [EntityEditorProps(category: "GameScripted/Buildings", description: "The main entity for a destructible building.", visible: false, dynamicBox: true)]
3 {
4  /*[Attribute("", UIWidgets.ResourceNamePicker, "The building configuration object to use for this building", "conf", category: "Destruction Building")]
5  protected ResourceName m_sBuildingConfig;*/
6  [Attribute("1", UIWidgets.EditBox, "Minimum damage above which the building switches to damaged state from the undamaged state", "0 1000000 0.5", category: "Destruction Building")]
7  protected float m_fMinUndamagedThreshold;
8 
9 #ifdef WORKBENCH
10  [Attribute("0", UIWidgets.CheckBox, "Check to update various data in the config (must be defined)", category: "EDITOR: Destruction Building")]
11  bool m_bUpdateConfigData;
12 
13  //------------------------------------------------------------------------------------------------
14  bool UpdateConfigData()
15  {
16  return m_bUpdateConfigData;
17  }
18 #endif
19 
20  //------------------------------------------------------------------------------------------------
21  /*ResourceName GetBuildingConfig()
22  {
23  return m_sBuildingConfig;
24  }*/
25 
26  //------------------------------------------------------------------------------------------------
27  float GetMinUndamagedThreshold()
28  {
29  return m_fMinUndamagedThreshold;
30  }
31 
32 };
33 
35 {
39 };
40 
46 //------------------------------------------------------------------------------------------------
48 {
49  [Attribute("", UIWidgets.ResourceNamePicker, "The building configuration object to use for this building", "conf", category: "Destruction Building")]
50  protected ResourceName m_BuildingConfig;
51 
52  [Attribute(uiwidget: UIWidgets.Hidden)]
53  protected int m_iId;
54 
55  //-----------------------------------------------------------------------
56  int GetBuildingId()
57  {
58  return m_iId;
59  }
60 
61  //-----------------------------------------------------------------------
62  void SetBuildingId(int id)
63  {
64  m_iId = id;
65  }
66 
67  #ifdef ENABLE_BUILDING_DESTRUCTION
68  #ifdef WORKBENCH
69  [Attribute("0", UIWidgets.CheckBox, "Check to update various data in the config (must be defined)", category: "EDITOR: Destruction Building")]
70  bool UpdateConfigData;
71 
72  //-----------------------------------------------------------------------
73  override bool _WB_OnKeyChanged(BaseContainer src, string key, BaseContainerList ownerContainers, IEntity parent)
74  {
75  WorldEditorAPI api = _WB_GetEditorAPI();
76  if (!api || api.UndoOrRedoIsRestoring())
77  return false;
78 
79  if (key != "UpdateConfigData")
80  return true;
81 
82  IEntitySource entSrc = src.ToEntitySource();
83  entSrc.ClearVariable("UpdateConfigData");
84  BaseContainerTools.WriteToInstance(this, entSrc);
85 
86  if (m_BuildingConfig == string.Empty)
87  {
88  Print("SCR_DestructibleBuildingEntity: Trying to update data in config, but config not defined!");
89  return true;
90  }
91 
92  m_BuildingSetup = SCR_BuildingConfigManagerEntity.GetBuildingSetupFromConfig(m_BuildingConfig);
93  if (!m_BuildingSetup)
94  {
95  Print("SCR_DestructibleBuildingEntity: Trying to update data in config, but config not loaded!");
96  return true;
97  }
98 
99  Print("SCR_DestructibleBuildingEntity: Updating data in config...");
100 
101  m_BuildingSetup.FillDamagedModels();
102 
103  Resource configResource = BaseContainerTools.LoadContainer(m_BuildingConfig);
104  BaseResourceObject configSource = configResource.GetResource();
105  BaseContainer configBase = configSource.ToBaseContainer();
106  configBase.Set("m_DamagedRegionModels", m_BuildingSetup.m_DamagedRegionModels);
107  configBase.Set("m_DamagedRegionIntersectDebrisModels", m_BuildingSetup.m_DamagedRegionIntersectDebrisModels);
108  if (BaseContainerTools.SaveContainer(configBase, m_BuildingConfig))
109  Print("SCR_DestructibleBuildingEntity: Success! Config data updated and stored.");
110  else
111  Print("SCR_DestructibleBuildingEntity: Failed! Config data was not successfully stored!!");
112 
113  m_BuildingSetup = SCR_BuildingConfigManagerEntity.ReloadConfig(m_BuildingConfig);
114 
115  return true;
116  }
117  #endif
118 
119  SCR_BuildingSetup m_BuildingSetup = null;
120 
121  // Uncomment to enable building destruction debugging
122  //#define BUILDING_DESTRUCTION_DEBUG
123 
124  // Uncomment to enable temporary debug shapes
125  //#define BUILDING_DEBUG_TEMP
126 
128  protected bool m_bDestroyed = false;
129 
131  protected ref SCR_BitMaskArray m_RegionMask = null;
132 
134  protected ref map<int, float> m_RegionDamage = null;
135 
137  protected BaseWorld m_World = null;
138 
140  protected BaseSoundComponent m_SoundComponent = null;
141 
142  protected RplComponent m_RplComponent;
143 
144  ref array<SCR_BuildingRegionEntity> m_RegionEntities = null;
145 
146  // List to hold queried props list
147  static ref array<IEntity> s_aQueryPropsList = new array<IEntity>();
148 
149  // Static reference to queried building region
150  static SCR_BuildingRegionEntity s_QueryBuildingRegion = null;
151 
152  #ifdef BUILDING_DEBUG_TEMP
153  // TODO: Remove once box trace bug is fixed
154  static ref array<ref Shape> debugShapes = new array<ref Shape>();
155  #endif
156 
157  //------------------------------------------------------------------------------------------------
158  [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
159  private void RPC_OnRegionDestroyed(int regionNumber, bool destroyed, bool doStructuralIntegrityCheck, bool doDamageEffects)
160  {
161  if (destroyed)
162  SetRegionDamage01(regionNumber, 1, doStructuralIntegrityCheck, doDamageEffects, false);
163  else
164  SetRegionDamage01(regionNumber, 0, doStructuralIntegrityCheck, doDamageEffects, false);
165  }
166 
167  //------------------------------------------------------------------------------------------------
169  override bool RplLoad(ScriptBitReader reader)
170  {
171  bool undamaged;
172  reader.Read(undamaged, 1);
173 
174  // Building undamaged, so stop reading
175  if (undamaged)
176  {
177  SetDestroyedState(false);
178  return true;
179  }
180 
181  bool destroyed;
182  reader.Read(destroyed, 1);
183 
184  // Building destroyed, so stop reading
185  if (destroyed)
186  {
187  SetDestroyedState(true);
188  return true;
189  }
190 
191  // Set to undestroyed (damage to be passed)
192  SetDestroyedState(false);
193 
194  // Now read the list of destroyed regions
195  int numRegions, regionIndex;
196  reader.Read(numRegions, 16);
197  for (int i = 0; i < numRegions; i++)
198  {
199  reader.Read(regionIndex, 16);
200  SetRegionDamage01(regionIndex, 1, false, false, false);
201  }
202 
203  return true;
204  }
205 
206  //------------------------------------------------------------------------------------------------
208  override bool RplSave(ScriptBitWriter writer)
209  {
210  // Building undamaged, so send true and return
211  if (GetUndamaged())
212  {
213  writer.Write(1, 1);
214  return true;
215  }
216  else
217  writer.Write(0, 1);
218 
219  // Building destroyed, so send true and return
220  if (GetDestroyed())
221  {
222  writer.Write(1, 1);
223  return true;
224  }
225  else
226  writer.Write(0, 1);
227 
228  autoptr array<int> destroyedRegions = new array<int>();
229  int numRegions = GetRegionsCount();
230  for (int i = 0; i < numRegions; i++)
231  {
232  if (GetRegionDestroyed(i))
233  destroyedRegions.Insert(i);
234  }
235  numRegions = destroyedRegions.Count();
236  writer.Write(numRegions, 16);
237  for (int i = 0; i < numRegions; i++)
238  {
239  writer.Write(destroyedRegions.Get(i), 16);
240  }
241 
242  return true;
243  }
244 
245  //------------------------------------------------------------------------------------------------
246  override void OnDamage(float damage, EDamageType type, IEntity pHitEntity, inout vector outMat[3], IEntity damageSource, notnull Instigator instigator, int colliderID, float speed)
247  {
248  if (!m_BuildingSetup)
249  return;
250 
251  if (GetDestroyed())
252  return;
253 
254  if (RplSession.Mode() == RplMode.Client)
255  return;
256 
258  if (!prefabData)
259  return;
260 
261  damage = SCR_Global.GetScaledStructuralDamage(damage, type);
262 
263  // Special case if the building is undamaged
264  if (GetUndamaged())
265  {
266  if (damage < prefabData.GetMinUndamagedThreshold())
267  return;
268 
269  // Force the building into the damaged state so we can find which region we hit and apply the damage
270  UpdateBuildingModel(BuildingDamageState.DAMAGED, true);
271 
272  vector hitPos = outMat[0];
273  vector hitDir = outMat[1];
274  //vector hitNorm = outMat[2];
275 
276  autoptr TraceParam param = new TraceParam;
277 
278  param.Start = hitPos + hitDir * -10;
279  param.End = hitPos + hitDir * 10;
280  param.Flags = TraceFlags.WORLD | TraceFlags.ENTS;
281  param.LayerMask = -1;
282 
283  int hitRegion = -1;
284 
285  // Trace the region
286  float traceDist = m_World.TraceMove(param, SCR_Global.FilterCallback_IgnoreNotInList);
287  if (traceDist < 1)
288  {
289  SCR_BuildingRegionEntity regionEnt = SCR_BuildingRegionEntity.Cast(param.TraceEnt);
290  if (regionEnt)
291  hitRegion = regionEnt.GetRegionNumber();
292  }
293 
294  // Could not trace region, so get via bound box intersection
295  if (hitRegion == -1 && m_BuildingSetup)
296  hitRegion = m_BuildingSetup.GetBoundingRegionNumber(CoordToLocal(hitPos));
297 
298  // Still failed to get the rgion, so just apply to base region
299  if (hitRegion == -1)
300  hitRegion = 0;
301 
302  // Pass the damage to the region
303  AddRegionDamage(hitRegion, damage);
304  }
305  }
306 
307  //------------------------------------------------------------------------------------------------
308  #ifdef BUILDING_DESTRUCTION_DEBUG
309 
310  //------------------------------------------------------------------------------------------------
311  bool GetCameraViewIntersect()
312  {
313  if (!m_BuildingSetup)
314  return false;
315 
316  vector camMat[4];
317  GetWorld().GetCurrentCamera(camMat);
318 
319  vector from = CoordToLocal(camMat[3]);
320  vector to = VectorToLocal(camMat[2]);
321  to = to * 1000 + from;
322  float intersect = Math3D.IntersectRayBox(from, to, m_BuildingSetup.m_vBuildingMins, m_BuildingSetup.m_vBuildingMaxs);
323  if (intersect >= 0)
324  return true;
325  else
326  return false;
327  }
328 
329  #ifdef WORKBENCH
330  //------------------------------------------------------------------------------------------------
331  override void _WB_AfterWorldUpdate(float timeSlice)
332  {
333  if (m_BuildingConfig != string.Empty)
334  m_BuildingSetup = SCR_BuildingConfigManagerEntity.GetBuildingSetupFromConfig(m_BuildingConfig);
335 
336  UpdateDebug(timeSlice);
337  }
338  #endif
339 
340  //------------------------------------------------------------------------------------------------
341  override protected void EOnFrame(IEntity owner, float timeSlice) //EntityEvent.FRAME
342  {
343  UpdateDebug(timeSlice);
344  }
345 
346  //------------------------------------------------------------------------------------------------
347  private void UpdateDebug(float timeSlice)
348  {
349  if (!m_BuildingSetup)
350  return;
351 
352  // If we are not looking at the building with the camera, delete highlight and return
353  if (!GetCameraViewIntersect())
354  return;
355 
356  DisplayRegions();
357 
358  vector pos = GetOrigin();
359  vector textMat[4];
360 
361  GetWorld().GetCurrentCamera(textMat);
362  textMat[3] = GetOrigin() + Vector(0, m_BuildingSetup.m_vBuildingMaxs[1] + 2, 0);
363 
364  if (GetDestroyed())
365  CreateSimpleText("DESTROYED", textMat, 0.5, ARGB(0, 255, 0, 0), ShapeFlags.ONCE|ShapeFlags.NOZBUFFER, null, 0.7);
366  else if (GetDamaged())
367  {
368  CreateSimpleText("DAMAGED", textMat, 0.5, ARGB(0, 255, 128, 0), ShapeFlags.ONCE|ShapeFlags.NOZBUFFER, null, 0.7);
369  float dmgPct = 0;
370  for (int i = 0; i < GetRegionsCount(); i++)
371  {
372  dmgPct += GetRegionDamage01(i) / GetRegionsCount();
373  }
374  textMat[3] = textMat[1] * -0.6 + textMat[3];
375  CreateSimpleText(Math.Floor(dmgPct * 100).ToString() + "%", textMat, 0.5, ARGB(0, 255, 128, 0), ShapeFlags.ONCE|ShapeFlags.NOZBUFFER, null, 0.7);
376  }
377  else
378  CreateSimpleText("UNDAMAGED", textMat, 0.5, ARGB(0, 0, 255, 0), ShapeFlags.ONCE|ShapeFlags.NOZBUFFER, null, 0.7);
379  }
380 
381  //------------------------------------------------------------------------------------------------
383  void DisplayRegions()
384  {
385  if (!m_BuildingSetup)
386  return;
387 
388  vector textMat[4];
389  GetWorld().GetCurrentCamera(textMat);
390  vector camDir = textMat[2];
391  vector camPos = textMat[3];
392 
393  int highlightRegion = -1;
394  float highlightDist = -1;
395 
396  // First get the region we are highlighting (if at all)
397  for (int i = 0; i < GetRegionsCount(); i++)
398  {
399  SCR_BuildingRegion regionStruct = m_BuildingSetup.GetRegionStruct(i);
400  if (!regionStruct)
401  continue;
402 
403  vector regionPos = CoordToParent(regionStruct.GetRegionPos());
404 
405  vector intersectScreenDiff = regionPos.InvMultiply4(textMat);
406  intersectScreenDiff[2] = 0;
407 
408  float distScale = vector.Distance(camPos, regionPos) * 0.1;
409  distScale = Math.Clamp(distScale, 0.5, 5);
410 
411  float distToCircle = intersectScreenDiff.Length() / distScale;
412  if (distToCircle < 0.75 && (distToCircle < highlightDist || highlightDist == -1))
413  {
414  highlightRegion = i;
415  highlightDist = distToCircle;
416  }
417  }
418 
419  for (int i = 0; i < GetRegionsCount(); i++)
420  {
421  SCR_BuildingRegion regionStruct = m_BuildingSetup.GetRegionStruct(i);
422  if (!regionStruct)
423  continue;
424 
425  vector regionPos = CoordToParent(regionStruct.GetRegionPos());
426 
427  float distScale = vector.Distance(camPos, regionPos) * 0.1;
428  distScale = Math.Clamp(distScale, 0.5, 3);
429 
430  textMat[3] = textMat[1] * 0.05 * distScale + regionPos;
431 
432  // Display debug info about the region
433  if (i == highlightRegion)
434  {
435  int color = ARGBF(1, 1, 1, 1);
436  CreateSimpleText("Region " + i.ToString(), textMat, 0.17 * distScale, color, ShapeFlags.ONCE | ShapeFlags.TRANSP | ShapeFlags.NOZBUFFER, null, 0.7, true, ARGB(128, 0, 0, 0));
437  textMat[3] = textMat[1] * -0.3 * distScale + textMat[3];
438  CreateSimpleText(GetRegionDamage(i).ToString() + "/" + GetRegionMaxDamage(i).ToString(), textMat, 0.17 * distScale, color, ShapeFlags.ONCE | ShapeFlags.TRANSP | ShapeFlags.NOZBUFFER, null, 0.7, true, ARGB(128, 0, 0, 0));
439  CreateCircle(regionPos, textMat[2], 0.75 * distScale, ARGBF(0.25, 1, 1, 1), 24, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER | ShapeFlags.TRANSP);
440  CreateCircle(regionPos, textMat[2], ((1 - GetRegionDamage01(i)) * 0.25 + 0.75) * distScale, color, 24, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER);
441  CreateCircle(regionPos, textMat[2], distScale, ARGBF(0.25, 1, 1, 1), 24, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER | ShapeFlags.TRANSP);
442  }
443  else
444  {
445  int color = ARGBF(0.1, 1, 1 - GetRegionDamage01(i), 1 - GetRegionDamage01(i));
446  CreateCircle(regionPos, textMat[2], 0.15 * distScale, color, 24, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER | ShapeFlags.TRANSP);
447  CreateCircle(regionPos, textMat[2], 0.01 * distScale, color, 4, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER | ShapeFlags.TRANSP);
448  textMat[3] = textMat[1] * 0.18 * distScale + textMat[3];
449  CreateSimpleText(i.ToString(), textMat, 0.17 * distScale, color, ShapeFlags.ONCE | ShapeFlags.TRANSP | ShapeFlags.NOZBUFFER);
450  }
451 
452  // Display links to supported regions
453  for (int s = 0; s < regionStruct.GetConnectionNumOut(); s++)
454  {
455  SCR_BuildingRegion suppRegionStruct = regionStruct.GetConnectedRegionOut(s);
456  if (!suppRegionStruct)
457  continue;
458 
459  int suppRegion = suppRegionStruct.GetRegionIndex();
460  vector suppRegionPos = CoordToParent(suppRegionStruct.GetRegionPos());
461 
462  int arrowsColor = ARGBF(0.02, 1, 1, 1);
463  if (i == highlightRegion || suppRegion == highlightRegion)
464  arrowsColor = ARGB(255, 128, 128, 64);
465 
466  int numArrows = Math.Ceil(vector.Distance(suppRegionPos, regionPos) * 5 / distScale);
467  if (numArrows == 0)
468  numArrows = 1;
469  CreateArrowLinkLines(regionPos, suppRegionPos, camDir, 0.08 * distScale, numArrows, arrowsColor, ShapeFlags.ONCE | ShapeFlags.TRANSP | ShapeFlags.NOZBUFFER);
470  }
471  }
472  }
473  #endif
474 
475  //------------------------------------------------------------------------------------------------
477  protected void OnRegionDestroyed(int region, bool doDamageEffects)
478  {
479  SCR_BuildingRegionEntity regionEnt = null;
480  if (m_RegionEntities && m_RegionEntities.Count() > region)
481  regionEnt = m_RegionEntities.Get(region);
482 
483  if (!regionEnt)
484  return;
485 
486  SCR_DebrisBuildingEntity buildingDebris = null;
487  if (doDamageEffects)
488  buildingDebris = SpawnFallingRegionDebris(region);
489 
490  DestroyPropsForRegion(regionEnt, buildingDebris);
491 
492  if (m_SoundComponent)
493  {
494  vector camMat[4], regionMat[4];
495  GetWorld().GetCurrentCamera(camMat);
496  regionEnt.GetTransform(regionMat);
497 
498  m_SoundComponent.SetSignalValueStr("partSoundID", region);
499  m_SoundComponent.SetSignalValueStr("Distance", vector.Distance(camMat[3], SCR_EntityHelper.GetEntityCenterWorld(regionEnt)));
500  m_SoundComponent.SoundEventTransform(SCR_SoundEvent.SOUND_BUILDING_CRACK, regionMat)
501  }
502  }
503 
504  //------------------------------------------------------------------------------------------------
506  protected void OnRegionRepaired(int region)
507  {
508  }
509 
510  //------------------------------------------------------------------------------------------------
512  vector GetRegionPosition(int regionNumber)
513  {
514  if (!m_BuildingSetup)
515  return vector.Zero;
516 
517  SCR_BuildingRegion regionStruct = m_BuildingSetup.GetRegionStruct(regionNumber);
518  if (!regionStruct)
519  return vector.Zero;
520 
521  return CoordToParent(regionStruct.GetRegionPos());
522  }
523 
524  //------------------------------------------------------------------------------------------------
526  protected SCR_DebrisBuildingEntity SpawnFallingRegionDebris(int region)
527  {
528  // Get the region
529  SCR_BuildingRegion regionStruct = m_BuildingSetup.GetRegionStruct(region);
530  if (!regionStruct)
531  return null;
532 
533  vector mat[4];
534  GetTransform(mat);
535 
536  SCR_DebrisBuildingEntity buildingDebris = SCR_DebrisBuildingEntity.SpawnBuildingDebris(mat, m_BuildingSetup, region, GetRegionEntity(region));
537  if (!buildingDebris)
538  return null;
539 
540  vector regionDir = buildingDebris.CoordToParent(regionStruct.GetRegionPos()) - buildingDebris.GetOrigin();
541  buildingDebris.SetLinearVelocity(buildingDebris.GetLinearVelocity() + regionDir * Math.RandomFloat(0, 0.1));
542  buildingDebris.SetAngularVelocity(buildingDebris.GetAngularVelocity() + Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * 2);
543 
544  return buildingDebris;
545  }
546 
547  //------------------------------------------------------------------------------------------------
549  protected void CheckStructuralIntegrity(int region)
550  {
551  if (!m_BuildingSetup)
552  return;
553 
554  // Region is not destroyed, so no need for any structural checks
555  if (!GetRegionDestroyed(region))
556  return;
557 
558  // Random fall direction and speed (for any potential falling parts)
559  //vector fallLinVel = Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * 0.5;
560  //vector fallAngVel = Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * 5;
561 
562  // Create an array to hold all regions that must be checked
563  autoptr array<int> toCheckRegionsList = new array<int>;
564  toCheckRegionsList.Insert(region);
565 
566  while (toCheckRegionsList.Count() > 0)
567  {
568  // Get the first region in the to check list
569  int checkRegion = toCheckRegionsList.Get(0);
570  toCheckRegionsList.Remove(0);
571 
572  // Get the region
573  SCR_BuildingRegion regionStruct = m_BuildingSetup.GetRegionStruct(checkRegion);
574  if (!regionStruct)
575  continue;
576 
577  // If this is the region that started the structural integrity check, skip creating falling debris etc
578  if (checkRegion != region)
579  {
580  // Go through and get all regions that are supporting the checked region
581  int numSupportingRegions = regionStruct.GetConnectionNumIn();
582  int numOKSupportingRegions = 0;
583  for (int n = 0; n < numSupportingRegions; n++)
584  {
585  SCR_BuildingRegion regionSupportingStruct = regionStruct.GetConnectedRegionIn(n);
586 
587  if (GetRegionDestroyed(regionSupportingStruct.GetRegionIndex())) // Already destroyed, skip
588  continue;
589 
590  numOKSupportingRegions++;
591  }
592 
593  // If the amount of regions holding us up above or equal to required, skip
594  float heldPct = (float)numOKSupportingRegions / (float)numSupportingRegions;
595  if (heldPct >= regionStruct.GetStructuralSupportPercentage())
596  continue;
597 
598  // Not enough holding us up, so destroy the region too and create falling debris
599  SetRegionDamage01(checkRegion, 1, false, true, false);
600  }
601 
602  // Add all the regions the checked region is supporting to the list
603  for (int i = 0; i < regionStruct.GetConnectionNumOut(); i++)
604  {
605  SCR_BuildingRegion regionSupportedStruct = regionStruct.GetConnectedRegionOut(i);
606 
607  int r = regionSupportedStruct.GetRegionIndex();
608  if (toCheckRegionsList.Find(r) > -1) // Already in the list, skip
609  continue;
610 
611  if (GetRegionDestroyed(r)) // Already destroyed, skip
612  continue;
613 
614  toCheckRegionsList.Insert(r);
615  }
616  }
617  }
618 
619  //------------------------------------------------------------------------------------------------
621  protected bool IsProxy()
622  {
623  return (m_RplComponent && m_RplComponent.IsProxy());
624  }
625 
626  //------------------------------------------------------------------------------------------------
628  bool GetUndamaged()
629  {
630  if (!m_bDestroyed && !m_RegionMask && !m_RegionDamage)
631  return true;
632  else
633  return false;
634  }
635 
636  //------------------------------------------------------------------------------------------------
638  bool GetDestroyed()
639  {
640  return m_bDestroyed;
641  }
642 
643  //------------------------------------------------------------------------------------------------
645  bool GetDamaged()
646  {
647  if (GetUndamaged())
648  return false;
649  else if (GetDestroyed())
650  return false;
651  else
652  return true;
653  }
654 
655  //------------------------------------------------------------------------------------------------
657  bool GetRegionDestroyed(int regionNumber)
658  {
659  if (GetDestroyed())
660  return true;
661 
662  if (!m_RegionMask)
663  return false;
664 
665  return m_RegionMask.GetBit(regionNumber);
666  }
667 
668  //------------------------------------------------------------------------------------------------
670  int GetRegionsCount()
671  {
672  if (!m_BuildingSetup)
673  return 0;
674 
675  return m_BuildingSetup.GetRegionNum();
676  }
677 
678  //------------------------------------------------------------------------------------------------
680  float GetRegionMaxDamage(int regionNumber)
681  {
682  if (!m_BuildingSetup)
683  return 0;
684 
685  if (regionNumber < 0) // Out of limits, return 0
686  return 0;
687 
688  if (regionNumber >= GetRegionsCount()) // Above region count, return 0
689  return 0;
690 
691  SCR_BuildingRegion regionStruct = m_BuildingSetup.GetRegionStruct(regionNumber);
692  if (!regionStruct)
693  return 0;
694 
695  return regionStruct.GetMaxHealth();
696  }
697 
698  //------------------------------------------------------------------------------------------------
700  float GetRegionDamage(int regionNumber)
701  {
702  // Building undamaged, so neither is region
703  if (GetUndamaged())
704  return 0;
705 
706  // Building completely destroyed, so region is too
707  if (GetDestroyed())
708  return GetRegionMaxDamage(regionNumber);
709 
710  // Region is in the bit array, so is destroyed
711  if (m_RegionMask && m_RegionMask.GetBit(regionNumber))
712  return GetRegionMaxDamage(regionNumber);
713 
714  // No stored damage values, so this region is undamaged
715  if (!m_RegionDamage)
716  return 0;
717 
718  // Return the stored damage value
719  return m_RegionDamage.Get(regionNumber);
720  }
721 
722  //------------------------------------------------------------------------------------------------
724  float GetRegionDamage01(int regionNumber)
725  {
726  if (regionNumber >= GetRegionsCount())
727  return 0;
728 
729  float maxDamage = GetRegionMaxDamage(regionNumber);
730  if (maxDamage == 0)
731  return 0;
732 
733  return GetRegionDamage(regionNumber) / maxDamage;
734  }
735 
736  //------------------------------------------------------------------------------------------------
738  protected void SetRegionDamage(int regionNumber, float damage, bool doStructuralIntegrityCheck = true, bool doDamageEffects = true, bool sendRPC = true)
739  {
740  if (!m_BuildingSetup)
741  return;
742 
743  if (regionNumber >= GetRegionsCount())
744  return;
745 
746  float maxDamage = GetRegionMaxDamage(regionNumber);
747 
748  // If we are completely destroyed and wanting to set more damage, skip
749  if (GetDestroyed() && damage >= maxDamage)
750  return;
751 
752  // If we are completely undamaged and wanting to set no damage, skip
753  if (GetUndamaged() && damage <= 0)
754  return;
755 
756  // Get our state as 3 state int
757  int state = 0;
758  if (GetDamaged())
759  state = 1;
760  else if (GetDestroyed())
761  state = 2;
762 
763  damage = Math.Clamp(damage, 0, maxDamage);
764  float curDam = GetRegionDamage(regionNumber);
765 
766  // Setting same damage, skip
767  if (curDam == damage)
768  return;
769 
770  if (sendRPC && !IsProxy())
771  {
772  if (damage >= maxDamage)
773  Rpc(RPC_OnRegionDestroyed, regionNumber, true, doStructuralIntegrityCheck, doDamageEffects);
774  else if (damage <= 0)
775  Rpc(RPC_OnRegionDestroyed, regionNumber, false, doStructuralIntegrityCheck, doDamageEffects);
776  }
777 
778  // Building destroyed but setting damage below max, so 'undestroy' and set all zones to destroyed (this zone will be adjusted below)
779  if (GetDestroyed() && damage < maxDamage)
780  {
781  SetDestroyedState(false, false);
782  SetAllZonesDestroyed();
783  }
784 
785  // Set the zone to undamaged or destroyed
786  if (damage == 0 || damage == maxDamage)
787  {
788  if (damage == 0) // Undamaged, remove region from mask
789  {
790  // Remove region from the bitarray
791  if (m_RegionMask)
792  {
793  m_RegionMask.SetBit(regionNumber, false);
794  if (m_RegionMask.GetEmpty())
795  delete m_RegionMask;
796  }
797 
798  OnRegionRepaired(regionNumber);
799  }
800  else if (damage == maxDamage) // Destroyed, add region to mask
801  {
802  // Add region to the bitarray
803  if (!m_RegionMask)
804  m_RegionMask = new SCR_BitMaskArray(GetRegionsCount());
805  m_RegionMask.SetBit(regionNumber, true);
806 
807  OnRegionDestroyed(regionNumber, doDamageEffects);
808  }
809 
810  // Find our region in the map and remove it if found
811  if (m_RegionDamage)
812  {
813  for (int i = 0; i < m_RegionDamage.Count(); i++)
814  {
815  if (m_RegionDamage.GetKey(i) == regionNumber)
816  {
817  m_RegionDamage.RemoveElement(i);
818  break;
819  }
820  }
821 
822  // If no more stored damage values left, delete the map
823  if (m_RegionDamage.Count() == 0)
824  delete m_RegionDamage;
825  }
826  }
827  else // Damage is non-zero and not maximum, so set it
828  {
829  // Remove region from the bitarray
830  if (m_RegionMask)
831  {
832  m_RegionMask.SetBit(regionNumber, false);
833  if (m_RegionMask.GetEmpty())
834  delete m_RegionMask;
835  }
836 
837  // Damage value map does not exist, so create it
838  if (!m_RegionDamage)
839  m_RegionDamage = new map<int, float>;
840 
841  if (m_RegionDamage.Contains(regionNumber)) // Region damage already stored, so change it
842  m_RegionDamage.Set(regionNumber, damage);
843  else // Add region damage to the map
844  m_RegionDamage.Insert(regionNumber, damage);
845  }
846 
847  // All regions have damage set, so go to destroyed state
848  if (GetAllZonesAtMaxDamage())
849  SetDestroyedState(true, false);
850 
851  // Get our new state as 3 stage int
852  int newState = 0;
853  if (GetDamaged())
854  newState = 1;
855  else if (GetDestroyed())
856  newState = 2;
857 
858  // Our state has changed, so update the model to reflect this
859  if (newState != state)
860  UpdateBuildingModel();
861 
862  // Update the region display of the model based on damage and check structural integrity
863  if (GetDamaged())
864  {
865  UpdateBuildingRegions();
866  if (doStructuralIntegrityCheck)
867  CheckStructuralIntegrity(regionNumber);
868  }
869  }
870 
871  //------------------------------------------------------------------------------------------------
873  void SetRegionDamage01(int regionNumber, float damagePct, bool doStructuralIntegrityCheck = true, bool doDamageEffects = true, bool sendRPC = true)
874  {
875  SetRegionDamage(regionNumber, GetRegionMaxDamage(regionNumber) * damagePct, doStructuralIntegrityCheck, doDamageEffects, sendRPC);
876  }
877 
878  //------------------------------------------------------------------------------------------------
880  void AddRegionDamage(int regionNumber, float damage, bool doStructuralIntegrityCheck = true, bool doDamageEffects = true, bool sendRPC = true)
881  {
882  SetRegionDamage(regionNumber, GetRegionDamage(regionNumber) + damage, doStructuralIntegrityCheck, doDamageEffects, sendRPC);
883  }
884 
885  //------------------------------------------------------------------------------------------------
887  void SetDestroyedState(bool destroyed, bool updateModel = true)
888  {
889  // Delete any stored damage values
890  if (m_RegionDamage)
891  delete m_RegionDamage;
892 
893  // Delete any stored region masks
894  if (m_RegionMask)
895  delete m_RegionMask;
896 
897  m_bDestroyed = destroyed;
898 
899  if (updateModel)
900  UpdateBuildingModel();
901  }
902 
903  //------------------------------------------------------------------------------------------------
905  SCR_BuildingRegionEntity GetRegionEntity(int regionNumber)
906  {
907  if (!m_RegionEntities)
908  return null;
909 
910  if (m_RegionEntities.Count() > regionNumber)
911  return m_RegionEntities.Get(regionNumber);
912 
913  return null;
914  }
915 
916  //------------------------------------------------------------------------------------------------
918  private SCR_BuildingRegionEntity SpawnRegionEntity(int regionNumber)
919  {
920  if (!m_RegionEntities)
921  m_RegionEntities = new array<SCR_BuildingRegionEntity>;
922 
923  SCR_BuildingRegionEntity regionEnt = null;
924  if (m_RegionEntities.Count() > regionNumber)
925  regionEnt = m_RegionEntities.Get(regionNumber);
926 
927  if (regionEnt)
928  return regionEnt;
929 
930  vector buildingMat[4];
931  GetTransform(buildingMat);
932 
933  //regionEnt = SCR_BuildingRegionEntity.Cast(GetGame().SpawnEntityPrefab(Resource.Load("{944DD356E5175140}Prefabs/Test/BuildingRegion.et")));
934 
935  if (!regionEnt)
936  return null;
937 
938  regionEnt.SetBuildingAndIndex(this, regionNumber);
939  regionEnt.LoadRegionModel();
940 
941  AddChild(regionEnt, -1, EAddChildFlags.NONE);
942  regionEnt.SetTransform(buildingMat);
943 
944  m_RegionEntities.InsertAt(regionEnt, regionNumber);
945 
946  return regionEnt;
947  }
948 
949  //------------------------------------------------------------------------------------------------
951  bool GetPropDestructible(notnull IEntity prop)
952  {
953  GenericEntity genEnt = GenericEntity.Cast(prop);
954  if (!genEnt)
955  return false;
956 
957  // If we have a destructible component then we may be destroyed
958  if (genEnt.FindComponent(SCR_DestructionDamageManagerComponent))
959  return true;
960 
961  // If we have a ladder component then we may be destroyed
962  if (genEnt.FindComponent(LadderComponent))
963  return true;
964 
965  return false;
966  }
967 
968  //------------------------------------------------------------------------------------------------
971  bool QueryRegionProp(IEntity prop, bool propIsChild = false, float traceUp = 0.1, float traceDown = 0.1)
972  {
973  if (!prop)
974  return true;
975 
976  // Is a building
977  if (SCR_DestructibleBuildingEntity.Cast(prop))
978  return true;
979 
980  // Is a building region
981  if (SCR_BuildingRegionEntity.Cast(prop))
982  return true;
983 
984  // Prop has a parent that is not the building, so ignore (as the children of the building are destroyed)
985  if (prop.GetParent() && prop.GetParent() != this)
986  return true;
987 
988  // Prop is not a child, so limit what we can destroy to certain types
989  if (!propIsChild && !GetPropDestructible(prop))
990  return true;
991 
992  // Prop is already in the list
993  if (s_aQueryPropsList.Find(prop) >= 0)
994  return true;
995 
996  vector mins, maxs, mat[4];
997  prop.GetWorldTransform(mat);
998  /*prop.GetWorldBounds(mins, maxs);
999 
1000  vector center = (maxs - mins) * 0.5 + mins;
1001  vector size;
1002  for (int a = 0; a < 3; a++)
1003  {
1004  size[a] = Math.AbsFloat(maxs[a] - mins[a]);
1005  }
1006  autoptr TraceParam param = new TraceParam;
1007  param.Flags = TraceFlags.ENTS | TraceFlags.WORLD;
1008  param.Start = center;
1009  param.End = center - vector.Up * (size[1]) + mat[2] * 0.1;
1010  */
1011  prop.GetBounds(mins, maxs);
1012  for (int a = 0; a < 3; a++)
1013  {
1014  float min = mins[a] + 0.2;
1015  float max = maxs[a] - 0.2;
1016 
1017  if (min >= 0)
1018  min = -0.05;
1019  if (max <= 0)
1020  max = 0.05;
1021 
1022  mins[a] = min;
1023  maxs[a] = max;
1024  }
1025 
1026  autoptr TraceOBB param = new TraceOBB;
1027  param.Mat[0] = mat[0];
1028  param.Mat[1] = mat[1];
1029  param.Mat[2] = mat[2];
1030  param.Flags = TraceFlags.ENTS | TraceFlags.WORLD;
1031  param.LayerMask = EPhysicsLayerDefs.Default;
1032  param.Mins = mins;
1033  param.Maxs = maxs;
1034  // TODO: REMOVE THIS TEMPORARY OVERRIDE IN SIZE!!!!! Once box tracing is fixed.
1035  param.Mins = -vector.One;
1036  param.Maxs = vector.One;
1037 
1038  param.Start = mat[3] + vector.Up * 1;
1039  param.End = mat[3] - vector.Up * 1;
1040 
1041  SCR_Global.g_TraceFilterEnt = s_QueryBuildingRegion;
1042  float traced = m_World.TraceMove(param, SCR_Global.FilterCallback_IgnoreAllButEntity);
1043 
1044  // The prop is a child and is floating in mid-air somewhere or traced the building region we are interested in
1045  //if ((propIsChild && traced == 1) || param.TraceEnt == s_QueryBuildingRegion)
1046  if (traced < 1 && param.TraceEnt == s_QueryBuildingRegion)
1047  s_aQueryPropsList.Insert(prop);
1048 
1049  #ifdef BUILDING_DEBUG_TEMP
1050  Shape shp;
1051 
1052  int color = ARGB(255, 255, 0, 0);
1053  if (traced < 1)
1054  color = ARGB(255, 0, 255, 0);
1055 
1056  int color2 = ARGB(255, 0, 0, 255);
1057 
1058  vector mins2 = param.Mins - vector.One * 0.025;
1059  vector maxs2 = param.Maxs + vector.One * 0.025;
1060 
1061  // Start trace - target
1062  shp = Shape.Create(ShapeType.BBOX, color2, ShapeFlags.VISIBLE | ShapeFlags.NOZBUFFER | ShapeFlags.WIREFRAME, param.Mins, param.Maxs);
1063  mat[3] = param.Start;
1064  shp.SetMatrix(mat);
1065  debugShapes.Insert(shp);
1066 
1067  // End trace - target
1068  shp = Shape.Create(ShapeType.BBOX, color2, ShapeFlags.VISIBLE | ShapeFlags.NOZBUFFER | ShapeFlags.WIREFRAME, param.Mins, param.Maxs);
1069  mat[3] = param.End;
1070  shp.SetMatrix(mat);
1071  debugShapes.Insert(shp);
1072 
1073  // Trace - target
1074  shp = Shape.Create(ShapeType.LINE, color2, ShapeFlags.VISIBLE | ShapeFlags.NOZBUFFER, param.Start, param.End);
1075  debugShapes.Insert(shp);
1076 
1077  // Start trace - result
1078  shp = Shape.Create(ShapeType.BBOX, color, ShapeFlags.VISIBLE | ShapeFlags.NOZBUFFER | ShapeFlags.WIREFRAME, mins2, maxs2);
1079  mat[3] = param.Start;
1080  shp.SetMatrix(mat);
1081  debugShapes.Insert(shp);
1082 
1083  // End trace - result
1084  shp = Shape.Create(ShapeType.BBOX, color, ShapeFlags.VISIBLE | ShapeFlags.NOZBUFFER | ShapeFlags.WIREFRAME, mins2, maxs2);
1085  mat[3] = (param.End - param.Start) * traced + param.Start;
1086  shp.SetMatrix(mat);
1087  debugShapes.Insert(shp);
1088 
1089  // Trace - result
1090  shp = Shape.Create(ShapeType.LINE, color, ShapeFlags.VISIBLE | ShapeFlags.NOZBUFFER, param.Start + vector.One * 0.025, (param.End - param.Start) * traced + param.Start + vector.One * 0.025);
1091  debugShapes.Insert(shp);
1092 
1093  CreateSimpleText("REGION: " + s_QueryBuildingRegion.GetRegionNumber().ToString(), mat, 0.2, ARGB(255, 255, 255, 255), ShapeFlags.NOZBUFFER, debugShapes, 0.7);
1094 
1095  PrintFormat("REGION: %1", s_QueryBuildingRegion.GetRegionNumber());
1096  #endif
1097 
1098  return true;
1099  }
1100 
1101  bool QueryRegionPropCallback(IEntity e)
1102  {
1103  return QueryRegionProp(e);
1104  }
1105 
1106  //------------------------------------------------------------------------------------------------
1108  void GetPropsForRegion(SCR_BuildingRegionEntity regionEnt)
1109  {
1110  #ifdef BUILDING_DEBUG_TEMP
1111  debugShapes.Clear();
1112  #endif
1113 
1114  s_aQueryPropsList.Clear();
1115  s_QueryBuildingRegion = regionEnt;
1116 
1117  if (!s_QueryBuildingRegion)
1118  return;
1119 
1120  // First go through direct children (which have correctly set hierarchies)
1121  IEntity child = GetChildren();
1122  while (child)
1123  {
1124  IEntity prop = child;
1125  child = child.GetSibling();
1126 
1127  QueryRegionProp(prop, true);
1128  }
1129 
1130  // Now go through objects within the bounding box of the region
1131  if (!m_World)
1132  return;
1133 
1134  vector regionMins, regionMaxs, regionMat[4];
1135  s_QueryBuildingRegion.GetWorldBounds(regionMins, regionMaxs);
1136 
1137  m_World.QueryEntitiesByAABB(regionMins, regionMaxs, QueryRegionPropCallback);
1138  }
1139 
1140  //------------------------------------------------------------------------------------------------
1141  // Copies the input prop object (and its children) to the building debris
1142  protected void CopyPropToBuildingDebris(SCR_DebrisBuildingEntity buildingDebris, IEntity prop, vector debrisMat[4])
1143  {
1144  if (!buildingDebris)
1145  return;
1146 
1147  if (!prop)
1148  return;
1149 
1150  // Recursively call through all children
1151  IEntity propChild = prop.GetChildren();
1152  while (propChild)
1153  {
1154  CopyPropToBuildingDebris(buildingDebris, propChild, debrisMat);
1155  propChild = propChild.GetSibling();
1156  }
1157 
1158  // Get the prop's model
1159  VObject obj = prop.GetVObject();
1160  if (!obj)
1161  return;
1162 
1163  // Get its relative transform to the building debris
1164  vector propMat[4], localPropMat[4];
1165  prop.GetWorldTransform(propMat);
1166  Math3D.MatrixInvMultiply4(debrisMat, propMat, localPropMat);
1167 
1168  // Create a copy of the prop (visual only) and attach it to the building debris
1170  propCopy.SetObject(obj, string.Empty);
1171  propCopy.SetTransform(localPropMat);
1172  buildingDebris.AddChild(propCopy, -1, EAddChildFlags.AUTO_TRANSFORM);
1173  }
1174 
1175  //------------------------------------------------------------------------------------------------
1176  // Checks for any door/window/etc intersection and destroys the object as well
1177  protected void DestroyPropsForRegion(SCR_BuildingRegionEntity regionEnt, SCR_DebrisBuildingEntity buildingDebris)
1178  {
1179  if (!regionEnt)
1180  return;
1181 
1182  GetPropsForRegion(regionEnt);
1183 
1184  vector debrisMat[4];
1185  if (buildingDebris)
1186  buildingDebris.GetWorldTransform(debrisMat);
1187 
1188  int numProps = s_aQueryPropsList.Count();
1189  for (int i = numProps - 1; i >= 0; i--)
1190  {
1191  IEntity prop = s_aQueryPropsList.Get(i);
1192  if (!prop)
1193  continue;
1194 
1195  // Destroy any destructibles
1196  GenericEntity genProp = GenericEntity.Cast(prop);
1197  if (genProp)
1198  {
1199  SCR_DestructionDamageManagerComponent destructible = SCR_DestructionDamageManagerComponent.Cast(genProp.FindComponent(SCR_DestructionDamageManagerComponent));
1200  if (destructible)
1201  {
1202  vector mat[3];
1203  Math3D.MatrixIdentity3(mat);
1204  destructible.HandleDamage(EDamageType.EXPLOSIVE, destructible.GetMaxHealth(), mat, destructible.GetOwner(), null, this, null, -1, -1);
1205  }
1206  }
1207 
1208  if (buildingDebris)
1209  CopyPropToBuildingDebris(buildingDebris, prop, debrisMat);
1210 
1211  // TODO: Hide prop and disable physics instead of deleting? To allow repair
1212  SCR_EntityHelper.DeleteEntityAndChildren(prop);
1213  //prop.ClearFlags(EntityFlags.VISIBLE | EntityFlags.ACTIVE, true);
1214  //Physics phys = prop.GetPhysics();
1215  //if (phys)
1216  // disable physics here!
1217  }
1218  }
1219 
1220  //------------------------------------------------------------------------------------------------
1221  // Delete a region entity
1222  private void DeleteRegionEntity(int regionNumber)
1223  {
1224  if (!m_RegionEntities || m_RegionEntities.Count() <= regionNumber)
1225  return;
1226 
1227  SCR_BuildingRegionEntity regionEnt = m_RegionEntities.Get(regionNumber);
1228  if (regionEnt)
1229  delete regionEnt;
1230  else
1231  return;
1232 
1233  // Check whether there are any regions left in the array
1234  for (int i = 0; i < m_RegionEntities.Count(); i++)
1235  {
1236  regionEnt = m_RegionEntities.Get(i);
1237  if (regionEnt) // Found a region, so return
1238  return;
1239  }
1240 
1241  // No region entities left, so delete the array
1242  delete m_RegionEntities;
1243  m_RegionEntities = null;
1244  }
1245 
1246  //------------------------------------------------------------------------------------------------
1248  private void DeleteAllRegionEntities()
1249  {
1250  if (!m_RegionEntities)
1251  return;
1252 
1253  for (int i = m_RegionEntities.Count() - 1; i > -1; i--)
1254  {
1255  SCR_BuildingRegionEntity regionEnt = m_RegionEntities.Get(i);
1256  m_RegionEntities.Remove(i);
1257  delete regionEnt;
1258  }
1259 
1260  delete m_RegionEntities;
1261  m_RegionEntities = null;
1262  }
1263 
1264  //------------------------------------------------------------------------------------------------
1266  private void SpawnAllRegionEntities(bool addRegionsToTraceIgnoreList = false)
1267  {
1268  if (addRegionsToTraceIgnoreList)
1269  SCR_Global.g_TraceFilterList.Clear();
1270 
1271  DeleteAllRegionEntities();
1272 
1273  for (int i = 0; i < GetRegionsCount(); i++)
1274  {
1275  SCR_BuildingRegionEntity region = SpawnRegionEntity(i);
1276  if (addRegionsToTraceIgnoreList && region)
1277  SCR_Global.g_TraceFilterList.Insert(region);
1278  }
1279  }
1280 
1281  //------------------------------------------------------------------------------------------------
1283  private void UpdateBuildingModel(int forceState = -1, bool addRegionsToTraceIgnoreList = false)
1284  {
1285  if (!m_BuildingSetup)
1286  return;
1287 
1288  int buildingState = BuildingDamageState.UNDAMAGED;
1289  if (GetDestroyed())
1290  buildingState = BuildingDamageState.DESTROYED;
1291  else
1292  buildingState = BuildingDamageState.DAMAGED;
1293 
1294  // We are forcing a new state, so use it
1295  if (forceState != -1)
1296  buildingState = forceState;
1297 
1298  ResourceName assetPath = m_BuildingSetup.m_ModelUndamaged;
1299  if (buildingState == BuildingDamageState.DESTROYED)
1300  assetPath = m_BuildingSetup.m_ModelDestroyed;
1301  else if (buildingState == BuildingDamageState.DAMAGED)
1302  assetPath = "";
1303 
1304  // Delete any attachments to the building in destroyed state
1305  if (buildingState == BuildingDamageState.DESTROYED)
1306  {
1307  IEntity child = GetChildren();
1308  while (child)
1309  {
1310  //delete child;
1311  //child = GetChildren();
1312  child = child.GetSibling();
1313  }
1314  }
1315  else
1316  {
1317  //Print("=================");
1318  IEntity child = GetChildren();
1319  while (child)
1320  {
1321  //delete child;
1322  //child = GetChildren();
1323  if (child.GetFlags() & EntityFlags.PROXY)
1324  {
1325  child.ClearFlags(EntityFlags.PROXY, false);
1326  child.Update();
1327  }
1328  //if (child.GetFlags() & EntityFlags.PROXY)
1329  // Print(child.GetVObject().ToString());
1330  child = child.GetSibling();
1331  }
1332  }
1333 
1334  // Updates physics and visual model
1335  Physics phys = GetPhysics();
1336  if (buildingState == BuildingDamageState.UNDAMAGED || buildingState == BuildingDamageState.DESTROYED)
1337  {
1338  if (phys)
1339  phys.Destroy();
1340  if (assetPath == "")
1341  {
1342  SetObject(null, "");
1343  ClearFlags(EntityFlags.VISIBLE, false);
1344  }
1345  else
1346  {
1347  Resource resource = Resource.Load(assetPath);
1348  VObject asset = resource.GetResource().ToVObject();
1349  SetObject(asset, "");
1350  SetFlags(EntityFlags.VISIBLE, false);
1351 
1352  Physics.CreateStatic(this, -1);
1353  }
1354  }
1355  else
1356  {
1357  ClearFlags(EntityFlags.VISIBLE, false);
1358  if (phys)
1359  phys.Destroy();
1360  }
1361 
1362  // Create the region entities if we are damaged
1363  if (buildingState == BuildingDamageState.DAMAGED)
1364  SpawnAllRegionEntities(addRegionsToTraceIgnoreList);
1365  else
1366  DeleteAllRegionEntities();
1367  }
1368 
1369  //------------------------------------------------------------------------------------------------
1371  private void UpdateBuildingRegions()
1372  {
1373  if (!m_BuildingSetup)
1374  return;
1375 
1376  int regionNum = GetRegionsCount();
1377  for (int i = 0; i < regionNum; i++)
1378  {
1379  if (GetRegionDestroyed(i))
1380  {
1381  DeleteRegionEntity(i);
1382  continue;
1383  }
1384 
1385  SCR_BuildingRegionEntity regionEnt = SpawnRegionEntity(i);
1386 
1387  if (!regionEnt)
1388  return;
1389 
1390  // Create/destroy each region intersection debris
1391  for (int n = 0; n < regionNum; n++)
1392  {
1393  if (n == i) // Ignore the same region
1394  continue;
1395 
1396  // Other region is destroyed, so show the intersection debris
1397  if (GetRegionDestroyed(n))
1398  regionEnt.CreateIntersectDebris(n);
1399  else
1400  regionEnt.DeleteIntersectDebris(n);
1401  }
1402  }
1403  }
1404 
1405  //------------------------------------------------------------------------------------------------
1407  private void SetAllZonesDestroyed()
1408  {
1409  // Delete any stored damage values
1410  if (m_RegionDamage)
1411  delete m_RegionDamage;
1412 
1413  for (int i = 0; i < GetRegionsCount(); i++)
1414  {
1415  // Add region to the bitarray
1416  if (!m_RegionMask)
1417  m_RegionMask = new SCR_BitMaskArray(GetRegionsCount());
1418  m_RegionMask.SetBit(i, true);
1419  }
1420  }
1421 
1422  //------------------------------------------------------------------------------------------------
1424  bool GetAllZonesAtMaxDamage()
1425  {
1426  // No bitmask array, so no destroyed regions
1427  if (!m_RegionMask)
1428  return false;
1429 
1430  for (int i = 0; i < GetRegionsCount(); i++)
1431  {
1432  // If the region is in the bitmask array, go to the next as it is destroyed
1433  if (m_RegionMask.GetBit(i))
1434  continue;
1435 
1436  // Not all zones are destroyed
1437  return false;
1438  }
1439 
1440  return true;
1441  }
1442 
1443  //------------------------------------------------------------------------------------------------
1444  protected override void EOnInit(IEntity owner)
1445  {
1446  // Insert building and children into replication
1447  RplComponent rplComponent = RplComponent.Cast(FindComponent(RplComponent));
1448  if (rplComponent)
1449  {
1450  rplComponent.InsertToReplication();
1451  m_RplComponent = rplComponent;
1452  }
1453 
1454  m_SoundComponent = BaseSoundComponent.Cast(FindComponent(BaseSoundComponent));
1455  }
1456 
1457  //------------------------------------------------------------------------------------------------
1458  void SCR_DestructibleBuildingEntity(IEntitySource src, IEntity parent)
1459  {
1460  if (!GetGame().InPlayMode())
1461  return;
1462  m_World = GetWorld();
1463 
1464  //SetFlags(EntityFlags.ACTIVE, false);
1465  #ifdef BUILDING_DESTRUCTION_DEBUG
1466  SetEventMask(EntityEvent.FRAME);
1467  #endif
1468  SetEventMask(EntityEvent.INIT);
1469 
1470  if (m_BuildingConfig != string.Empty)
1471  m_BuildingSetup = SCR_BuildingConfigManagerEntity.GetBuildingSetupFromConfig(m_BuildingConfig);
1472  }
1473 
1474  //------------------------------------------------------------------------------------------------
1476  {
1477  if (!GetGame().InPlayMode())
1478  return;
1479 
1480  DeleteAllRegionEntities();
1481  }
1482  #endif
1483 };
BuildingDamageState
BuildingDamageState
Definition: SCR_DestructibleBuildingEntity.c:34
SpawnEntity
protected IEntity SpawnEntity(ResourceName entityResourceName, notnull IEntity slotOwner)
Definition: SCR_CatalogEntitySpawnerComponent.c:1008
GetPrefabData
SCR_VehicleDamageManagerComponentClass GetPrefabData()
Definition: SCR_VehicleDamageManagerComponent.c:260
SCR_EntityHelper
Definition: SCR_EntityHelper.c:1
SCR_DestructibleBuildingEntity
Definition: SCR_DestructibleBuildingEntity.c:47
EntityEditorProps
enum EQueryType EntityEditorProps(category:"GameScripted/Sound", description:"THIS IS THE SCRIPT DESCRIPTION.", color:"0 0 255 255")
Definition: SCR_AmbientSoundsComponent.c:12
UNDAMAGED
@ UNDAMAGED
Definition: SCR_DestructibleBuildingEntity.c:36
SCR_DestructibleBuildingEntityClass
Definition: SCR_DestructibleBuildingEntity.c:2
OnDamage
override protected void OnDamage(notnull BaseDamageContext damageContext)
Definition: SCR_ArmorDamageManagerComponent.c:11
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
EOnFrame
override void EOnFrame(IEntity owner, float timeSlice)
Definition: SCR_PlayerProfileManagerComponent.c:199
SCR_BuildingConfigManagerEntity
Definition: SCR_BuildingConfigManagerEntity.c:7
SCR_SoundEvent
Definition: SCR_SoundEvent.c:1
RplRpc
SCR_AchievementsHandlerClass ScriptComponentClass RplRpc(RplChannel.Reliable, RplRcver.Owner)] void UnlockOnClient(AchievementId achievement)
Definition: SCR_AchievementsHandler.c:11
RplLoad
override bool RplLoad(ScriptBitReader reader)
Definition: SCR_AIGroupInfoComponent.c:106
GenericEntity
SCR_GenericBoxEntityClass GenericEntity
DESTROYED
@ DESTROYED
Definition: SCR_DestructibleBuildingEntity.c:38
Instigator
Definition: Instigator.c:6
RplSave
override bool RplSave(ScriptBitWriter writer)
Definition: SCR_CampaignBuildingCompositionComponent.c:490
CreateArrowLinkLines
void CreateArrowLinkLines(vector from, vector to, vector faceDir, float size, int numArrows, int color, ShapeFlags flags)
Definition: DebugShapes.c:202
GetOrigin
vector GetOrigin()
Definition: SCR_AIUtilityComponent.c:279
IsProxy
protected bool IsProxy()
Definition: SCR_CampaignBuildingCompositionComponent.c:456
DAMAGED
@ DAMAGED
Definition: SCR_DestructibleBuildingEntity.c:37
Attribute
typedef Attribute
Post-process effect of scripted camera.
SCR_BuildingRegion
Definition: SCR_BuildingRegion.c:2
GetUndamaged
bool GetUndamaged()
Definition: SCR_DestructionBaseComponent.c:132
CreateCircle
Shape CreateCircle(vector pos, vector aroundDir, float radius, int color, int subdivisions, ShapeFlags flags)
Definition: DebugShapes.c:83
CreateSimpleText
void CreateSimpleText(string text, vector mat[4], float size, int color, ShapeFlags flags, array< ref Shape > output=null, float scaleWidth=1, bool doBackground=false, int backgroundColor=0x80000000)
Definition: DebugShapes.c:236
destructible
SCR_DestructionDamageManagerComponent destructible
Definition: SCR_DestructionSynchronizationComponent.c:22
m_World
protected BaseWorld m_World
Definition: SCR_PreviewEntityEditorUIComponent.c:46
m_SoundComponent
protected SoundComponent m_SoundComponent
Definition: SCR_RotorDamageManagerComponent.c:9
EOnInit
override void EOnInit(IEntity owner)
Definition: SCR_AIConfigComponent.c:79
m_RplComponent
protected RplComponent m_RplComponent
Definition: SCR_CampaignBuildingManagerComponent.c:42
GetDestroyed
bool GetDestroyed()
Definition: SCR_DestructionBaseComponent.c:142
SCR_BitMaskArray
Definition: BitMaskArray.c:6
SCR_Global
Definition: Functions.c:6
SCR_DebrisBuildingEntity
Definition: DebrisBuildingEntity.c:7
UpdateDebug
protected void UpdateDebug()
Definition: SCR_AISettingsComponent.c:79
type
EDamageType type
Definition: SCR_DestructibleTreeV2.c:32
EDamageType
EDamageType
Definition: EDamageType.c:12
SCR_BuildingRegionEntity
Definition: SCR_BuildingRegionEntity.c:7
GetChildren
void GetChildren(out array< SCR_ScenarioFrameworkLayerBase > children)
Definition: SCR_ScenarioFrameworkLayerBase.c:359
BuildingClass
Definition: BuildingClass.c:12
Building
Definition: Building.c:12
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180
SCR_BuildingSetup
Definition: SCR_BuildingSetup.c:4