Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_BuildingSetup.c
Go to the documentation of this file.
1 #define ENABLE_BASE_DESTRUCTION
2 //------------------------------------------------------------------------------------------------
3 [BaseContainerProps(configRoot: true)]
5 {
6  [Attribute("1", UIWidgets.EditBox, "", "1 500 1")]
7  int m_iNumRegions;
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")]
11  bool m_bNoDebrisFX;
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;
22 
23  [Attribute("", UIWidgets.Object, "Default definition settings for all regions")]
24  ref SCR_BuildingRegionSetup m_RegionSetupDefaults;
25 
26  [Attribute("", UIWidgets.Object, "List of region objects defining settings for each region")]
27  ref array<ref SCR_BuildingRegionSetupMulti> m_RegionSetupOverride;
28 
29  [Attribute("", UIWidgets.Object, "List of region interconnections")]
30  ref array<ref SCR_BuildingLinkRegion> m_RegionLinks;
31 
32  ResourceName m_sConfigPath;
33 
34  vector m_vBuildingMins;
35  vector m_vBuildingMaxs;
36 
37  ref array<ref SCR_BuildingRegion> m_Regions = new array<ref SCR_BuildingRegion>;
38 
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;
43 
44  //------------------------------------------------------------------------------------------------
45  void SetConfigPath(ResourceName path)
46  {
47  m_sConfigPath = path;
48  }
49 
50  //------------------------------------------------------------------------------------------------
51  int GetRegionNum()
52  {
53  if (!m_Regions)
54  return 0;
55 
56  return m_Regions.Count();
57  }
58 
59  //------------------------------------------------------------------------------------------------
60  SCR_BuildingRegion GetRegionStruct(int regionNumber)
61  {
62  if (regionNumber >= m_Regions.Count())
63  return null;
64  else
65  return m_Regions.Get(regionNumber);
66  }
67 
68  //------------------------------------------------------------------------------------------------
69  void FillDamagedModels()
70  {
71  Print("SCR_BuildingSetup::FillDamagedModels: Filling damaged model lists...");
72 
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();
79 
80  int numRegions = GetRegionNum();
81  for (int region = 0; region < numRegions; region++)
82  {
83  // Add damaged region model path
84  ResourceName resPath = ResourceName.Empty;
85  Resource resource;
86  #ifdef WORKBENCH
87  if (m_ModelDamagedPartBase != string.Empty)
88  {
89  if (region < 10)
90  resPath = Workbench.GetResourceName(m_ModelDamagedPartBase + "0" + region.ToString() + ".xob");
91  else
92  resPath = Workbench.GetResourceName(m_ModelDamagedPartBase + region.ToString() + ".xob");
93  resource = Resource.Load(resPath);
94  if (!resource.IsValid())
95  resPath = ResourceName.Empty;
96  }
97  #endif
98  m_DamagedRegionModels.Insert(resPath);
99 
101  resList.m_aResources = new array<ResourceName>;
102 
103  // Add damaged region intersection debris model path
104  for (int otherRegion = 0; otherRegion < numRegions; otherRegion++)
105  {
106  resPath = ResourceName.Empty;
107  #ifdef WORKBENCH
108  if (m_ModelRegionIntersectDebrisBase != string.Empty)
109  {
110  if (region != otherRegion)
111  {
112  if (region < 10)
113  {
114  if (otherRegion < 10)
115  resPath = Workbench.GetResourceName(m_ModelRegionIntersectDebrisBase + "0" + region.ToString() + m_ModelRegionIntersectDebrisPrefix + "0" + otherRegion.ToString() + ".xob");
116  else
117  resPath = Workbench.GetResourceName(m_ModelRegionIntersectDebrisBase + "0" + region.ToString() + m_ModelRegionIntersectDebrisPrefix + otherRegion.ToString() + ".xob");
118  }
119  else
120  {
121  if (otherRegion < 10)
122  resPath = Workbench.GetResourceName(m_ModelRegionIntersectDebrisBase + region.ToString() + m_ModelRegionIntersectDebrisPrefix + "0" + otherRegion.ToString() + ".xob");
123  else
124  resPath = Workbench.GetResourceName(m_ModelRegionIntersectDebrisBase + region.ToString() + m_ModelRegionIntersectDebrisPrefix + otherRegion.ToString() + ".xob");
125  }
126  }
127  resource = Resource.Load(resPath);
128  if (!resource.IsValid())
129  resPath = ResourceName.Empty;
130  }
131  #endif
132  resList.m_aResources.Insert(resPath);
133  }
134  m_DamagedRegionIntersectDebrisModels.Insert(resList);
135  }
136  }
137 
138  //------------------------------------------------------------------------------------------------
139  ResourceName GetDamagedRegionModel(int region)
140  {
141  if (m_DamagedRegionModels.IsEmpty())
142  {
143  Print("SCR_BuildingSetup::GetDamagedRegionModel: Models not stored for config '" + m_sConfigPath + "', building will not function correctly in built game!", LogLevel.WARNING);
144  #ifdef WORKBENCH
145  FillDamagedModels();
146  if (m_DamagedRegionModels.IsEmpty())
147  return ResourceName.Empty;
148  #else
149  return ResourceName.Empty;
150  #endif
151  }
152 
153  return m_DamagedRegionModels[region];
154  }
155 
156  //------------------------------------------------------------------------------------------------
157  ResourceName GetRegionIntersectDebrisModel(int region, int otherRegion)
158  {
159  if (m_DamagedRegionIntersectDebrisModels.IsEmpty())
160  {
161  Print("SCR_BuildingSetup::GetRegionIntersectDebrisModel: Models not stored for config '" + m_sConfigPath + "', building will not function correctly in built game!", LogLevel.WARNING);
162  #ifdef WORKBENCH
163  FillDamagedModels();
164  if (m_DamagedRegionIntersectDebrisModels.IsEmpty())
165  return ResourceName.Empty;
166  #else
167  return ResourceName.Empty;
168  #endif
169  }
170 
171  SCR_BuildingResourceList resList = m_DamagedRegionIntersectDebrisModels[region];
172  return resList.m_aResources[otherRegion];
173  }
174 
175  //------------------------------------------------------------------------------------------------
176  private void ConnectStructuralRegions(int parentIndex, int childIndex)
177  {
178  SCR_BuildingRegion regionParent = m_Regions.Get(parentIndex);
179  SCR_BuildingRegion regionChild = m_Regions.Get(childIndex);
180 
181  if (!regionParent || !regionChild)
182  return;
183 
184  regionParent.AddConnectionOut(regionChild);
185  regionChild.AddConnectionIn(regionParent);
186  }
187 
188  //------------------------------------------------------------------------------------------------
189  void Cleanup()
190  {
191  while (m_Regions.Count() > 0)
192  {
193  SCR_BuildingRegion region = m_Regions.Get(0);
194  m_Regions.Remove(0);
195  delete region;
196  }
197  }
198 
199  //------------------------------------------------------------------------------------------------
200  int GetBoundingRegionNumber(vector localPos)
201  {
202  int numRegions = GetRegionNum();
203  for (int i = 0; i < numRegions; i++)
204  {
205  SCR_BuildingRegion regionStruct = GetRegionStruct(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();
210  }
211 
212  return -1;
213  }
214 
215  //------------------------------------------------------------------------------------------------
216  void CalculateRegionCentersAndSize(GenericEntity buildingMdl)
217  {
218  Resource resource = Resource.Load(m_ModelUndamaged);
219  VObject asset;
220 
221  if (resource.IsValid())
222  {
223  asset = resource.GetResource().ToVObject();
224  buildingMdl.SetObject(asset, "");
225  buildingMdl.GetBounds(m_vBuildingMins, m_vBuildingMaxs);
226  }
227 
228  int numRegions = GetRegionNum();
229  for (int i = 0; i < numRegions; i++)
230  {
231 
232  resource = Resource.Load(GetDamagedRegionModel(i));
233  if (resource.GetResource())
234  {
235  asset = resource.GetResource().ToVObject();
236  if (asset)
237  {
238  buildingMdl.SetObject(asset, "");
239 
240  vector mins, maxs;
241  buildingMdl.GetBounds(mins, maxs);
242 
243  // Store region size and pos
244  SCR_BuildingRegion regionStruct = GetRegionStruct(i);
245 
246  regionStruct.SetRegionPos((maxs - mins) * 0.5 + mins);
247  regionStruct.SetRegionSize(maxs - mins);
248 
249  continue;
250  }
251  }
252 
253  Print("BUILDING_SETUP::CalculateRegionCentersAndSize(): Failed to load model path " + GetDamagedRegionModel(i));
254 
255  }
256  }
257 
258  //------------------------------------------------------------------------------------------------
260  void SetNoDebrisFX(bool noDebrisFX)
261  {
262  m_bNoDebrisFX = noDebrisFX;
263  }
264  //------------------------------------------------------------------------------------------------
266  void GetDebrisRegionMatrix(IEntity buildingEnt, int regionNumber, out vector fxMat[4])
267  {
268  SCR_BuildingRegion regionStruct = GetRegionStruct(regionNumber);
269  buildingEnt.GetWorldTransform(fxMat);
270  fxMat[3] = buildingEnt.CoordToParent(regionStruct.GetRegionPos());
271  }
272 
273  //------------------------------------------------------------------------------------------------
274  // Spawns debris objects for each region
275  void SpawnDebrisForRegion(IEntity buildingEnt, int region, vector baseLinVel, vector baseAngVel)
276  {
277  if (m_bNoDebrisFX)
278  return;
279 
280  SCR_BuildingRegion regionStruct = GetRegionStruct(region);
281  if (!regionStruct)
282  return;
283 
284  vector fxMat[4];
285  GetDebrisRegionMatrix(buildingEnt, region, fxMat);
286 
287  ResourceName ptcPath;
288  ResourceName sndPath;
289  ResourceName pfbPath;
290 
291  // Spawn destruction effects, if defined
292  if (!regionStruct.GetDestructFX(ptcPath, sndPath, pfbPath))
293  return;
294 
295  if (ptcPath != "")
296  {
297  ParticleEffectEntitySpawnParams spawnParams();
298  spawnParams.Transform[3] = fxMat[3];
299  spawnParams.UseFrameEvent = true;
300  ParticleEffectEntity.SpawnParticleEffect(ptcPath, spawnParams);
301  }
302 
303  // TODO: Implement playing sound
304 
305  if (pfbPath != "")
306  {
307  Resource resource = Resource.Load(pfbPath);
308  if (resource.IsValid())
309  {
310  IEntity pfbParent = GetGame().SpawnEntityPrefab(resource);
311  SCR_EntityHelper.SetHierarchyTransform(pfbParent, fxMat);
312  }
313  }
314 
315  int num = 10;
316  float radius = 1.5;
317 
318  for (int i = 0; i < num; i++)
319  {
320  vector debrisMat[4];
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];
323 
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;
328 
329  ResourceName debrisPath;
330  float debrisMass;
331  float debrisLifetime;
332  float debrisMaxDist;
333  float debrisSpeed;
334  int debrisPriority;
335 
336  if (Math.RandomFloat01() < 0.4) // Wood bits
337  {
338  if (Math.RandomFloat01() < 0.1) // Fence part
339  {
340  debrisPath = "{1121FA3793FC3796}Assets/Tests/A2OA/Debris/debris_K_03.xob";
341  debrisMass = 5;
342  debrisLifetime = Math.RandomFloat(5, 10);
343  debrisMaxDist = 150;
344  debrisSpeed = Math.RandomFloat(2, 10);
345  debrisPriority = 2;
346  }
347  else if (Math.RandomFloat01() < 0.25) // Pylon part
348  {
349  debrisPath = "{16E60066F57A8D55}Assets/Tests/A2OA/Debris/debris_K_04.xob";
350  debrisMass = 25;
351  debrisLifetime = Math.RandomFloat(8, 12);
352  debrisMaxDist = 200;
353  debrisSpeed = Math.RandomFloat(2, 7);
354  debrisPriority = 2;
355  }
356  else if (Math.RandomFloat01() < 0.4) // Log part
357  {
358  debrisPath = "{61EC68EE01D86225}Assets/Tests/A2OA/Debris/debris_K_05.xob";
359  debrisMass = 5;
360  debrisLifetime = Math.RandomFloat(5, 10);
361  debrisMaxDist = 150;
362  debrisSpeed = Math.RandomFloat(5, 15);
363  debrisPriority = 1;
364  }
365  else if (Math.RandomFloat01() < 0.4) // Small plank
366  {
367  debrisPath = "{F8F2D1771C3F53B5}Assets/Tests/A2OA/Debris/debris_K_06.xob";
368  debrisMass = 5;
369  debrisLifetime = Math.RandomFloat(5, 10);
370  debrisMaxDist = 150;
371  debrisSpeed = Math.RandomFloat(5, 15);
372  debrisPriority = 1;
373  }
374  else // Large plank
375  {
376  debrisPath = "{F77D25D5D1322633}Assets/Tests/A2OA/Debris/debris_K_08.xob";
377  debrisMass = 10;
378  debrisLifetime = Math.RandomFloat(10, 14);
379  debrisMaxDist = 200;
380  debrisSpeed = Math.RandomFloat(3, 8);
381  debrisPriority = 3;
382  }
383  }
384  else // Brick blocks
385  {
386  if (Math.RandomFloat01() < 0.4) // Small block
387  {
388  debrisPath = "{FF352B267AB9E976}Assets/Tests/A2OA/Debris/debris_K_01.xob";
389  debrisMass = 10;
390  debrisLifetime = Math.RandomFloat(5, 10);
391  debrisMaxDist = 100;
392  debrisSpeed = Math.RandomFloat(2, 8);
393  debrisPriority = 1;
394  }
395  else if (Math.RandomFloat01() < 0.5) // Large block 1
396  {
397  debrisPath = "{662B92BF675ED8E6}Assets/Tests/A2OA/Debris/debris_K_02.xob";
398  debrisMass = 50;
399  debrisLifetime = Math.RandomFloat(8, 12);
400  debrisMaxDist = 200;
401  debrisSpeed = Math.RandomFloat(1, 5);
402  debrisPriority = 3;
403  }
404  else // Large block 2
405  {
406  debrisPath = "{8FF8B9FFE89DBCC5}Assets/Tests/A2OA/Debris/debris_K_07.xob";
407  debrisMass = 100;
408  debrisLifetime = Math.RandomFloat(10, 14);
409  debrisMaxDist = 250;
410  debrisSpeed = Math.RandomFloat(1, 5);
411  debrisPriority = 3;
412  }
413  }
414 
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);
420 #endif
421  }
422  }
423 
424  //------------------------------------------------------------------------------------------------
425  void Init()
426  {
427  // Create our regions
428  for (int i = 0; i < m_iNumRegions; i++)
429  {
430  SCR_BuildingRegion regionStruct = new SCR_BuildingRegion;
431  regionStruct.SetRegionIndex(i);
432  m_Regions.Insert(regionStruct);
433 
434  // Set defaults
435  if (m_RegionSetupDefaults)
436  {
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);
440  }
441  }
442 
443  // Set settings for regions
444  int cnt = m_RegionSetupOverride.Count();
445  for (int i = 0; i < cnt; i++)
446  {
447  SCR_BuildingRegionSetupMulti setupMulti = m_RegionSetupOverride.Get(i);
448  int forRegionNum = setupMulti.m_aIndexes.Count();
449  for (int n = 0; n < forRegionNum; n++)
450  {
451  int rIndex = setupMulti.m_aIndexes.Get(n);
452  if (rIndex < 0 || rIndex >= m_iNumRegions)
453  continue;
454 
455  SCR_BuildingRegion regionStruct = m_Regions.Get(rIndex);
456  if (regionStruct)
457  {
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);
461  }
462  }
463  }
464 
465  // Create a temporary entity that uses the damaged model, to get the bone positions etc
467 
468  CalculateRegionCentersAndSize(buildingMdl);
469 
470  // Delete the temporary entity here
471  if (buildingMdl)
472  {
473  delete buildingMdl;
474  buildingMdl = null;
475  }
476 
477  cnt = m_Regions.Count();
478  for (int i = 0; i < cnt; i++)
479  {
480  SCR_BuildingRegion rgn = m_Regions.Get(i);
481  rgn.SetRegionIndex(i);
482  }
483 
484  cnt = m_RegionLinks.Count();
485  for (int i = 0; i < cnt; i++)
486  {
487  SCR_BuildingLinkRegion link = m_RegionLinks.Get(i);
488  int chldCnt = link.m_aChildren.Count();
489  for (int n = 0; n < chldCnt; n++)
490  {
491  ConnectStructuralRegions(link.m_iParent, link.m_aChildren.Get(n));
492  }
493  }
494  }
495 
496  //------------------------------------------------------------------------------------------------
497  void ~SCR_BuildingSetup()
498  {
499  Cleanup();
500  }
501 };
SpawnEntity
protected IEntity SpawnEntity(ResourceName entityResourceName, notnull IEntity slotOwner)
Definition: SCR_CatalogEntitySpawnerComponent.c:1008
SCR_EntityHelper
Definition: SCR_EntityHelper.c:1
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
GenericEntity
SCR_GenericBoxEntityClass GenericEntity
SCR_BuildingRegionSetup
Definition: SCR_BuildingRegionSetup.c:2
SCR_BuildingResourceList
Definition: SCR_BuildingResourceList.c:2
Attribute
typedef Attribute
Post-process effect of scripted camera.
SCR_BuildingRegion
Definition: SCR_BuildingRegion.c:2
SCR_DebrisSmallEntity
Definition: DebrisSmallEntity.c:14
SCR_Global
Definition: Functions.c:6
SCR_BuildingRegionSetupMulti
Definition: SCR_BuildingRegionSetupMulti.c:2
BaseContainerProps
SCR_AIGoalReaction_Follow BaseContainerProps
Handles insects that are supposed to be spawned around selected prefabs defined in prefab names array...
Definition: SCR_AIGoalReaction.c:468
SCR_BuildingSetup
Definition: SCR_BuildingSetup.c:4