Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_ImpactEffectComponent.c
Go to the documentation of this file.
6}
7
8enum SCR_EImpactSoundEvent
9{
13 SOUND_VEHICLE_IMPACT_BOTTOM
14}
15
16class SCR_ImpactEffectComponentClass : ScriptComponentClass
17{
18 [Attribute()]
19 ref array<ResourceName> m_aDefaultParticles;
20
21 [Attribute()]
22 ref array<ResourceName> m_aWaterParticles;
23
24 [Attribute(defvalue: "-1", desc: "If set to -1 component will use impulse to determine effect intensity")]
26}
27
29{
33
34 //Shared
35 // Distance (squared) between current impact and last contact, below which impact is ignored
36 protected const float IMPACT_DIST_SQ_THRESHOLD = 2;
37 // Change in velocity (m/s) above which an impact is registered
38 protected const float VELOCITY_IMPACT_THRESHOLD = 0.8;
39
41
44 protected vector m_vNormal;
45
46 // Particles
47 protected const float MIN_TINY_IMPULSE = 2500;
48 protected const float MIN_SMALL_IMPULSE = 5000;
49 protected const float MIN_MEDIUM_IMPULSE = 10000;
50 protected const float MIN_BIG_IMPULSE = 20000;
51 protected const float MIN_HUGE_IMPULSE = 40000;
52 protected int m_iMagnitude = -1;
54
55 // Sound
56 protected const string IMPACT_SURFACE_SIGNAL_NAME = "ImpactSurface";
57 protected const string COLLISION_D_M_SIGNAL_NAME = "CollisionDM";
58 protected const float DEFAULT_DENSITY = 100;
59 protected const float VEHICLE_VELOCITY_MINIMUM = 3;
60 protected const float COLLISION_LAST_POSITION_REST_TIME = 500;
61 protected const float CHARACTER_IMPULSE_MINIMUM = 20;
62 protected const float SMALL_OBJECT_IMPULSE_MINIMUM = 10000;
63 protected const float SMALL_OBJECT_VOLUME_MAXIMUM = 90;
64
65 protected static const ref array<string> WATER_SOUNDS = { SCR_SoundEvent.SOUND_VEHICLE_WATER_SMALL, SCR_SoundEvent.SOUND_VEHICLE_WATER_MEDIUM, SCR_SoundEvent.SOUND_VEHICLE_WATER_BIG, SCR_SoundEvent.SOUND_VEHICLE_WATER_BIG };
66 protected static const int m_aAproximatedMasses[5] = { 250, 400, 1500, 3500, 10000 };
68 protected int m_iSurface;
69 protected float m_fdM;
70 protected float m_fMass = 2000;
71
72
73 //------------------------------------------------------------------------------------------------
74 protected array<ResourceName> GetDefaultParticles()
75 {
76 return SCR_ImpactEffectComponentClass.Cast(GetComponentData(GetOwner())).m_aDefaultParticles;
77 }
78
79 //------------------------------------------------------------------------------------------------
80 protected array<ResourceName> GetWaterParticles()
81 {
82 return SCR_ImpactEffectComponentClass.Cast(GetComponentData(GetOwner())).m_aWaterParticles;
83 }
84
85 //------------------------------------------------------------------------------------------------
86 protected int GetEffectMagnitude()
87 {
88 return SCR_ImpactEffectComponentClass.Cast(GetComponentData(GetOwner())).m_iEffectMagnitude;
89 }
90
91 //------------------------------------------------------------------------------------------------
92 void OnImpact(notnull IEntity other, float impulse, vector impactPosition, vector impactNormal, GameMaterial mat, vector velocityBefore = vector.Zero, vector velocityAfter = vector.Zero)
93 {
94 // Change in velocity due to contact
95 float dV = Math.AbsFloat(vector.Dot(velocityBefore - velocityAfter, impactNormal));
96
97 SCR_EImpactSoundType impactSoundType = SCR_EImpactSoundType.DEFAULT;
98
99 // Some types of entities may have a negligible effect on the vehicle's speed but should play an impact sound anyway - this is handled here
101 {
102 float velocity = velocityBefore.Length();
103
104 if (velocity < VEHICLE_VELOCITY_MINIMUM)
105 return;
106
108 {
109 impactSoundType = SCR_EImpactSoundType.CHARACTER;
110 }
111 // high impulse but negligible change in velocity = small destructible object
113 {
114 impactSoundType = SCR_EImpactSoundType.SMALL_OBJECT;
115
116 float otherMass = GetAproximatedMass(other);
117 float finalMass = m_fMass + otherMass;
118 if (finalMass != 0.0)
119 {
120 float velocityAfterImpact = m_fMass * velocity / finalMass;
121 dV = velocity - velocityAfterImpact;
122 }
123 else
124 {
125 dV = velocity;
126 }
127 }
128 }
129
130 dV *= m_fMass;
131
132 if (dV > m_fdM)
133 {
134 m_fdM = dV;
135 m_eImpactType = impactSoundType;
136
137 m_vPosition = impactPosition;
138 m_vNormal = impactNormal;
139 m_iSurface = mat.GetSoundInfo().GetSignalValue();
140
141 m_GameMaterial = mat;
142
145 }
146 }
147
148 //------------------------------------------------------------------------------------------------
149 protected void OnWaterEnter()
150 {
152 return;
153
154 Physics physics = GetOwner().GetPhysics();
155 if (!physics)
156 return;
157
158 // Only vertical axis is measured since water particles only go up
159 float impulse = Math.AbsFloat(physics.GetVelocity()[1]) * m_fMass;
160
162 return;
163
164 int magnitude = -1;
166 magnitude = 0;
167 else if (impulse < MIN_MEDIUM_IMPULSE)
168 magnitude = 1;
169 else if (impulse < MIN_BIG_IMPULSE)
170 magnitude = 2;
171 else
172 magnitude = 3;
173
174 vector ownerTransform[4];
175 GetOwner().GetTransform(ownerTransform);
176
177 EWaterSurfaceType surfaceType;
178 float lakeArea;
179 float waterHeight = SCR_WorldTools.GetWaterSurfaceY(GetGame().GetWorld(), ownerTransform[3], surfaceType, lakeArea);
180
181 vector transform[4];
182 Math3D.MatrixIdentity3(transform);
183 vector particleOrigin = {ownerTransform[3][0], waterHeight, ownerTransform[3][2]};
184 transform[3] = particleOrigin;
185
187 string soundEvent = WATER_SOUNDS[magnitude];
188
189 if (resourceName.IsEmpty())
191
192 EmitParticles(transform, resourceName);
193 PlaySound(soundEvent);
194
195 if (magnitude > -1)
196 Rpc(RPC_OnWaterEnterBroadcast, transform, magnitude);
197 }
198
199 //------------------------------------------------------------------------------------------------
200 protected void UpdateParticlesMagnitude(notnull IEntity other, float impulse)
201 {
202 int magnitude = GetEffectMagnitude();
203 if (magnitude <= -1)
204 {
205 Physics physics = other.GetPhysics();
206 if (physics == null)
207 return;
208
209 int responseIndex = physics.GetResponseIndex();
210
211 // Exclude collisions with physics objects with tiny response index e.g. bushes, fences etc.
212 if (responseIndex == SCR_EPhysicsResponseIndex.TINY_DESTRUCTIBLE || responseIndex == SCR_EPhysicsResponseIndex.SMALL_DESTRUCTIBLE)
213 return;
214
215 // Exclude collisions with other vehicle parts
216 if (SCR_VehicleDamageManagerComponent.Cast(SCR_DamageManagerComponent.GetDamageManager(other.GetRootParent())))
217 return;
218
220 return;
221
223 magnitude = 0;
224 else if (impulse < MIN_MEDIUM_IMPULSE)
225 magnitude = 1;
226 else
227 magnitude = 2;
228 }
229
230 if (magnitude > m_iMagnitude)
231 m_iMagnitude = magnitude;
232 }
233
234 //------------------------------------------------------------------------------------------------
235 protected void EmitParticles(vector transform[4], ResourceName particleResource)
236 {
237 if (!m_ParticleSpawnParams || particleResource.IsEmpty())
238 return;
239
240 m_ParticleSpawnParams.Transform = transform;
241 ParticleEffectEntity.SpawnParticleEffect(particleResource, m_ParticleSpawnParams);
242 }
243
244 //------------------------------------------------------------------------------------------------
245 protected void PlaySound(string soundEvent)
246 {
247 if (!m_SoundComponent || soundEvent.IsEmpty())
248 return;
249
250 m_SoundComponent.SoundEvent(soundEvent);
251 }
252
253 //------------------------------------------------------------------------------------------------
254 protected void ScheduleImpactEffect()
255 {
257 return;
258
259 // Largest contact was cashed and will be processed only "once per frame"
260 GetGame().GetCallqueue().CallLater(HandleImpactEffect, 0);
262 }
263
264 //------------------------------------------------------------------------------------------------
265 protected void HandleImpactEffect()
266 {
268
269 // Ignore impacts that occur within close range of the last one
271 {
272 float collisionDM = m_fdM;
273
274 // Ignore velocity change when colliding with characters
275 if (m_eImpactType == SCR_EImpactSoundType.CHARACTER)
276 {
277 collisionDM = -1 * m_eImpactType;
278 }
279
280 const SCR_EImpactSoundEvent eventIndex = GetImpactSoundEventIndex(m_vNormal);
281
282 PlayImpactSound(eventIndex, m_vPosition, m_iSurface, collisionDM);
283
284 if (m_iMagnitude != -1)
285 {
288 }
289 else
290 {
291 Rpc(RPC_OnImpactSoundBroadcast, eventIndex, m_vPosition, m_iSurface, collisionDM);
292 }
293
294 // Set cashed values
295 m_iMagnitude = -1;
297
298 // Reset position last after COLLISION_LAST_POSITION_REST_TIME
300 }
301
302 m_fdM = 0;
304 }
305
306 //------------------------------------------------------------------------------------------------
307 protected void PlayImpactParticle(vector position, int magnitude, GameMaterial material)
308 {
309 vector transform[4];
310 Math3D.MatrixIdentity4(transform);
311 transform[3] = position;
312
313 ParticleEffectInfo effectInfo = material.GetParticleEffectInfo();
314 ResourceName resourceName = effectInfo.GetBlastResource(magnitude);
315
316 if (resourceName.IsEmpty())
317 resourceName = GetDefaultParticles()[magnitude];
318
319 EmitParticles(transform, resourceName);
320 }
321
322 //------------------------------------------------------------------------------------------------
323 protected void PlayImpactSound(SCR_EImpactSoundEvent eventIndex, vector position, int surface, float collisionDM)
324 {
326 return;
327
329 m_SignalsManagerComponent.SetSignalValue(m_SignalsManagerComponent.AddOrFindSignal(COLLISION_D_M_SIGNAL_NAME), collisionDM);
330 m_SoundComponent.SoundEventOffset(typename.EnumToString(SCR_EImpactSoundEvent, eventIndex), GetOwner().CoordToLocal(position));
331 }
332
333 //------------------------------------------------------------------------------------------------
334 protected float GetAproximatedMass(IEntity entity)
335 {
336 Physics physics = GetOwner().GetPhysics();
337 if (physics == null)
338 return 0;
339
340 int responseIndex = physics.GetResponseIndex();
341
342 if (responseIndex < SCR_EPhysicsResponseIndex.TINY_DESTRUCTIBLE || responseIndex >= SCR_EPhysicsResponseIndex.NO_COLLISION)
343 return 1700;
344
345 return m_aAproximatedMasses[responseIndex - SCR_EPhysicsResponseIndex.TINY_DESTRUCTIBLE];
346 }
347
348 //------------------------------------------------------------------------------------------------
350 {
351 m_vPositionLast = vector.Zero;
352 }
353
354 //------------------------------------------------------------------------------------------------
355 SCR_EImpactSoundEvent GetImpactSoundEventIndex(vector normal)
356 {
357 vector normalLocal = GetOwner().VectorToLocal(normal);
358 normalLocal = normalLocal.VectorToAngles();
359
360 float pitch = normalLocal[1];
361
362 if (pitch > 225 && pitch <= 315)
363 {
364 return SCR_EImpactSoundEvent.SOUND_VEHICLE_IMPACT_TOP;
365 }
366 else if (pitch > 45 && pitch <= 135)
367 {
368 return SCR_EImpactSoundEvent.SOUND_VEHICLE_IMPACT_BOTTOM;
369 }
370 else
371 {
372 float yaw = normalLocal[0];
373
374 if ((yaw > 45 && yaw <= 135) || (yaw > 225 && yaw <= 315))
375 {
376 return SCR_EImpactSoundEvent.SOUND_VEHICLE_IMPACT_SIDE;
377 }
378
379 return SCR_EImpactSoundEvent.SOUND_VEHICLE_IMPACT_FRONT;
380 }
381 }
382
383 //------------------------------------------------------------------------------------------------
384 [RplRpc(RplChannel.Unreliable, RplRcver.Broadcast)]
385 protected void RPC_OnImpactParticlesBroadcast(vector contactPos, vector contactNormal, int magnitude)
386 {
387 if(IsPhysicActive())
388 return;
389
390 vector transform[4];
391 Math3D.MatrixIdentity4(transform);
392 transform[3] = contactPos;
393
394 TraceParam trace = new TraceParam();
395 trace.Start = contactPos + contactNormal;
396 trace.End = contactPos - contactNormal;
397 trace.Flags = TraceFlags.WORLD | TraceFlags.ENTS;
398
399 GetOwner().GetWorld().TraceMove(trace, TraceFilter);
400
401 GameMaterial contactMat = trace.SurfaceProps;
402 ParticleEffectInfo effectInfo = contactMat.GetParticleEffectInfo();
403 ResourceName resourceName = effectInfo.GetBlastResource(magnitude);
404
405 if (resourceName.IsEmpty())
406 resourceName = GetDefaultParticles()[magnitude];
407
408 EmitParticles(transform, resourceName);
409 }
410
411 //------------------------------------------------------------------------------------------------
412 [RplRpc(RplChannel.Unreliable, RplRcver.Broadcast)]
413 protected void RPC_OnImpactSoundBroadcast(SCR_EImpactSoundEvent eventIndex, vector impactPosition, int impactSurface, float collisionDM)
414 {
415 if(IsPhysicActive())
416 return;
417
418 PlayImpactSound(eventIndex, impactPosition, impactSurface, collisionDM);
419 }
420
421 //------------------------------------------------------------------------------------------------
422 [RplRpc(RplChannel.Unreliable, RplRcver.Broadcast)]
423 protected void RPC_OnImpactSoundAndParticlesBroadcast(vector impactPosition, float collisionDM, vector contactNormal, int magnitude)
424 {
425
426 vector transform[4];
427 Math3D.MatrixIdentity4(transform);
428 transform[3] = impactPosition;
429
430 TraceParam trace = new TraceParam();
431 trace.Start = impactPosition + contactNormal;
432 trace.End = impactPosition - contactNormal;
433 trace.Flags = TraceFlags.WORLD | TraceFlags.ENTS;
434
435 GetOwner().GetWorld().TraceMove(trace, TraceFilter);
436
437 GameMaterial contactMat = trace.SurfaceProps;
438 ParticleEffectInfo effectInfo = contactMat.GetParticleEffectInfo();
439 ResourceName resourceName = effectInfo.GetBlastResource(magnitude);
440
441 if (resourceName.IsEmpty())
442 resourceName = GetDefaultParticles()[magnitude];
443
444 EmitParticles(transform, resourceName);
445
446 PlayImpactSound(GetImpactSoundEventIndex(contactNormal), impactPosition, contactMat.GetSoundInfo().GetSignalValue(), collisionDM);
447 }
448
449 //------------------------------------------------------------------------------------------------
450 [RplRpc(RplChannel.Unreliable, RplRcver.Broadcast)]
451 protected void RPC_OnWaterEnterBroadcast(vector transform[4], int magnitude)
452 {
454 string soundEvent = WATER_SOUNDS[magnitude];
455
456 if (resourceName.IsEmpty())
458
459 EmitParticles(transform, resourceName);
460 PlaySound(soundEvent);
461 }
462
463 //------------------------------------------------------------------------------------------------
464 protected bool IsPhysicActive()
465 {
466 Physics physics = GetOwner().GetPhysics();
467 if (physics && physics.IsActive())
468 return true;
469
470 return false;
471 }
472
473 //------------------------------------------------------------------------------------------------
474 protected bool TraceFilter(notnull IEntity e)
475 {
476 return e != GetOwner() && e.GetRootParent() != GetOwner(); // ignore if traced entity is vehicle or vehicle part
477 }
478
479 //------------------------------------------------------------------------------------------------
480 override void EOnInit(IEntity owner)
481 {
483 m_ParticleSpawnParams.TransformMode = ETransformMode.WORLD;
484 m_ParticleSpawnParams.UseFrameEvent = true;
485
488
489 Physics physics = owner.GetPhysics();
490 if (physics)
491 m_fMass = physics.GetMass();
492
493 RplComponent rpl = RplComponent.Cast(GetOwner().FindComponent(RplComponent));
494 if (!rpl || rpl.IsProxy())
495 return;
496
497 SCR_VehicleBuoyancyComponent buoyancyComp = SCR_VehicleBuoyancyComponent.Cast(GetOwner().FindComponent(SCR_VehicleBuoyancyComponent));
498 if (!buoyancyComp)
499 return;
500
501 buoyancyComp.GetOnWaterEnter().Insert(OnWaterEnter);
502 }
503
504 //------------------------------------------------------------------------------------------------
505 override void OnPostInit(IEntity owner)
506 {
508 }
509}
EWaterSurfaceType
ArmaReforgerScripted GetGame()
Definition game.c:1398
enum SCR_EAICombatMoveRequestType CHARACTER
ResourceName resourceName
Definition SCR_AIGroup.c:66
SCR_CharacterSoundComponentClass GetComponentData()
SCR_DestructibleTreeV2Class impulse
vector position
enum SCR_EImpactSoundType SOUND_VEHICLE_IMPACT_SIDE
ref array< ResourceName > m_aWaterParticles
int m_iEffectMagnitude
enum SCR_EImpactSoundType SOUND_VEHICLE_IMPACT_FRONT
enum SCR_EImpactSoundType SOUND_VEHICLE_IMPACT_TOP
void ParticleEffectEntity(IEntitySource src, IEntity parent)
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
void SCR_VehicleDamageManagerComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
proto external int SetEventMask(notnull IEntity owner, int mask)
proto external GenericComponent FindComponent(typename typeName)
void Rpc(func method, void p0=NULL, void p1=NULL, void p2=NULL, void p3=NULL, void p4=NULL, void p5=NULL, void p6=NULL, void p7=NULL)
proto external Physics GetPhysics()
proto external BaseWorld GetWorld()
proto external void GetTransform(out vector mat[])
proto external vector VectorToLocal(vector vec)
proto external IEntity GetRootParent()
Definition Math.c:13
void PlayImpactParticle(vector position, int magnitude, GameMaterial material)
void RPC_OnImpactSoundBroadcast(SCR_EImpactSoundEvent eventIndex, vector impactPosition, int impactSurface, float collisionDM)
array< ResourceName > GetWaterParticles()
float GetAproximatedMass(IEntity entity)
static const ref array< string > WATER_SOUNDS
void PlayImpactSound(SCR_EImpactSoundEvent eventIndex, vector position, int surface, float collisionDM)
array< ResourceName > GetDefaultParticles()
void RPC_OnImpactSoundAndParticlesBroadcast(vector impactPosition, float collisionDM, vector contactNormal, int magnitude)
void EmitParticles(vector transform[4], ResourceName particleResource)
void UpdateParticlesMagnitude(notnull IEntity other, float impulse)
void OnImpact(notnull IEntity other, float impulse, vector impactPosition, vector impactNormal, GameMaterial mat, vector velocityBefore=vector.Zero, vector velocityAfter=vector.Zero)
void RPC_OnImpactParticlesBroadcast(vector contactPos, vector contactNormal, int magnitude)
bool TraceFilter(notnull IEntity e)
SCR_EImpactSoundEvent GetImpactSoundEventIndex(vector normal)
void RPC_OnWaterEnterBroadcast(vector transform[4], int magnitude)
override void EOnInit(IEntity owner)
override void OnPostInit(IEntity owner)
ref ParticleEffectEntitySpawnParams m_ParticleSpawnParams
SignalsManagerComponent m_SignalsManagerComponent
proto external GenericEntity GetOwner()
Get owner entity.
@ DEFAULT
Use currently set main RT format (based on game options).
SCR_FieldOfViewSettings Attribute
EntityEvent
Various entity events.
Definition EntityEvent.c:14
void RplRpc(RplChannel channel, RplRcver rcver, RplCondition condition=RplCondition.None, string customConditionName="")
Definition EnNetwork.c:95
RplRcver
Definition RplRcver.c:59
RplChannel
Communication channel. Reliable is guaranteed to be delivered. Unreliable not.
Definition RplChannel.c:14
proto native bool IsEmpty()
TraceFlags
Definition TraceFlags.c:13