4 ref array<ref SCR_TimedEffect> m_aEffects;
6 [
Attribute(
"0",
"Delay in seconds between damage and the beginning of the building transition")]
10 float m_fSinkingSpeed;
12 [
Attribute(
"150",
"This speeds up the sinking gradually % per second.",
params:
"0 10000 1")]
13 float m_fSinkingSpeedGradualMultiplier;
16 float m_fRotationSpeed;
18 [
Attribute(
"0.8",
"Time between rotation changes when building is collapsing in seconds")]
19 float m_fRotationTime;
21 [
Attribute(
"50",
"Rotation time randomizer in % - can both shorten/prolong the time",
params:
"0 10000 1")]
22 float m_fRotationTimeRandom;
24 [
Attribute(
"1",
"Max rotations count while sinking")]
27 [
Attribute(vector.Zero.ToString(),
"This vector defines offset for the final position after destruction.")]
30 [
Attribute(
"", UIWidgets.Auto,
desc:
"Slow down event audio source configuration")]
31 ref SCR_AudioSourceConfiguration m_AudioSourceConfiguration;
33 [
Attribute(uiwidget: UIWidgets.GraphDialog)]
34 ref Curve m_CameraShakeCurve;
36 [
Attribute(uiwidget: UIWidgets.Flags, enums: ParamEnumArray.FromEnum(SCR_EDestructionRotationEnum))]
37 SCR_EDestructionRotationEnum m_eAllowedRotations;
40 enum SCR_EDestructionRotationEnum
50 protected const float MAX_MULTIPLIER = 1.5;
51 protected float m_fMaxDistance = 50;
54 protected ref Curve m_CameraShakeCurve;
55 protected vector m_vStartOrigin;
58 override void Update(IEntity owner,
float timeSlice)
63 super.Update(owner, timeSlice);
65 CameraBase camera =
GetGame().GetCameraManager().CurrentCamera();
69 float distanceSq = vector.DistanceSqXZ(m_vStartOrigin, camera.GetOrigin());
70 float multiplier = 1 - Math.Clamp(distanceSq / (m_fMaxDistance * m_fMaxDistance *
m_fSizeMultiplier), 0, 1);
71 float curveMultiplier = Math3D.Curve(ECurveType.CatmullRom, 1 - multiplier, m_CameraShakeCurve)[1];
73 m_vTranslation *= Math.Min(multiplier *
m_fSizeMultiplier * curveMultiplier, MAX_MULTIPLIER);
74 m_vRotation *= Math.Min(multiplier *
m_fSizeMultiplier * curveMultiplier, MAX_MULTIPLIER);
79 void SetStartOrigin(vector startOrigin)
81 m_vStartOrigin = startOrigin
86 void SetCurve(Curve curve)
88 m_CameraShakeCurve = curve;
93 void SetSizeMultiplier(
float sizeMultiplier)
100 class SCR_TimedDebris : SCR_TimedEffect
102 [
Attribute(
"0 0 0", UIWidgets.Coords,
desc:
"Positional offset (in local space to the destructible)")]
103 protected vector m_vOffsetPosition;
105 [
Attribute(
"0 0 0", UIWidgets.Coords,
desc:
"Yaw, pitch & roll offset (in local space to the destructible)")]
106 protected vector m_vOffsetRotation;
108 [
Attribute(ResourceName.Empty, UIWidgets.ResourcePickerThumbnail,
"Debris model prefabs to spawn (spawns ALL of them)",
"et xob")]
111 [
Attribute(
"10", UIWidgets.Slider,
"Mass of the debris",
"0.01 1000 0.01")]
114 [
Attribute(
"5", UIWidgets.Slider,
"Minimum lifetime value for the debris (in s)",
"0 3600 0.5")]
117 [
Attribute(
"10", UIWidgets.Slider,
"Maximum lifetime value for the debris (in s)",
"0 3600 0.5")]
120 [
Attribute(
"200", UIWidgets.Slider,
"Maximum distance from camera above which the debris is not spawned (in m)",
"0 3600 0.5")]
123 [
Attribute(
"0", UIWidgets.Slider,
"Higher priority overrides lower priority if at or over debris limit",
"0 100 1")]
126 [
Attribute(
"0.1", UIWidgets.Slider,
"Damage received to physics impulse (speed / mass) multiplier",
"0 10000 0.01")]
129 [
Attribute(
"2", UIWidgets.Slider,
"Damage to speed multiplier, used when objects get too much damage to impulse",
"0 10000 0.01")]
132 [
Attribute(
"0.5", UIWidgets.Slider,
"Random linear velocity multiplier (m/s)",
"0 200 0.1")]
135 [
Attribute(
"180", UIWidgets.Slider,
"Random angular velocity multiplier (deg/s)",
"0 3600 0.1")]
146 void GetSpawnTransform(IEntity owner, out vector outMat[4],
bool localCoords =
false)
150 Math3D.AnglesToMatrix(m_vOffsetRotation, outMat);
152 if (m_vOffsetPosition == vector.Zero)
153 outMat[3] = vector.Up * 0.001;
155 outMat[3] = m_vOffsetPosition;
159 vector localMat[4], parentMat[4];
160 owner.GetWorldTransform(parentMat);
161 Math3D.AnglesToMatrix(m_vOffsetRotation, localMat);
162 localMat[3] = m_vOffsetPosition;
164 Math3D.MatrixMultiply4(parentMat, localMat, outMat);
173 override void ExecuteEffect(IEntity owner,
SCR_HitInfo hitInfo, inout notnull SCR_BuildingDestructionData
data)
175 int numModelPrefabs = 0;
179 SCR_DestructionDamageManagerComponent destructionComponent;
180 for (
int i = 0; i < numModelPrefabs; i++)
184 ResourceName modelPath;
186 SCR_Global.GetModelAndRemapFromResource(prefabPath, modelPath, remap);
188 if (modelPath == ResourceName.Empty)
192 GetSpawnTransform(owner, spawnMat);
194 destructionComponent = SCR_DestructionDamageManagerComponent.Cast(owner.FindComponent(SCR_DestructionDamageManagerComponent));
198 vector linearVelocity = hitInfo.m_HitDirection * Math.RandomFloat(0, 1);
199 linearVelocity += Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) *
m_fRandomVelocityLinear;
200 linearVelocity *= dmgSpeed;
201 vector angularVelocity = Vector(Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1), Math.RandomFloat(-1, 1)) * Math.RandomFloat(0.25, 4) *
m_fRandomVelocityAngular;
202 angularVelocity *= dmgSpeed;
204 SCR_DebrisSmallEntity.SpawnDebris(owner.GetWorld(), spawnMat, modelPath,
m_fMass, Math.RandomFloat(
m_fLifetimeMin,
m_fLifetimeMax),
m_fDistanceMax,
m_fPriority, linearVelocity, angularVelocity, remap,
false,
m_eMaterialSoundType);
210 class SCR_TimedEffect : Managed
212 [
Attribute(
"0", UIWidgets.Slider,
"Set time in % of sinking the building. 0 = Immediately, can happen before the sinking starts if delay is used",
"0 1 0.01")]
216 bool m_bSnapToTerrain;
219 bool m_bAttachToParent;
221 [
Attribute(
"0",
desc:
"Does this effect remain after destruction? F. E. ruins.")]
226 void SnapToTerrain(inout vector origin, IEntity owner)
228 if (!m_bSnapToTerrain)
237 void ExecuteEffect(IEntity owner,
SCR_HitInfo hitInfo, inout notnull SCR_BuildingDestructionData
data)
243 class SCR_TimedSound : SCR_TimedEffect
245 [
Attribute(
"", UIWidgets.Auto,
desc:
"Audio Source Configuration")]
250 override void ExecuteEffect(IEntity owner,
SCR_HitInfo hitInfo, inout notnull SCR_BuildingDestructionData
data)
252 super.ExecuteEffect(owner, hitInfo,
data);
258 SCR_DestructibleBuildingComponent destructibleComponent = SCR_DestructibleBuildingComponent.Cast(owner.FindComponent(SCR_DestructibleBuildingComponent));
259 if (!destructibleComponent)
266 destructibleComponent.SetAudioSource(audioSource);
267 soundManagerEntity.PlayAudioSource(audioSource,
data.m_vStartMatrix);
272 class SCR_TimedPrefab : SCR_TimedEffect
274 [
Attribute(
"",
"Defines what remains after the building is destroyed.",
params:
"et")]
275 protected ResourceName m_sRuinsPrefab;
279 override void ExecuteEffect(IEntity owner,
SCR_HitInfo hitInfo, inout notnull SCR_BuildingDestructionData
data)
281 super.ExecuteEffect(owner, hitInfo,
data);
283 Resource resource = Resource.Load(m_sRuinsPrefab);
284 if (!resource || !resource.IsValid())
288 mat =
data.m_vStartMatrix;
290 if (m_bSnapToTerrain)
292 vector origin = mat[3];
293 SnapToTerrain(origin, owner);
297 EntitySpawnParams
params =
new EntitySpawnParams();
299 params.TransformMode = ETransformMode.WORLD;
301 if (m_bAttachToParent)
304 IEntity spawnedEntity =
GetGame().SpawnEntityPrefab(resource, owner.GetWorld(),
params);
307 Debug.Error(
"Could not spawn prefab in SCR_TimedPrefab.ExecuteEffect()");
311 data.m_aExcludeList.Insert(spawnedEntity);
316 class SCR_TimedParticle : SCR_TimedEffect
319 protected ref SCR_ParticleSpawnable
m_Particle;
322 protected float m_fParticlesMultiplier;
326 override void ExecuteEffect(IEntity owner,
SCR_HitInfo hitInfo, inout notnull SCR_BuildingDestructionData
data)
328 super.ExecuteEffect(owner, hitInfo,
data);
330 ParticleEffectEntity emitter;
331 if (m_bAttachToParent)
332 emitter =
m_Particle.SpawnAsChild(owner, hitInfo, m_bSnapToTerrain);
334 emitter = ParticleEffectEntity.Cast(
m_Particle.Spawn(owner, owner.GetPhysics(), hitInfo, m_bSnapToTerrain));
338 Debug.Error(
"No emitter was spawned in SCR_TimedParticle.ExecuteEffect()");
342 SetParticleParams(emitter,
data);
344 data.m_aExcludeList.Insert(emitter);
350 void SetParticleParams(ParticleEffectEntity emitter, inout notnull SCR_BuildingDestructionData
data)
352 Particles particles = emitter.GetParticles();
356 particles.MultParam(-1, EmitterParam.BIRTH_RATE, Math.Clamp(
data.m_fSizeMultiplier, 0.5, 2) * m_fParticlesMultiplier);
357 particles.MultParam(-1, EmitterParam.BIRTH_RATE_RND, Math.Clamp(
data.m_fSizeMultiplier, 0.5, 2) * m_fParticlesMultiplier);
358 particles.MultParam(-1, EmitterParam.SIZE, Math.Clamp(
data.m_fSizeMultiplier, 0.5, 1));
359 particles.MultParam(-1, EmitterParam.VELOCITY, Math.Clamp(
data.m_fSizeMultiplier, 0.5, 2) * m_fParticlesMultiplier);
360 particles.MultParam(-1, EmitterParam.VELOCITY_RND, Math.Clamp(
data.m_fSizeMultiplier, 0.5, 2) * m_fParticlesMultiplier);
364 class SCR_DestructibleBuildingComponent : SCR_DamageManagerComponent
367 protected static const int NO_COLLISION_RESPONSE_INDEX = 11;
368 protected static const int MAX_CHECKS_PER_FRAME = 20;
369 protected static const float BUILDING_SIZE = 5000;
370 protected static const vector TRACE_DIRECTIONS[3] = { vector.Right, vector.Up, vector.Forward };
372 private int m_iDataIndex = -1;
374 protected bool m_bDestroyed =
false;
378 protected SCR_BuildingDestructionData
GetData()
383 Print(
"SCR_BuildingDestructionManagerComponent not found! Building destruction won't work.", LogLevel.ERROR);
387 return manager.GetData(m_iDataIndex);
392 protected void FreeData()
397 Print(
"SCR_BuildingDestructionManagerComponent not found! Building destruction won't work.", LogLevel.ERROR);
401 manager.FreeData(m_iDataIndex);
407 protected float GetSpeedGradualMultiplier()
413 protected float GetRotationTimeRandomizer()
419 protected float GetRotationSpeed()
425 protected float GetRotationTime()
431 protected int GetMaxRotations()
438 protected float GetSpeed()
444 protected vector GetSinkVector()
451 protected float GetDelay()
457 protected bool GetAllowRotationX()
463 protected bool GetAllowRotationY()
469 protected bool GetAllowRotationZ()
475 protected Curve GetCameraShakeCurve()
482 protected array<ref SCR_TimedEffect> GetEffects()
488 protected SCR_AudioSourceConfiguration GetSlowDownAudioSourceConfiguration()
501 if (
data.m_AudioSource)
505 if (soundManagerEntity)
506 soundManagerEntity.TerminateAudioSource(
data.m_AudioSource);
509 data.m_AudioSource = audioSource;
523 return data.m_AudioSource;
527 protected void SetSeed(
int seed)
533 data.m_RandomGenerator.SetSeed(seed);
541 super.OnDamageStateChanged(state);
554 int seed = Math.RandomInt(
int.MIN,
int.MAX);
556 RPC_GoToDestroyedState(seed);
557 Rpc(RPC_GoToDestroyedState, seed);
564 [
RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
565 protected void RPC_GoToDestroyedState(
int seed)
568 DestroyInteriorInit(
false);
569 CalculateAndStoreVolume();
571 GetGame().GetCallqueue().CallLater(GoToDestroyedState, 1000 * GetDelay(), param1:
false);
577 protected void DestroyInteriorInit(
bool immediate)
585 BaseWorld world = owner.GetWorld();
588 owner.GetWorldBounds(mins, maxs);
589 owner.GetTransform(
data.m_vStartMatrix);
591 data.m_aQueriedEntities = {};
594 world.QueryEntitiesByAABB(mins, maxs, AddEntityCallback);
600 protected void DestroyInterior(
bool immediate)
606 int count =
data.m_aQueriedEntities.Count();
609 SCR_DestructionDamageManagerComponent destructionComponent;
610 vector hitPosDirNorm[3];
611 RplComponent rplComponent;
613 array<IEntity> handledEntities = {};
619 if (!
data.m_aQueriedEntities[i])
621 data.m_aQueriedEntities.Remove(i);
628 childEntity =
data.m_aQueriedEntities[i].GetChildren();
632 if (!
data.m_aQueriedEntities.Contains(childEntity) && !handledEntities.Contains(childEntity))
634 data.m_aQueriedEntities.Insert(childEntity);
639 if (!handledEntities.Contains(childEntity))
649 handledEntities.Insert(
data.m_aQueriedEntities[i]);
652 data.m_iChecksThisFrame++;
653 if (
data.m_iChecksThisFrame >= MAX_CHECKS_PER_FRAME)
655 data.m_iChecksThisFrame = 0;
657 GetGame().GetCallqueue().CallLater(DestroyInterior, param1: immediate);
673 destructionComponent = SCR_DestructionDamageManagerComponent.Cast(
data.m_aQueriedEntities[i].FindComponent(SCR_DestructionDamageManagerComponent));
676 if (!destructibleEntity && !destructionComponent)
678 rplComponent = RplComponent.Cast(
data.m_aQueriedEntities[i].FindComponent(RplComponent));
681 delete data.m_aQueriedEntities[i];
689 if (destructibleEntity)
690 destructibleEntity.HandleDamage(
EDamageType.TRUE, destructibleEntity.GetCurrentHealth() * 11, hitPosDirNorm);
693 if (destructionComponent)
694 destructionComponent.DeleteDestructible();
696 data.m_aQueriedEntities.Remove(i);
706 protected void FinishDestruction()
713 data.m_CameraShake.SetParams(0.15, 0.15, 0.01, 0.3, 0.24);
714 data.m_CameraShake =
null;
715 data.m_aQueriedEntities =
null;
720 protected bool PerformTrace(notnull TraceParam param, vector start, vector
direction, notnull BaseWorld world,
float lengthMultiplier = 1)
722 param.Start = start -
direction * lengthMultiplier;
723 param.End = start +
direction * lengthMultiplier;
726 return param.TraceEnt !=
null;
732 protected bool IsInside(notnull IEntity entity)
735 BaseWorld world = owner.GetWorld();
736 vector start = entity.GetOrigin();
738 TraceParam param =
new TraceParam();
739 param.Flags = TraceFlags.ENTS;
740 param.LayerMask = EPhysicsLayerDefs.Projectile;
741 param.Include = owner;
744 for (
int i = 0; i < 3; i++)
746 float lengthMultiplier = 1;
748 lengthMultiplier = 100;
750 result = PerformTrace(param, start, TRACE_DIRECTIONS[i], world, lengthMultiplier);
764 protected bool TraceFilter(notnull IEntity e, vector start =
"0 0 0", vector dir =
"0 0 0")
772 protected bool AddEntityCallback(IEntity e)
778 if (e.FindComponent(SCR_DestructibleBuildingComponent))
782 IEntity entityParent = e.GetParent();
785 if (e == owner || (entityParent && entityParent != owner))
794 vector hitPosDirNorm[3];
797 if (ChimeraCharacter.Cast(e) || Vehicle.Cast(e))
807 damageManager.HandleDamage(damageContext);
815 if (ChimeraCharacter.Cast(mainParent) || Vehicle.Cast(mainParent))
819 owner.AddChild(e, -1, EAddChildFlags.AUTO_TRANSFORM | EAddChildFlags.RECALC_LOCAL_TRANSFORM);
821 data.m_aQueriedEntities.Insert(e);
827 void GoToDestroyedStateLoad()
830 GoToDestroyedState(
true);
835 void CalculateAndStoreVolume()
844 float x = Math.AbsFloat(mins[0]) + maxs[0];
845 float y = Math.AbsFloat(mins[1]) + maxs[1];
846 float z = Math.AbsFloat(mins[2]) + maxs[2];
848 data.m_fBuildingVolume = x * y * z;
849 data.m_fSizeMultiplier =
data.m_fBuildingVolume / BUILDING_SIZE;
857 protected void GoToDestroyedState(
bool immediate)
864 GetGame().GetBuildingDestructionManager().RegisterDestroyedBuilding(
this);
869 owner.GetBounds(mins, maxs);
874 vector sinkVector = GetSinkVector();
875 if (sinkVector == vector.Zero)
878 data.m_vTargetOrigin = owner.GetOrigin() + sinkVector;
879 data.m_vStartAngles = owner.GetAngles();
881 StaticModelEntity.Cast(owner).DestroyOccluders();
886 DestroyInteriorInit(immediate);
887 FinishLerp(owner, immediate);
891 owner.GetPhysics().SetResponseIndex(NO_COLLISION_RESPONSE_INDEX);
892 data.m_CameraShake.SetParams(0.15, 0.15, 0.01, 400, 0.24);
893 data.m_CameraShake.SetCurve(GetCameraShakeCurve());
894 data.m_CameraShake.SetStartOrigin(
data.m_vStartMatrix[3]);
895 data.m_CameraShake.SetSizeMultiplier(
data.m_fSizeMultiplier);
896 SCR_CameraShakeManagerComponent.AddCameraShake(
data.m_CameraShake);
897 SetEventMask(owner, EntityEvent.FRAME);
907 protected void SpawnEffects(
float percentDone, IEntity owner,
bool immediateDestruction)
913 if (!
data.m_aExcludeList)
914 data.m_aExcludeList = {};
919 array<ref SCR_TimedEffect> effects = GetEffects();
920 SCR_TimedEffect currentEffect;
921 for (
int i = effects.Count() - 1; i >= 0; i--)
923 if (
data.m_aExecutedEffectIndices &&
data.m_aExecutedEffectIndices.Contains(i))
926 currentEffect = effects[i];
928 if (immediateDestruction && !currentEffect.m_bPersistent)
931 if (currentEffect.m_fSpawnTime <= percentDone)
933 currentEffect.ExecuteEffect(owner, hitInfo,
data);
936 if (!
data.m_aExecutedEffectIndices)
938 data.m_aExecutedEffectIndices =
new set<int>();
940 data.m_aExecutedEffectIndices.Reserve(effects.Count());
943 data.m_aExecutedEffectIndices.Insert(i);
955 protected void FinishLerp(IEntity owner,
bool immediate)
957 owner.SetObject(
null,
"");
958 ClearEventMask(owner, EntityEvent.FRAME);
960 SpawnEffects(1, owner, immediate);
966 owner.SetOrigin(
data.m_vTargetOrigin);
969 DestroyInterior(immediate);
974 protected void RegenerateNavmesh()
984 aiWorld.RequestNavmeshRebuildAreas(
data.m_aNavmeshAreas,
data.m_aRedoRoads);
989 protected void StoreNavmeshData()
991 if (Replication.IsClient())
1002 data.m_aNavmeshAreas = {};
1003 data.m_aRedoRoads = {};
1004 aiWorld.GetNavmeshRebuildAreas(
GetOwner(),
data.m_aNavmeshAreas,
data.m_aRedoRoads);
1008 protected void ClampVector(inout vector currentOrigin, vector startOrigin, vector endOrigin)
1011 for (
int i = 0; i < 3; i++)
1013 targetSmaller = endOrigin[i] < startOrigin[i];
1016 if (currentOrigin[i] < endOrigin[i])
1017 currentOrigin[i] = endOrigin[i];
1021 if (currentOrigin[i] > endOrigin[i])
1022 currentOrigin[i] = endOrigin[i];
1028 protected void LerpRotation(IEntity owner,
float timeSlice)
1035 if (
data.m_iRotationStart +
data.m_iRotationTime < owner.GetWorld().GetWorldTime() &&
data.m_iRotatedTimes < GetMaxRotations())
1038 float rotationTimeRandomizer = GetRotationTimeRandomizer() * 0.01;
1039 data.m_iRotationTime = GetRotationTime() * (1 +
data.m_RandomGenerator.RandFloatXY(0, rotationTimeRandomizer)) * 1000;
1042 data.m_fSpeedMultiplier *= 0.05;
1045 if (
data.m_iRotatedTimes != 0)
1048 bool allowRotationX = GetAllowRotationX();
1049 bool allowRotationY = GetAllowRotationY();
1050 bool allowRotationZ = GetAllowRotationZ();
1053 vector newTargetAngles = {
1054 data.m_RandomGenerator.RandFloatXY(5, 20) * allowRotationX *
data.m_iRotationMultiplier +
data.m_vStartAngles[0],
1055 data.m_RandomGenerator.RandFloatXY(5, 20) * allowRotationY *
data.m_iRotationMultiplier +
data.m_vStartAngles[1],
1056 data.m_RandomGenerator.RandFloatXY(5, 20) * allowRotationZ *
data.m_iRotationMultiplier +
data.m_vStartAngles[2]
1060 data.m_iRotationMultiplier *= -1;
1063 data.m_fRotationSpeedMultiplier = 0.5;
1066 data.m_vTargetAngles = newTargetAngles;
1069 BaseWorld world = owner.GetWorld();
1071 int pauseTime =
data.m_RandomGenerator.RandIntInclusive(0, 500);
1075 data.m_iRotationStart = world.GetWorldTime() + pauseTime;
1078 data.m_iPauseTime = world.GetWorldTime() + pauseTime;
1080 data.m_iRotatedTimes++;
1084 data.m_fRotationSpeedMultiplier += timeSlice;
1086 vector newAngles = LerpAngles(
data.m_vStartAngles, owner.GetAngles(),
data.m_vTargetAngles, GetRotationSpeed(), timeSlice,
data);
1087 owner.SetAngles(newAngles);
1091 protected void PlaySlowDownSound()
1094 if (!soundManagerEntity)
1097 SCR_AudioSourceConfiguration audioSourceConfiguration = GetSlowDownAudioSourceConfiguration();
1098 if (!audioSourceConfiguration || !audioSourceConfiguration.IsValid())
1105 SetAudioSource(audioSource);
1110 protected void OnSlowDown()
1112 PlaySlowDownSound();
1116 protected vector LerpAngles(vector start, vector current, vector target,
float rotationSpeed,
float timeSlice, notnull SCR_BuildingDestructionData
data)
1118 if (target == vector.Zero)
1121 float percent = timeSlice / (
data.m_iRotationTime * 0.001);
1122 vector diff = target - start;
1123 vector nextRotation = current + percent * diff * rotationSpeed *
data.m_fRotationSpeedMultiplier;
1125 ClampVector(nextRotation, start, target);
1126 return nextRotation;
1134 protected void LerpPosition(IEntity owner,
float timeSlice)
1140 vector currentOrigin = owner.GetOrigin();
1141 vector
direction = (
data.m_vTargetOrigin - currentOrigin).Normalized();
1143 data.m_fSpeedMultiplier += (GetSpeedGradualMultiplier() * timeSlice) * 0.01;
1145 owner.GetTransform(mat);
1146 vector newOrigin = currentOrigin +
direction * GetSpeed() * timeSlice *
data.m_fSpeedMultiplier;
1148 ClampVector(newOrigin,
data.m_vStartMatrix[3],
data.m_vTargetOrigin);
1150 float difY =
data.m_vTargetOrigin[1] -
data.m_vStartMatrix[3][1];
1151 float curY = newOrigin[1] -
data.m_vStartMatrix[3][1];
1152 float percentDone = curY/difY;
1153 SpawnEffects(percentDone, owner,
false);
1155 if (
float.AlmostEqual(newOrigin[0],
data.m_vTargetOrigin[0]) &&
float.AlmostEqual(newOrigin[1],
data.m_vTargetOrigin[1]) &&
float.AlmostEqual(newOrigin[2],
data.m_vTargetOrigin[2]))
1156 FinishLerp(owner,
false);
1158 owner.SetOrigin(newOrigin);
1165 protected override event bool OnRplSave(ScriptBitWriter writer)
1167 super.OnRplSave(writer);
1169 writer.WriteBool(m_bDestroyed);
1177 protected override event bool OnRplLoad(ScriptBitReader reader)
1179 super.OnRplLoad(reader);
1181 reader.ReadBool(m_bDestroyed);
1186 GetGame().GetCallqueue().Remove(GoToDestroyedState);
1187 GoToDestroyedState(
true);
1198 override bool OnContact(IEntity owner, IEntity other, Contact contact)
1210 Physics physics = contact.Physics1;
1211 int responseIndex = physics.GetResponseIndex();
1212 float ownerMass = physics.GetMass();
1214 if (!physics.IsDynamic())
1216 physics = contact.Physics2;
1220 otherMass = physics.GetMass();
1224 Physics otherPhysics = other.GetPhysics();
1228 otherMass = otherPhysics.GetMass();
1234 vector relVel = contact.VelocityBefore2 - contact.VelocityBefore1;
1235 outMat[0] = contact.Position;
1236 outMat[1] = relVel.Normalized();
1237 outMat[2] = contact.Normal;
1239 float damage = momentum * 0.05;
1243 HandleDamage(damageContext);
1252 protected override void OnFrame(IEntity owner,
float timeSlice)
1254 LerpPosition(owner, timeSlice);
1257 if (!
data ||
data.m_iRotatedTimes <= GetMaxRotations())
1258 LerpRotation(owner, timeSlice);
1264 super.OnPostInit(owner);
1265 SetEventMask(owner, EntityEvent.CONTACT);
1268 #ifdef BUILDING_DESTRUCTION_SAVING
1270 override event void _WB_OnDelete(IEntity owner, IEntitySource src)
1276 override event void _WB_OnInit(IEntity owner, inout vector mat[4], IEntitySource src)
1278 int id = GetBuildingId();
1283 src.Set(
"m_iId",
id);
1293 return ent.GetBuildingId();
1303 void SCR_DestructibleBuildingComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
1305 #ifdef BUILDING_DESTRUCTION_SAVING
1307 Print(
"SCR_DestructibleBuildingComponent not attached to SCR_DestructibleBuildingEntity!", LogLevel.WARNING);
1310 int id = GetBuildingId();
1319 void ~SCR_DestructibleBuildingComponent()
1321 #ifdef BUILDING_DESTRUCTION_SAVING
1330 RplComponent rplComponent = RplComponent.Cast(
GetOwner().FindComponent(RplComponent));
1331 return rplComponent && rplComponent.IsProxy();