8 [
ComponentEditorProps(
category:
"GameScripted/Destruction", description:
"Fractal destruction component. For objects that should shatter/splinter etc")]
11 [
Attribute(ResourceName.Empty, UIWidgets.ResourceNamePicker,
"Particle effect to play when a fragment is destroyed",
"ptc",
category:
"Destruction Fractal")]
12 ResourceName m_ParticleDestroyFragment;
14 [
Attribute(
"", UIWidgets.Object,
"Debris settings to use when a fragment is destroyed and debris is spawned",
category:
"Destruction Fractal")]
17 [
Attribute(
"10", UIWidgets.Slider,
"Health value of each fragment",
"0.01 100000 0.01",
category:
"Destruction Fractal")]
18 float m_fFragmentHealth;
20 [
Attribute(
"1", UIWidgets.Slider,
"Whether to destroy the fragment at the impact point when damage leads to fracturing of the object",
category:
"Destruction Fractal")]
21 bool m_bDestroyFragmentOnFracture;
23 [
Attribute(
"0", UIWidgets.CheckBox,
"If true, the object will be deleted after the last fragment has been destroyed",
category:
"Destruction Fractal")]
24 bool m_bDeleteAfterFinalFragment;
26 [
Attribute(
"1", UIWidgets.Slider,
"Whether structural integrity is enabled (fragments that have no anchor fragments to hold on to fall as well when a nearby fragment is destroyed)",
category:
"Destruction Fractal")]
27 bool m_bEnableStructuralIntegrity;
29 [
Attribute(
"", UIWidgets.Object,
"List of fractal setup variations (chosen using position as seed)",
category:
"Destruction Fractal")]
30 ref array<ref SCR_FractalVariation> m_FractalVariants;
36 #ifdef ENABLE_DESTRUCTION
38 protected static ref array<SCR_FragmentEntity> s_FragmentList = {};
39 protected static ref array<SCR_FragmentEntity> s_FragmentToCheckList = {};
40 protected static ref array<SCR_FragmentEntity> s_FragmentCheckedList = {};
43 [
Attribute(
"0", UIWidgets.CheckBox,
"Check to generate fragment hierarchies for each fractal variant",
category:
"EDITOR: Destruction Fractal")]
44 protected bool GenerateFragmentHierarchies;
46 [
Attribute(
"0", UIWidgets.CheckBox,
"Check to toggle display of visualizers in the World Editor",
category:
"EDITOR: Destruction Fractal")]
47 protected bool ToggleVisualizers;
49 static bool s_WBDisplayVisualizers =
false;
51 static ref array<SCR_PreviewEntity> s_WBFragmentList = {};
54 protected static void ClearVisualizers()
56 s_WBVisualizeEntity =
null;
60 fragVis = s_WBFragmentList[i];
63 s_WBFragmentList.Clear();
67 override bool _WB_OnKeyChanged(IEntity owner, BaseContainer src,
string key, BaseContainerList ownerContainers, IEntity parent)
73 WorldEditorAPI api = genOwner._WB_GetEditorAPI();
74 if (!api || api.UndoOrRedoIsRestoring())
79 case "GenerateFragmentHierarchies":
81 src.ClearVariable(
"GenerateFragmentHierarchies");
83 Print(
"SCR_DestructionFractalComponent: Generating fragment hierarchies...", LogLevel.NORMAL);
85 BaseContainerList srcFractalVariantList = src.GetObjectArray(
"m_FractalVariants");
86 int numVariants = m_FractalVariants.Count();
87 for (
int v = 0; v < numVariants; v++)
89 BaseContainer srcFractalVariant = srcFractalVariantList.Get(v);
91 fractalVariant.m_Hierarchy =
new SCR_FragmentHierarchy;
92 fractalVariant.m_Hierarchy.GenerateHierarchy(fractalVariant);
93 srcFractalVariant.Set(
"m_Hierarchy", fractalVariant.m_Hierarchy);
96 BaseContainerTools.WriteToInstance(
this, src);
97 genOwner._WB_GetEditorAPI().UpdateSelectionGui();
101 case "ToggleVisualizers":
103 src.ClearVariable(
"ToggleVisualizers");
104 BaseContainerTools.WriteToInstance(
this, src);
106 s_WBDisplayVisualizers = !s_WBDisplayVisualizers;
107 if (!s_WBDisplayVisualizers)
110 genOwner._WB_GetEditorAPI().UpdateSelectionGui();
186 BaseContainer srcFractalComp =
null;
187 if (src.GetClassName() ==
"SCR_DestructionFractalComponent")
189 srcFractalComp = src;
193 for (
int c = 0, srcCount = ownerContainers.Count(); c < srcCount; c++)
195 BaseContainer compSrc = ownerContainers.Get(c);
196 if (compSrc.GetClassName() !=
"SCR_DestructionFractalComponent")
199 srcFractalComp = compSrc;
207 BaseContainerList srcFVariantList = srcFractalComp.GetObjectArray(
"m_FractalVariants");
208 int numVariants = m_FractalVariants.Count();
209 bool needResave =
false;
210 for (
int v = 0; v < numVariants; v++)
212 BaseContainer srcFVariant = srcFVariantList.Get(v);
216 BaseContainer srcHier = srcFVariant.GetObject(
"m_Hierarchy");
221 if (fracVariant.m_Hierarchy && fracVariant.m_Hierarchy.ValidateHierarchy(fracVariant, srcHier, v))
227 BaseContainerTools.WriteToInstance(
this, srcFractalComp);
228 genOwner._WB_GetEditorAPI().UpdateSelectionGui();
246 bool isAnchor =
false;
248 Resource resource = Resource.Load(m_UsedFractalData.GetFragmentModel(
index, isAnchor));
249 VObject asset = resource.GetResource().ToVObject();
250 string materials[256];
251 int numMats = asset.GetMaterials(materials);
253 for (
int m = 0; m < numMats; m++)
255 remap +=
"$remap '" + materials[m] +
"' '{639855E4E1F52285}Assets/Editor/PlacingPreview/Preview_Scriptable.emat';";
258 const int intensity = 200;
259 const int intensityOther = 16;
262 fragVis.m_Color = ARGB(255, intensityOther, intensityOther, intensity);
265 fragVis.m_Color = ARGB(255, intensityOther, intensity, intensityOther);
268 fragVis.m_Color = ARGB(255, intensity, intensityOther, intensityOther);
271 fragVis.m_Color = ARGB(255, intensity, intensityOther, intensity);
274 fragVis.m_Color = ARGB(255, intensityOther, intensity, intensity);
277 fragVis.m_Color = ARGB(255, intensity, intensity, intensityOther);
279 fragVis.SetObject(asset, remap);
280 fragVis.SetFlags(EntityFlags.ACTIVE);
288 override void _WB_AfterWorldUpdate(IEntity owner,
float timeSlice)
291 if (!s_WBDisplayVisualizers)
293 if (s_WBVisualizeEntity)
300 if (!gEntity._WB_GetEditorAPI().IsEntitySelectedAsMain(gEntity))
302 if (s_WBVisualizeEntity == gEntity)
308 vector textMat[4], camMat[4];
309 gEntity.GetWorld().GetCurrentCamera(camMat);
310 gEntity.GetWorld().GetCurrentCamera(textMat);
311 vector camDir = camMat[2];
312 vector camPos = camMat[3];
313 vector entPos = gEntity.GetOrigin();
314 vector entCenter =
SCR_Global.GetEntityCenterWorld(gEntity);
315 vector entMins, entMaxs;
316 gEntity.GetWorldBounds(entMins, entMaxs);
317 vector entTop = Vector((entMaxs[0] + entMins[0]) * 0.5, entMaxs[1], (entMaxs[2] + entMins[2]) * 0.5);
318 float distScale = Math.Clamp(vector.Distance(camPos, entCenter) * 0.15, 0.1, 3);
321 if (s_WBVisualizeEntity != gEntity)
324 s_WBVisualizeEntity = gEntity;
326 if (!m_UsedFractalData)
329 if (!m_UsedFractalData)
332 int numFrags = m_UsedFractalData.CountFragments();
333 for (
int i = 0; i < numFrags; i++)
335 s_WBFragmentList.Insert(CreateFragmentVisualizer(i));
340 if (!m_UsedFractalData)
342 textMat[3] = entTop + vector.Up * 0.25;
343 CreateSimpleText(
"NO FRACTAL VARIANT", textMat, 0.17 * distScale, ARGB(255, 255, 0, 0), ShapeFlags.ONCE | ShapeFlags.TRANSP | ShapeFlags.NOZBUFFER,
null, 0.7,
true, ARGB(128, 0, 0, 0));
348 vector highlightDir =
SCR_Global.ProjWorldEditorMouseScreenToWorld(gEntity);
349 int highlighted = -1;
350 int numFrags = m_UsedFractalData.CountFragments();
351 for (
int i = 0; i < numFrags; i++)
354 bool isAnchor = m_UsedFractalData.GetFragmentIndexIsAnchor(i);
355 vector fragCenter =
SCR_Global.GetEntityCenterWorld(fragVis);
356 vector fragToCamDir = (fragCenter - camPos).Normalized();
357 textMat[3] = fragCenter;
359 int textColor = ARGB(255, 255, 255, 255);
360 int bgColor = ARGB(128, 0, 0, 0);
361 float textSize = 0.12;
362 if (highlighted == -1 && vector.Dot(fragToCamDir, highlightDir) > 0.9997)
365 textColor = ARGB(255, 0, 255, 0);
366 bgColor = ARGB(200, 0, 32, 0);
368 fragVis.ClearFlags(EntityFlags.VISIBLE,
false);
370 if (m_UsedFractalData.m_Hierarchy)
375 vector from = fragCenter + vector.Up * distScale * -0.2;
376 int numLinked = link.m_aOtherIndexes.Count();
377 for (
int n = 0; n < numLinked; n++)
379 int otherIndex = link.m_aOtherIndexes[n];
380 if (otherIndex < 0 || otherIndex >= numFrags || otherIndex == i)
384 bool isOtherAnchor = m_UsedFractalData.GetFragmentIndexIsAnchor(otherIndex);
385 vector fragOtherCenter =
SCR_Global.GetEntityCenterWorld(otherFragVis);
387 int arrowsColor = ARGB(255, 255, 0, 0);
388 if (isOtherAnchor || isAnchor)
389 arrowsColor = ARGB(255, 0, 128, 255);
391 int numArrows = Math.Ceil(vector.Distance(fragCenter, fragOtherCenter) * 10 / distScale);
395 Shape.Create(ShapeType.LINE, arrowsColor, ShapeFlags.ONCE | ShapeFlags.TRANSP | ShapeFlags.NOZBUFFER, from, fragOtherCenter);
398 CreateCircle(from, camDir, 0.02 * distScale, ARGB(255, 128, 128, 128), 12, ShapeFlags.ONCE | ShapeFlags.TRANSP | ShapeFlags.NOZBUFFER);
404 fragVis.SetFlags(EntityFlags.VISIBLE,
false);
407 textMat[3] = textMat[3] + camMat[1] * textSize * distScale * -0.5;
408 CreateSimpleText(i.ToString(), textMat, textSize * distScale, textColor, ShapeFlags.ONCE | ShapeFlags.TRANSP | ShapeFlags.NOZBUFFER,
null, 1,
true, bgColor);
411 textMat[3] = textMat[3] - vector.Up * distScale * textSize * 1.6;
412 CreateSimpleText(
"ANCHOR", textMat, textSize * distScale, ARGB(255, 255, 64, 64), ShapeFlags.ONCE | ShapeFlags.TRANSP | ShapeFlags.NOZBUFFER,
null, 1,
true, bgColor);
429 int numFragments = 0;
431 IEntity child =
m_Owner.GetChildren();
435 child = child.GetSibling();
447 int FillCompleteOrderedFragmentList(notnull array<SCR_FragmentEntity> fragmentList)
449 fragmentList.Clear();
450 int maxFragments = m_UsedFractalData.CountFragments();
451 for (
int i = 0; i < maxFragments; i++)
453 fragmentList.Insert(
null);
456 IEntity child =
m_Owner.GetChildren();
460 child = child.GetSibling();
462 fragmentList[fragment.GetIndex()] = fragment;
465 return fragmentList.Count();
472 int FillFragmentList(notnull array<SCR_FragmentEntity> fragmentList)
474 fragmentList.Clear();
476 IEntity child =
m_Owner.GetChildren();
480 child = child.GetSibling();
482 fragmentList.Insert(fragment);
485 return fragmentList.Count();
492 int FillFragmentIndexList(array<int> fragmentIndexList)
494 fragmentIndexList.Clear();
496 IEntity child =
m_Owner.GetChildren();
500 child = child.GetSibling();
502 fragmentIndexList.Insert(fragment.GetIndex());
505 return fragmentIndexList.Count();
512 return m_UsedFractalData;
519 int numVariants = m_FractalVariants.Count();
520 if (numVariants == 0)
528 pos = parent.GetOrigin();
536 int x = Math.Floor(pos[0] * 1000);
537 int z = Math.Floor(pos[2] * 1000);
541 Math.Randomize(seed);
543 int randomVariant = Math.RandomInt(0, numVariants);
552 void DeleteFragments()
557 IEntity child =
m_Owner.GetChildren();
561 child = child.GetSibling();
573 IEntity child =
m_Owner.GetChildren();
577 child = child.GetSibling();
578 if (fragment.GetIndex() ==
index)
591 bool isAnchor =
false;
592 ResourceName assetPath = m_UsedFractalData.GetFragmentModel(
index, isAnchor);
593 if (assetPath == ResourceName.Empty)
597 fragment.Initialize(
this,
index, m_fFragmentHealth, assetPath);
605 protected void CreateFragments(
bool addToTraceIgnoreList =
false)
607 if (!m_UsedFractalData)
610 if (addToTraceIgnoreList)
613 int num = m_UsedFractalData.CountFragments();
614 for (
int i = 0; i < num; i++)
617 if (addToTraceIgnoreList && fragment)
618 SCR_Global.g_TraceFilterList.Insert(fragment);
629 protected void UpdateStructuralIntegrity(
SCR_FragmentEntity fromFragment,
EDamageType damageType,
float damage, vector hitPosition, vector hitDirection)
632 int numFragments = FillCompleteOrderedFragmentList(s_FragmentList);
635 s_FragmentList[fromFragment.GetIndex()] =
null;
638 if (!m_UsedFractalData.m_Hierarchy)
642 SCR_FragmentLinkage fromLinkage = m_UsedFractalData.m_Hierarchy.GetFragmentLinkage(fromFragment.GetIndex());
647 s_FragmentToCheckList.Clear();
648 for (
int i = fromLinkage.m_aOtherIndexes.Count() - 1; i >= 0; i--)
651 if (!neighborFragment)
654 s_FragmentToCheckList.Insert(neighborFragment);
658 while (!s_FragmentToCheckList.IsEmpty())
661 s_FragmentToCheckList.RemoveItem(checkFragment);
664 s_FragmentCheckedList.Clear();
665 if (!CheckFragmentAnchored(checkFragment, numFragments))
667 s_FragmentList[checkFragment.GetIndex()] =
null;
669 SCR_FragmentLinkage linkage = m_UsedFractalData.m_Hierarchy.GetFragmentLinkage(checkFragment.GetIndex());
672 int numOther = linkage.m_aOtherIndexes.Count();
673 for (
int i = 0; i < numOther; i++)
675 int otherIndex = linkage.m_aOtherIndexes[i];
676 if (otherIndex < 0 || otherIndex >= numFragments)
680 if (!neighborFragment)
683 if (s_FragmentToCheckList.Find(neighborFragment) == -1)
684 s_FragmentToCheckList.Insert(neighborFragment);
688 checkFragment.QueueDestroy(damageType, damage, hitPosition, hitDirection,
false);
699 if (s_FragmentCheckedList.Find(fragment) >= 0)
702 s_FragmentCheckedList.Insert(fragment);
704 SCR_FragmentLinkage linkage = m_UsedFractalData.m_Hierarchy.GetFragmentLinkage(fragment.GetIndex());
708 if (linkage.m_bIsAnchor)
711 int numOther = linkage.m_aOtherIndexes.Count();
712 for (
int i = 0; i < numOther; i++)
714 int otherIndex = linkage.m_aOtherIndexes[i];
715 if (otherIndex < 0 || otherIndex >= numFragments)
719 if (!neighborFragment)
722 if (CheckFragmentAnchored(neighborFragment, numFragments))
738 if (m_bDeleteAfterFinalFragment)
748 if (m_bEnableStructuralIntegrity)
749 UpdateStructuralIntegrity(fragment, damageType, damage, hitPosition, hitDirection);
765 if (m_bEnableStructuralIntegrity)
766 UpdateStructuralIntegrity(fragment, damageType, damage, hitPosition, hitDirection);
768 fragment.QueueDestroy(damageType, damage, hitPosition, hitDirection);
772 override void OnFrame(IEntity owner,
float timeSlice)
775 if (m_bDeleteAfterFinalFragment && !m_DestructionHitInfo)
780 EnableOnFrame(
false);
784 super.OnFrame(owner, timeSlice);
793 if (!m_UsedFractalData)
796 bool fractured = GetFractured();
802 ResourceName assetPath;
804 assetPath = m_UsedFractalData.m_ModelDestroyed;
806 assetPath = m_UsedFractalData.m_ModelNormal;
809 Physics phys =
m_Owner.GetPhysics();
813 if (assetPath == ResourceName.Empty)
815 m_Owner.SetObject(
null,
string.Empty);
816 m_Owner.ClearFlags(EntityFlags.VISIBLE,
false);
821 Resource resource = Resource.Load(assetPath);
822 if (resource.IsValid())
824 BaseResourceObject baseResource = resource.GetResource();
827 VObject asset = baseResource.ToVObject();
830 m_Owner.SetObject(asset,
string.Empty);
831 m_Owner.SetFlags(EntityFlags.VISIBLE,
false);
834 Physics.CreateStatic(
m_Owner, -1);
837 Print(
"FRACTAL DESTRUCTION::UpdateModel: Could not load visual object '" + assetPath +
"'!!", LogLevel.WARNING);
840 Print(
"FRACTAL DESTRUCTION::UpdateModel: Could not load base resource for model '" + assetPath +
"'!!", LogLevel.WARNING);
843 Print(
"FRACTAL DESTRUCTION::UpdateModel: Could not load model '" + assetPath +
"'!!", LogLevel.WARNING);
856 if (!m_DestructionHitInfo.m_TotalDestruction)
858 CreateFragments(
true);
860 if (m_bDestroyFragmentOnFracture)
863 TraceParam param =
new TraceParam();
865 param.Start = m_DestructionHitInfo.m_HitPosition + m_DestructionHitInfo.m_HitDirection * -0.25;
866 param.End = m_DestructionHitInfo.m_HitPosition + m_DestructionHitInfo.m_HitDirection * 0.25;
867 param.Flags = TraceFlags.WORLD | TraceFlags.ENTS;
868 param.LayerMask = -1;
869 if (
m_Owner.GetWorld().TraceMove(param,
SCR_Global.FilterCallback_IgnoreNotInList) < 1)
871 IEntity child =
m_Owner.GetChildren();
875 child = child.GetSibling();
876 if (fragment && param.TraceEnt == fragment)
879 fragment.QueueDestroy(m_DestructionHitInfo.m_DamageType, m_DestructionHitInfo.m_HitDamage, m_DestructionHitInfo.m_HitPosition, m_DestructionHitInfo.m_HitDirection);
880 UpdateStructuralIntegrity(fragment, m_DestructionHitInfo.m_DamageType, m_DestructionHitInfo.m_HitDamage, m_DestructionHitInfo.m_HitPosition, m_DestructionHitInfo.m_HitDirection);
888 delete m_DestructionHitInfo;
896 int fractalVariantIndex;
897 reader.Read(fractalVariantIndex, 32);
898 if (fractalVariantIndex == -1)
905 m_UsedFractalData = m_FractalVariants[fractalVariantIndex];
909 reader.Read(numBitMasks, 32);
910 if (numBitMasks == 0)
915 for (
int i = 0; i < numBitMasks; i++)
918 reader.Read(bitMask, 32);
919 fragmentsBitMaskArray.SetBitMask(i, bitMask);
923 int numFragmentsMax = m_UsedFractalData.CountFragments();
924 for (
int i = 0; i < numFragmentsMax; i++)
926 if (fragmentsBitMaskArray.GetBit(i))
935 int fractalVariantIndex = -1;
936 if (m_UsedFractalData)
938 fractalVariantIndex = m_FractalVariants.Find(m_UsedFractalData);
939 writer.Write(fractalVariantIndex, 32);
943 writer.Write(-1, 32);
947 array<int> fragmentIndexList = {};
948 int numFragments = FillFragmentIndexList(fragmentIndexList);
950 if (numFragments == 0)
958 int numBitMasks = fragmentsBitMaskArray.GetNumBitMasks();
959 writer.Write(numBitMasks, 32);
962 for (
int i = 0; i < numFragments; i++)
964 fragmentsBitMaskArray.SetBit(fragmentIndexList[i],
true);
968 for (
int i = 0; i < numBitMasks; i++)
970 int bitMask = fragmentsBitMaskArray.GetBitMask(i);
971 writer.Write(bitMask, 32);
979 m_UsedFractalData = GetRandomFractalVariant();
994 #endif // ENABLE_DESTRUCTION
997 class SCR_FractalVariationTitle : BaseContainerCustomTitle
1002 array<ResourceName> fragMdls = {};
1003 array<ResourceName> fragAnchorMdls = {};
1004 source.Get(
"m_aModelFragments", fragMdls);
1005 source.Get(
"m_aModelAnchorFragments", fragAnchorMdls);
1008 num = fragMdls.Count();
1011 num += fragAnchorMdls.Count();
1013 title =
"Variation | FRAGS: " + num.ToString();
1021 [
Attribute(
"", UIWidgets.ResourcePickerThumbnail,
"Model to use when the object is undamaged",
"xob")]
1022 protected ResourceName m_ModelNormal;
1024 [
Attribute(
"", UIWidgets.ResourcePickerThumbnail,
"Model to use when the object is damaged/destroyed",
"xob")]
1025 protected ResourceName m_ModelDestroyed;
1027 [
Attribute(
"", UIWidgets.ResourceAssignArray,
"List of fragment models (excluding anchor fragments)",
"xob")]
1028 protected ref array<ResourceName> m_aModelFragments;
1030 [
Attribute(
"", UIWidgets.ResourceAssignArray,
"List of anchor fragment models (these are fragments that are considered firmly attached and hold other fragments in place, if structural integrity is enabled)",
"xob")]
1031 protected ref array<ResourceName> m_aModelAnchorFragments;
1033 [
Attribute(
"", UIWidgets.ResourceAssignArray,
"List of fragment debris models (excluding anchor fragments), if empty uses m_aModelFragments",
"xob")]
1034 protected ref array<ResourceName> m_aDebrisModelFragments;
1036 [
Attribute(
"", UIWidgets.ResourceAssignArray,
"List of anchor fragment debris models (these are fragments that are considered firmly attached and hold other fragments in place, if structural integrity is enabled), if empty uses m_aModelAnchorFragments",
"xob")]
1037 protected ref array<ResourceName> m_aDebrisModelAnchorFragments;
1039 [
Attribute(
"", UIWidgets.Object,
"Hierarchy between fragments")]
1040 protected ref SCR_FragmentHierarchy m_Hierarchy;
1044 int CountFragments()
1051 bool GetFragmentIndexIsAnchor(
int index)
1055 if (
index >= (numFrags + numAnchorFrags))
1058 return index >= numFrags;
1065 ResourceName GetFragmentModel(
int index, out
bool isAnchor)
1069 return ResourceName.Empty;
1073 if (
index >= (numFrags + numAnchorFrags))
1074 return ResourceName.Empty;
1076 if (
index < numFrags)
1089 ResourceName GetFragmentDebrisModel(
int index, out
bool isAnchor)
1093 return ResourceName.Empty;
1097 if (
index >= (numFrags + numAnchorFrags))
1098 return ResourceName.Empty;
1100 if (
index < numFrags)
1119 class SCR_Spawnable_FragmentDebrisTitle : BaseContainerCustomTitle
1124 title =
"Fragment Debris";
1132 override bool _WB_GetCustomTitle(BaseContainer source, out
string title)
1134 title =
"Fragment Hierarchy";
1139 class SCR_FragmentLinkageTitle : BaseContainerCustomTitle
1145 bool isAnchor =
false;
1146 source.Get(
"m_iIndex",
index);
1147 source.Get(
"m_bIsAnchor", isAnchor);
1149 title =
"INVALID INDEX";
1151 title =
"Anchor | Index: " +
index.ToString();
1153 title =
"------ | Index: " +
index.ToString();
1162 [
Attribute(
"10", UIWidgets.Slider,
"Mass of the debris",
"0.01 1000 0.01")]
1163 protected float m_fMass;
1165 [
Attribute(
"5", UIWidgets.Slider,
"Minimum lifetime value for the debris (in s)",
"0 3600 0.5")]
1166 protected float m_fLifetimeMin;
1168 [
Attribute(
"10", UIWidgets.Slider,
"Maximum lifetime value for the debris (in s)",
"0 3600 0.5")]
1169 protected float m_fLifetimeMax;
1171 [
Attribute(
"200", UIWidgets.Slider,
"Maximum distance from camera above which the debris is not spawned (in m)",
"0 3600 0.5")]
1172 protected float m_fDistanceMax;
1174 [
Attribute(
"0", UIWidgets.Slider,
"Higher priority overrides lower priority if at or over debris limit",
"0 100 1")]
1175 protected int m_fPriority;
1177 [
Attribute(
"0.1", UIWidgets.Slider,
"Damage received to physics impulse (speed / mass) multiplier",
"0 10000 0.01")]
1178 protected float m_fDamageToImpulse;
1180 [
Attribute(
"0.5", UIWidgets.Slider,
"Random linear velocity multiplier (m/s)",
"0 200 0.1")]
1181 protected float m_fRandomVelocityLinear;
1183 [
Attribute(
"180", UIWidgets.Slider,
"Random angular velocity multiplier (deg/s)",
"0 3600 0.1")]
1184 protected float m_fRandomVelocityAngular;
1192 void Spawn(
SCR_FragmentEntity fragment, Physics parentPhysics,
float damage, vector hitDirection)
1194 #ifndef ENABLE_DESTRUCTION
1197 SCR_FractalVariation fractalVariation = fragment.GetDestructibleParent().GetCurrentFractalVariant();
1198 if (!fractalVariation)
1201 int fragmentIndex = fragment.GetIndex();
1204 ResourceName modelPath = fractalVariation.GetFragmentDebrisModel(fragmentIndex, isAnchor);
1205 if (modelPath == ResourceName.Empty)
1209 fragment.GetTransform(spawnMat);
1213 vector linearVelocity = hitDirection * Math.RandomFloat(0, 1);
1214 linearVelocity += Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) *
m_fRandomVelocityLinear;
1215 linearVelocity *= dmgSpeed;
1216 vector angularVelocity = Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * Math.RandomFloat(0.25, 4) *
m_fRandomVelocityAngular;
1217 angularVelocity *= dmgSpeed;
1221 linearVelocity += parentPhysics.GetVelocity();
1222 angularVelocity += parentPhysics.GetAngularVelocity();
1226 #endif // ENABLE_DESTRUCTION
1231 class SCR_FragmentHierarchy
1233 [
Attribute(
desc:
"Hierarchical list of fragments containing which fragments they are connected to")]
1234 protected ref array<ref SCR_FragmentLinkage> m_aLinks;
1236 #ifdef ENABLE_DESTRUCTION
1242 int numLinks = m_aLinks.Count();
1245 if (link.m_iIndex ==
index)
1259 bool ValidateHierarchy(
SCR_FractalVariation fractalVariant, BaseContainer srcHierarchy,
int variantIndex)
1261 if (!fractalVariant)
1267 bool result =
false;
1269 BaseContainerList srcLinks = srcHierarchy.GetObjectArray(
"m_aLinks");
1270 array<int> foundIndexes = {};
1271 int numFrags = fractalVariant.CountFragments();
1272 int numLinks = m_aLinks.Count();
1273 for (
int l = 0; l < numLinks; l++)
1275 BaseContainer srcLink = srcLinks.Get(l);
1276 int srcLinkIndex = -1;
1277 if (!srcLink.Get(
"m_iIndex", srcLinkIndex))
1280 bool srcLinkIsAnchor =
false;
1281 if (!srcLink.Get(
"m_bIsAnchor", srcLinkIsAnchor))
1285 if (foundIndexes.Find(srcLinkIndex) != -1 || srcLinkIndex < -1 || srcLinkIndex >= numFrags)
1287 Print(
"SCR_DestructionFractalComponent: Bad index (" + srcLinkIndex.ToString() +
") detected in linkage object index " + l.ToString() +
" in variant index " + variantIndex.ToString() +
", setting to -1", LogLevel.WARNING);
1289 srcLink.Set(
"m_iIndex", srcLinkIndex);
1290 BaseContainerTools.WriteToInstance(
this, srcLink);
1295 foundIndexes.Insert(srcLinkIndex);
1298 if (srcLinkIsAnchor != fractalVariant.GetFragmentIndexIsAnchor(srcLinkIndex))
1300 Print(
"SCR_DestructionFractalComponent: Updating anchor setting in linkage object index " + l +
" in variant index " + variantIndex, LogLevel.NORMAL);
1301 srcLinkIsAnchor = !srcLinkIsAnchor;
1302 srcLink.Set(
"m_bIsAnchor", srcLinkIsAnchor);
1303 BaseContainerTools.WriteToInstance(
this, srcLink);
1308 array<int> srcOtherLinks;
1309 srcLink.Get(
"m_aOtherIndexes", srcOtherLinks);
1310 bool badOtherIndex =
false;
1311 int numOtherLinks = srcOtherLinks.Count();
1312 for (
int o = 0; o < numOtherLinks; o++)
1314 int srcLinkOtherIndex = srcOtherLinks[o];
1315 if (srcLinkOtherIndex < -1 || srcLinkOtherIndex >= numFrags)
1317 Print(
"SCR_DestructionFractalComponent: Bad other index (" + srcLinkOtherIndex.ToString() +
") detected in linkage object index " + l.ToString() +
" in variant index " + variantIndex.ToString() +
", setting to -1", LogLevel.WARNING);
1318 srcOtherLinks[o] = -1;
1319 badOtherIndex =
true;
1325 srcLink.Set(
"m_aOtherIndexes", srcOtherLinks);
1326 BaseContainerTools.WriteToInstance(
this, srcLink);
1332 BaseContainerTools.WriteToInstance(
this, srcHierarchy);
1347 if (!fractalVariant)
1351 int numFrags = fractalVariant.m_aModelFragments.Count();
1352 int numAnchorFrags = fractalVariant.m_aModelAnchorFragments.Count();
1353 int numTotal = numFrags + numAnchorFrags;
1357 array<vector> fragment_mins = {};
1358 array<vector> fragment_maxs = {};
1359 for (
int f = 0; f < numFrags; f++)
1361 Resource resource = Resource.Load(fractalVariant.m_aModelFragments[f]);
1362 VObject asset = resource.GetResource().ToVObject();
1363 fragmentDummy.SetObject(asset,
"");
1366 fragmentDummy.GetBounds(mins, maxs);
1367 fragment_mins.Insert(mins);
1368 fragment_maxs.Insert(maxs);
1371 for (
int f = 0; f < numAnchorFrags; f++)
1373 Resource resource = Resource.Load(fractalVariant.m_aModelAnchorFragments[f]);
1374 VObject asset = resource.GetResource().ToVObject();
1375 fragmentDummy.SetObject(asset,
"");
1378 fragmentDummy.GetBounds(mins, maxs);
1379 fragment_mins.Insert(mins);
1380 fragment_maxs.Insert(maxs);
1384 for (
int f = 0; f < numTotal; f++)
1388 vector fragMins = fragment_mins[f];
1389 vector fragMaxs = fragment_maxs[f];
1390 for (
int f2 = 0; f2 < numTotal; f2++)
1395 vector fragOtherMins = fragment_mins[f2];
1396 vector fragOtherMaxs = fragment_maxs[f2];
1398 if (IntersectionBoxBox(fragMins, fragMaxs, fragOtherMins, fragOtherMaxs))
1405 fragLinkage.m_bIsAnchor = f >= numFrags;
1406 fragLinkage.m_iIndex = f;
1407 fragLinkage.m_aOtherIndexes = {};
1408 m_aLinks.Insert(fragLinkage);
1411 fragLinkage.m_aOtherIndexes.Insert(f2);
1415 delete fragmentDummy;
1425 bool IntersectionBoxBox(vector mins1, vector maxs1, vector mins2, vector maxs2)
1427 return (mins1[0] > maxs2[0] || mins1[1] > maxs2[1] || mins1[2] > maxs2[2] || maxs1[0] < mins2[0] || maxs1[1] < mins2[1] || maxs1[2] < mins2[2]);
1430 #endif // ENABLE_DESTRUCTION
1436 [
Attribute(
"0", UIWidgets.None,
"Whether the fragment is an anchor")]
1439 [
Attribute(
"-1", UIWidgets.EditBox,
"Index of the fragment")]
1442 [
Attribute(
"", UIWidgets.EditBox,
"List of indexes of the surrounding fragments")]
1443 ref array<int> m_aOtherIndexes;