1 #define ENABLE_BASE_DESTRUCTION
6 [
Attribute(
"1", UIWidgets.EditBox,
"",
"1 500 1")]
8 [
Attribute(
"100", UIWidgets.Slider,
"Maximum drop of falling debris (in m)",
"1 500 1")]
9 float m_fLargeDebrisDropMax;
10 [
Attribute(
"0", UIWidgets.CheckBox,
"If true, no debris particle effects and pieces will be spawned")]
12 [
Attribute(
"", UIWidgets.ResourcePickerThumbnail,
"Model to use when the building is undamaged")]
13 ResourceName m_ModelUndamaged;
14 [
Attribute(
"", UIWidgets.ResourcePickerThumbnail,
"Model to use when the building is destroyed")]
15 ResourceName m_ModelDestroyed;
16 [
Attribute(
"", UIWidgets.EditBox,
"Model base path to use for the damaged region parts (automatically adds index to the end, eg: m_ModelDamagedPartBase00)")]
17 string m_ModelDamagedPartBase;
18 [
Attribute(
"", UIWidgets.EditBox,
"Model base path to use for the debris in the intersection between two region parts, when visible (m_ModelRegionIntersectDebrisBase + index + m_ModelRegionIntersectDebrisPrefix + otherIndex, eg: models/structure01/house_region00_rubble01)")]
19 string m_ModelRegionIntersectDebrisBase;
20 [
Attribute(
"_rubble", UIWidgets.EditBox,
"Prefix to add to the base path to use for the debris in the intersection between two region parts, when visible (m_ModelRegionIntersectDebrisBase + index + m_ModelRegionIntersectDebrisPrefix + otherIndex, eg: models/structure01/house_region00_rubble01)")]
21 string m_ModelRegionIntersectDebrisPrefix;
23 [
Attribute(
"", UIWidgets.Object,
"Default definition settings for all regions")]
26 [
Attribute(
"", UIWidgets.Object,
"List of region objects defining settings for each region")]
27 ref array<ref SCR_BuildingRegionSetupMulti> m_RegionSetupOverride;
29 [
Attribute(
"", UIWidgets.Object,
"List of region interconnections")]
30 ref array<ref SCR_BuildingLinkRegion> m_RegionLinks;
32 ResourceName m_sConfigPath;
34 vector m_vBuildingMins;
35 vector m_vBuildingMaxs;
37 ref array<ref SCR_BuildingRegion> m_Regions =
new array<ref SCR_BuildingRegion>;
39 [
Attribute(
"", UIWidgets.None,
"GENERATED ATTRIBUTE, HIDDEN FROM EDITOR")]
40 ref array<ResourceName> m_DamagedRegionModels;
41 [
Attribute(
"", UIWidgets.None,
"GENERATED ATTRIBUTE, HIDDEN FROM EDITOR")]
42 ref array<ref SCR_BuildingResourceList> m_DamagedRegionIntersectDebrisModels;
45 void SetConfigPath(ResourceName path)
56 return m_Regions.Count();
62 if (regionNumber >= m_Regions.Count())
65 return m_Regions.Get(regionNumber);
69 void FillDamagedModels()
71 Print(
"SCR_BuildingSetup::FillDamagedModels: Filling damaged model lists...");
73 if (!m_DamagedRegionModels)
74 m_DamagedRegionModels =
new array<ResourceName>;
75 if (!m_DamagedRegionIntersectDebrisModels)
76 m_DamagedRegionIntersectDebrisModels =
new array<ref SCR_BuildingResourceList>;
77 m_DamagedRegionModels.Clear();
78 m_DamagedRegionIntersectDebrisModels.Clear();
80 int numRegions = GetRegionNum();
81 for (
int region = 0; region < numRegions; region++)
84 ResourceName resPath = ResourceName.Empty;
87 if (m_ModelDamagedPartBase !=
string.Empty)
90 resPath = Workbench.GetResourceName(m_ModelDamagedPartBase +
"0" + region.ToString() +
".xob");
92 resPath = Workbench.GetResourceName(m_ModelDamagedPartBase + region.ToString() +
".xob");
93 resource = Resource.Load(resPath);
94 if (!resource.IsValid())
95 resPath = ResourceName.Empty;
98 m_DamagedRegionModels.Insert(resPath);
101 resList.m_aResources =
new array<ResourceName>;
104 for (
int otherRegion = 0; otherRegion < numRegions; otherRegion++)
106 resPath = ResourceName.Empty;
108 if (m_ModelRegionIntersectDebrisBase !=
string.Empty)
110 if (region != otherRegion)
114 if (otherRegion < 10)
115 resPath = Workbench.GetResourceName(m_ModelRegionIntersectDebrisBase +
"0" + region.ToString() + m_ModelRegionIntersectDebrisPrefix +
"0" + otherRegion.ToString() +
".xob");
117 resPath = Workbench.GetResourceName(m_ModelRegionIntersectDebrisBase +
"0" + region.ToString() + m_ModelRegionIntersectDebrisPrefix + otherRegion.ToString() +
".xob");
121 if (otherRegion < 10)
122 resPath = Workbench.GetResourceName(m_ModelRegionIntersectDebrisBase + region.ToString() + m_ModelRegionIntersectDebrisPrefix +
"0" + otherRegion.ToString() +
".xob");
124 resPath = Workbench.GetResourceName(m_ModelRegionIntersectDebrisBase + region.ToString() + m_ModelRegionIntersectDebrisPrefix + otherRegion.ToString() +
".xob");
127 resource = Resource.Load(resPath);
128 if (!resource.IsValid())
129 resPath = ResourceName.Empty;
132 resList.m_aResources.Insert(resPath);
134 m_DamagedRegionIntersectDebrisModels.Insert(resList);
139 ResourceName GetDamagedRegionModel(
int region)
141 if (m_DamagedRegionModels.IsEmpty())
143 Print(
"SCR_BuildingSetup::GetDamagedRegionModel: Models not stored for config '" + m_sConfigPath +
"', building will not function correctly in built game!", LogLevel.WARNING);
146 if (m_DamagedRegionModels.IsEmpty())
147 return ResourceName.Empty;
149 return ResourceName.Empty;
153 return m_DamagedRegionModels[region];
157 ResourceName GetRegionIntersectDebrisModel(
int region,
int otherRegion)
159 if (m_DamagedRegionIntersectDebrisModels.IsEmpty())
161 Print(
"SCR_BuildingSetup::GetRegionIntersectDebrisModel: Models not stored for config '" + m_sConfigPath +
"', building will not function correctly in built game!", LogLevel.WARNING);
164 if (m_DamagedRegionIntersectDebrisModels.IsEmpty())
165 return ResourceName.Empty;
167 return ResourceName.Empty;
172 return resList.m_aResources[otherRegion];
176 private void ConnectStructuralRegions(
int parentIndex,
int childIndex)
181 if (!regionParent || !regionChild)
184 regionParent.AddConnectionOut(regionChild);
185 regionChild.AddConnectionIn(regionParent);
191 while (m_Regions.Count() > 0)
200 int GetBoundingRegionNumber(vector localPos)
202 int numRegions = GetRegionNum();
203 for (
int i = 0; i < numRegions; i++)
206 vector mins = regionStruct.GetRegionPos() + regionStruct.GetRegionSize() * -0.5;
207 vector maxs = regionStruct.GetRegionPos() + regionStruct.GetRegionSize() * 0.5;
208 if (
SCR_Global.IntersectBoxPoint(localPos, mins, maxs))
209 return regionStruct.GetRegionIndex();
216 void CalculateRegionCentersAndSize(
GenericEntity buildingMdl)
218 Resource resource = Resource.Load(m_ModelUndamaged);
221 if (resource.IsValid())
223 asset = resource.GetResource().ToVObject();
224 buildingMdl.SetObject(asset,
"");
225 buildingMdl.GetBounds(m_vBuildingMins, m_vBuildingMaxs);
228 int numRegions = GetRegionNum();
229 for (
int i = 0; i < numRegions; i++)
232 resource = Resource.Load(GetDamagedRegionModel(i));
233 if (resource.GetResource())
235 asset = resource.GetResource().ToVObject();
238 buildingMdl.SetObject(asset,
"");
241 buildingMdl.GetBounds(mins, maxs);
246 regionStruct.SetRegionPos((maxs - mins) * 0.5 + mins);
247 regionStruct.SetRegionSize(maxs - mins);
253 Print(
"BUILDING_SETUP::CalculateRegionCentersAndSize(): Failed to load model path " + GetDamagedRegionModel(i));
260 void SetNoDebrisFX(
bool noDebrisFX)
262 m_bNoDebrisFX = noDebrisFX;
266 void GetDebrisRegionMatrix(IEntity buildingEnt,
int regionNumber, out vector fxMat[4])
269 buildingEnt.GetWorldTransform(fxMat);
270 fxMat[3] = buildingEnt.CoordToParent(regionStruct.GetRegionPos());
275 void SpawnDebrisForRegion(IEntity buildingEnt,
int region, vector baseLinVel, vector baseAngVel)
285 GetDebrisRegionMatrix(buildingEnt, region, fxMat);
287 ResourceName ptcPath;
288 ResourceName sndPath;
289 ResourceName pfbPath;
292 if (!regionStruct.GetDestructFX(ptcPath, sndPath, pfbPath))
297 ParticleEffectEntitySpawnParams spawnParams();
298 spawnParams.Transform[3] = fxMat[3];
299 spawnParams.UseFrameEvent =
true;
300 ParticleEffectEntity.SpawnParticleEffect(ptcPath, spawnParams);
307 Resource resource = Resource.Load(pfbPath);
308 if (resource.IsValid())
310 IEntity pfbParent =
GetGame().SpawnEntityPrefab(resource);
318 for (
int i = 0; i < num; i++)
321 Math3D.AnglesToMatrix(Vector(Math.RandomFloat(-180, 180), Math.RandomFloat(-90, 90), Math.RandomFloat(-180, 180)), debrisMat);
322 debrisMat[3] = debrisMat[0] * Math.RandomFloat(-radius, radius) + debrisMat[1] * Math.RandomFloat(-radius, radius) + debrisMat[2] * Math.RandomFloat(-radius, radius) + fxMat[3];
324 float rndScale = Math.RandomFloat(0.8, 1.5) * 0.5;
325 debrisMat[0] = debrisMat[0] * rndScale;
326 debrisMat[1] = debrisMat[1] * rndScale;
327 debrisMat[2] = debrisMat[2] * rndScale;
329 ResourceName debrisPath;
331 float debrisLifetime;
336 if (Math.RandomFloat01() < 0.4)
338 if (Math.RandomFloat01() < 0.1)
340 debrisPath =
"{1121FA3793FC3796}Assets/Tests/A2OA/Debris/debris_K_03.xob";
342 debrisLifetime = Math.RandomFloat(5, 10);
344 debrisSpeed = Math.RandomFloat(2, 10);
347 else if (Math.RandomFloat01() < 0.25)
349 debrisPath =
"{16E60066F57A8D55}Assets/Tests/A2OA/Debris/debris_K_04.xob";
351 debrisLifetime = Math.RandomFloat(8, 12);
353 debrisSpeed = Math.RandomFloat(2, 7);
356 else if (Math.RandomFloat01() < 0.4)
358 debrisPath =
"{61EC68EE01D86225}Assets/Tests/A2OA/Debris/debris_K_05.xob";
360 debrisLifetime = Math.RandomFloat(5, 10);
362 debrisSpeed = Math.RandomFloat(5, 15);
365 else if (Math.RandomFloat01() < 0.4)
367 debrisPath =
"{F8F2D1771C3F53B5}Assets/Tests/A2OA/Debris/debris_K_06.xob";
369 debrisLifetime = Math.RandomFloat(5, 10);
371 debrisSpeed = Math.RandomFloat(5, 15);
376 debrisPath =
"{F77D25D5D1322633}Assets/Tests/A2OA/Debris/debris_K_08.xob";
378 debrisLifetime = Math.RandomFloat(10, 14);
380 debrisSpeed = Math.RandomFloat(3, 8);
386 if (Math.RandomFloat01() < 0.4)
388 debrisPath =
"{FF352B267AB9E976}Assets/Tests/A2OA/Debris/debris_K_01.xob";
390 debrisLifetime = Math.RandomFloat(5, 10);
392 debrisSpeed = Math.RandomFloat(2, 8);
395 else if (Math.RandomFloat01() < 0.5)
397 debrisPath =
"{662B92BF675ED8E6}Assets/Tests/A2OA/Debris/debris_K_02.xob";
399 debrisLifetime = Math.RandomFloat(8, 12);
401 debrisSpeed = Math.RandomFloat(1, 5);
406 debrisPath =
"{8FF8B9FFE89DBCC5}Assets/Tests/A2OA/Debris/debris_K_07.xob";
408 debrisLifetime = Math.RandomFloat(10, 14);
410 debrisSpeed = Math.RandomFloat(1, 5);
415 vector rndLinVel = debrisMat[3] - buildingEnt.GetOrigin();
416 rndLinVel = rndLinVel.Normalized() * debrisSpeed + baseLinVel;
417 vector rndAngVel = Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * Math.RandomFloat(90, 720) + baseAngVel;
418 #ifdef ENABLE_BASE_DESTRUCTION
419 SCR_DebrisSmallEntity.SpawnDebris(buildingEnt.GetWorld(), debrisMat, debrisPath, debrisMass, debrisLifetime, debrisMaxDist, debrisPriority, rndLinVel, rndAngVel);
428 for (
int i = 0; i < m_iNumRegions; i++)
431 regionStruct.SetRegionIndex(i);
432 m_Regions.Insert(regionStruct);
435 if (m_RegionSetupDefaults)
437 regionStruct.SetMaxHealth(m_RegionSetupDefaults.m_MaxHealth);
438 regionStruct.SetStructuralSupportPercentage(m_RegionSetupDefaults.m_StructuralSupportPct);
439 regionStruct.SetDestructFX(m_RegionSetupDefaults.m_DestructFX_PTC, m_RegionSetupDefaults.m_DestructFX_SND, m_RegionSetupDefaults.m_DestructFX_PFB);
444 int cnt = m_RegionSetupOverride.Count();
445 for (
int i = 0; i < cnt; i++)
448 int forRegionNum = setupMulti.m_aIndexes.Count();
449 for (
int n = 0; n < forRegionNum; n++)
451 int rIndex = setupMulti.m_aIndexes.Get(n);
452 if (rIndex < 0 || rIndex >= m_iNumRegions)
458 regionStruct.SetMaxHealth(setupMulti.m_MaxHealth);
459 regionStruct.SetStructuralSupportPercentage(setupMulti.m_StructuralSupportPct);
460 regionStruct.SetDestructFX(setupMulti.m_DestructFX_PTC, setupMulti.m_DestructFX_SND, setupMulti.m_DestructFX_PFB);
468 CalculateRegionCentersAndSize(buildingMdl);
477 cnt = m_Regions.Count();
478 for (
int i = 0; i < cnt; i++)
481 rgn.SetRegionIndex(i);
484 cnt = m_RegionLinks.Count();
485 for (
int i = 0; i < cnt; i++)
488 int chldCnt = link.m_aChildren.Count();
489 for (
int n = 0; n < chldCnt; n++)
491 ConnectStructuralRegions(link.m_iParent, link.m_aChildren.Get(n));