Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
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 {
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 const int num = 10;
316 const 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};
string path
override void Init()
ArmaReforgerScripted GetGame()
Definition game.c:1398
SCR_AIAnimation_Loitering BaseContainerProps
Commanding menu commanding element class.
IEntity SpawnEntity(ResourceName entityResourceName, notnull IEntity slotOwner)
void ParticleEffectEntity(IEntitySource src, IEntity parent)
void Cleanup()
Cleanup component.
proto external vector GetOrigin()
proto external void GetBounds(out vector mins, out vector maxs)
proto external void GetWorldTransform(out vector mat[])
See IEntity::GetTransform.
proto external BaseWorld GetWorld()
proto external vector CoordToParent(vector coord)
Definition Math.c:13
Object holding reference to resource. In destructor release the resource.
Definition Resource.c:25
static void SetHierarchyTransform(notnull IEntity entity, vector newTransform[4])
Visual object.
Definition VObject.c:14
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
SCR_FieldOfViewSettings Attribute
proto native vector Vector(float x, float y, float z)