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