Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_RotorDamageManagerComponent.c
Go to the documentation of this file.
4
5class SCR_RotorDamageManagerComponent : SCR_DamageManagerComponent
6{
10 protected SCR_RotorHitZone m_RotorHitZone;
11
14 // Collider index for static rotor
15 protected int m_iShapeIndex1 = -1;
16
17 protected const float MIN_ROTOR_DAMAGE = 15.0; //everything below 15.0 gets discarded when calling HandleDamage
18
19 [Attribute(defvalue: "0.5")]
21
22 [Attribute(defvalue: "1.0")]
23 protected float m_fRotorDamageMultiplier;
24
25 [Attribute(defvalue: "1.0")]
27
28 [Attribute(defvalue: "50.0")]
30
31 [Attribute(defvalue: "10.0")]
32 protected float m_fMinCharacterDamage;
33
34 [Attribute(defvalue: "10000.0")]
35 protected float m_fMaxCharacterDamage;
36
37 [Attribute("{4AAF69CCD1AEA70E}Particles/Vehicle/Helicopter/Rotor Collision Effects/Helicopter_Rotor_Collision_Main_Solid.ptc")]
39
40 [Attribute(defvalue: "2")]
41 protected int m_iEffectIndex;
42
43 [Attribute(desc: "Blade collision sound event")]
44 protected string m_sImpactSoundEvent;
45
46 //------------------------------------------------------------------------------------------------
48 override bool ShouldCountAsHit(notnull BaseDamageContext damageContext)
49 {
50 SCR_RotorHitZone hitZone = SCR_RotorHitZone.Cast(damageContext.struckHitZone);
51 if (!hitZone)
52 return true;
53
54 if (damageContext.damageType == EDamageType.KINETIC && Math.RandomFloat01() > hitZone.RotorHitChance(damageContext.hitPosition))
55 return false;
56
57 return true;
58 }
59 //------------------------------------------------------------------------------------------------
60 protected void DamageRotors(float damage)
61 {
63 if (damage < MIN_ROTOR_DAMAGE)
64 damage = MIN_ROTOR_DAMAGE;
65
66 m_RotorHitZone.HandleDamage(damage, EDamageType.COLLISION, null);
67 }
68
69 //------------------------------------------------------------------------------------------------
70 protected void DamageOther(notnull IEntity other, float damage, notnull Contact contact, float rotorRPM)
71 {
72 ChimeraCharacter character = ChimeraCharacter.Cast(other);
73 if (!character)
74 return;
75
76 SCR_DamageManagerComponent characterDamageManager = character.GetDamageManager();
77 CharacterAnimationComponent characterAnimationComponent = character.GetAnimationComponent();
78 if (!characterDamageManager || !characterAnimationComponent)
79 return;
80
81 vector transformDir[4], rotorMat[4];
82 m_RotorHitZone.GetPointInfo().GetWorldTransform(rotorMat);
83
84 if (characterDamageManager.IsDestroyed())
85 {
86 const float ragrollEffectRadius = 0.5;
87 const float ragrollEffectMaxTime = 2;
88 vector forwardVec = vector.Direction(rotorMat[3], contact.Position).Normalized();
89 vector upVec = rotorMat[1];
90 vector impactOrientationMat[4];
91 Math3D.DirectionAndUpMatrix(forwardVec, upVec, impactOrientationMat);
92 vector worldImpactDir = impactOrientationMat[0];
93 if (m_HelicopterSimulation.RotorGetSpinDirection(m_RotorHitZone.GetRotorIndex()) == SpinDirection.CLOCKWISE)
94 worldImpactDir = -worldImpactDir;
95
96 vector hitPosLocal = character.CoordToLocal(contact.Position);
97 vector directionLocal = character.VectorToLocal(worldImpactDir).Normalized();
98 float force = rotorRPM * m_fCharacterImpulseMultiplier;
99 characterAnimationComponent.AddRagdollEffectorDamage(hitPosLocal, directionLocal, force, ragrollEffectRadius, ragrollEffectMaxTime);
100
101 return;
102 }
103
105
106 Physics otherPhysics = other.GetPhysics();
107 array<HitZone> characterHitZones = {};
108 characterDamageManager.GetAllHitZones(characterHitZones);
109
110 SCR_DamageContext context;
112 Vehicle vehicle = Vehicle.Cast(GetOwner().GetRootParent());
113 if (!vehicle)
114 return;
115
116 Instigator instigator = Instigator.CreateInstigator(vehicle.GetPilot());
117 GameMaterial gameMaterial;
118 array<int> colliderIDs = {};
119 array<SurfaceProperties> surfaces = {};
121 int nodeID;
122 MeshObject meshObject = character.GetVObject().ToMeshObject();
123
124 foreach (HitZone characterHitZone : characterHitZones)
125 {
126 if (!characterHitZone.HasColliderNodes() || characterHitZone.GetDamageState() == EDamageState.DESTROYED)
127 continue;
128
129 colliderIDs.Clear();
130 characterHitZone.GetColliderIDs(colliderIDs);
131
132 foreach (int colliderID : colliderIDs)
133 {
134 if (!m_RotorHitZone.HasCollision(otherPhysics.GetGeomWorldPosition(colliderID)))
135 continue;
136
137 surfaces.Clear();
138 otherPhysics.GetGeomSurfaces(colliderID, surfaces);
139 if (surfaces.IsEmpty())
140 continue;
141
142 direction = vector.Direction(rotorMat[3], otherPhysics.GetGeomWorldPosition(colliderID));
143 Math3D.DirectionAndUpMatrix(direction, rotorMat[0], transformDir);
144 nodeID = PhysicsUtils.GetNodeIndex(meshObject, colliderID);
145 context = new SCR_DamageContext(
146 EDamageType.COLLISION, damage, transformDir,
147 character, characterHitZone, instigator,
148 surfaces[0], colliderID, nodeID
149 );
150
151 context.damageEffect = collisionEffect;
152
153 characterDamageManager.HandleDamage(context);
154 break;
155 }
156 }
157 }
158
159 //------------------------------------------------------------------------------------------------
160 protected void EmitRotorParticles(vector contactPos, GameMaterial contactMat)
161 {
162 //set particle emitter transform
163
164 vector ownerTransform[4];
165 m_RootDamageManager.GetOwner().GetWorldTransform(ownerTransform);
166
167 vector rotorTransformLocal[4];
168 m_HelicopterSimulation.RotorGetTransform(m_RotorHitZone.GetRotorIndex(), rotorTransformLocal);
169
170 float rotorRadius = m_RotorHitZone.GetRotorRadius();
171 float rotorRadiusSq = rotorRadius * rotorRadius;
172
173 vector rotorEdge = vector.Right * rotorRadius;
174 vector contactPositionLocal = contactPos.InvMultiply4(ownerTransform).InvMultiply4(rotorTransformLocal).Normalized() * rotorRadius;
175
176 float distanceEdgeToContactSq = vector.DistanceSq(rotorEdge, contactPositionLocal);
177 float rotorContactAngle = Math.RAD2DEG * Math.Acos((2 * rotorRadiusSq - distanceEdgeToContactSq) / (2 * rotorRadiusSq));
178 if (contactPositionLocal[1] < 0) // if contact is below half-circle, add 180 degrees to complete 360 degree circle
179 rotorContactAngle = 360 - rotorContactAngle;
180
181 vector rotationMatrix[3];
182 if (m_HelicopterSimulation.RotorGetSpinDirection(m_RotorHitZone.GetRotorIndex()) == SpinDirection.CLOCKWISE)
183 Math3D.AnglesToMatrix({180, 0, rotorContactAngle}, rotationMatrix);
184 else
185 Math3D.AnglesToMatrix({180, 0, rotorContactAngle + 180}, rotationMatrix);
186
187 vector resultRotation[3];
188 Math3D.MatrixMultiply3(rotorTransformLocal, rotationMatrix, resultRotation);
189
190 vector translatedTransform[4];
191 Math3D.MatrixMultiply3(ownerTransform, resultRotation, translatedTransform);
192 translatedTransform[3] = contactPos;
193
194 //set particle emitter ptc
195 GameMaterial material = contactMat;
196 ParticleEffectInfo effectInfo = material.GetParticleEffectInfo();
197
198 ResourceName resource = effectInfo.GetVehicleDustResource(m_iEffectIndex);
199 if (!resource || resource.IsEmpty())
200 resource = m_sDefaultParticlePath;
201
202 //play effect
203 m_ParticleSpawnParams.Transform = translatedTransform;
205 }
206
207 //------------------------------------------------------------------------------------------------
211 void PlayRotorImpactSound(vector contactPos, int contactShapeIndex1)
212 {
213 if (!m_SoundComponent)
214 return;
215
216 if (m_sImpactSoundEvent.IsEmpty())
217 return;
218
219 RotorState rotorState = m_HelicopterSimulation.RotorGetState(m_RotorHitZone.GetRotorIndex());
220 if (rotorState == RotorState.DESTROYED)
221 return;
222
223 if (rotorState == RotorState.STATIC)
224 {
225 int shapeIndex1 = contactShapeIndex1;
226 if (m_iShapeIndex1 == shapeIndex1)
227 return;
228
229 m_iShapeIndex1 = shapeIndex1;
230 }
231
232 // Get sound position
233 vector mat[4];
234 Math3D.MatrixIdentity4(mat);
235 mat[3] = contactPos;
236
237 m_SoundComponent.SoundEventTransform(m_sImpactSoundEvent, mat);
238 }
239
240 //------------------------------------------------------------------------------------------------
241 protected override bool ShouldOverrideInstigator(notnull Instigator currentInstigator, notnull Instigator newInstigator)
242 {
243 if (!super.ShouldOverrideInstigator(currentInstigator, newInstigator))
244 return false;
245
246 DamageManagerComponent parentDamageManager = DamageManagerComponent.Cast(GetParentHitZoneContainer());
247 if (parentDamageManager && newInstigator.GetInstigatorType() != InstigatorType.INSTIGATOR_NONE)
248 parentDamageManager.SetInstigator(newInstigator);
249
250 return true;
251 }
252
253 //------------------------------------------------------------------------------------------------
254 override void OnDamageStateChanged(EDamageState newState, EDamageState previousDamageState, bool isJIP)
255 {
256 super.OnDamageStateChanged(newState, previousDamageState, isJIP);
257
259 if (newState != EDamageState.DESTROYED)
260 SetEventMask(GetOwner(), EntityEvent.CONTACT);
261 else
262 ClearEventMask(GetOwner(), EntityEvent.CONTACT);
263 }
264
265 //------------------------------------------------------------------------------------------------
266 protected bool TraceFilter(notnull IEntity e)
267 {
268 return e != GetOwner() && e != m_RootDamageManager.GetOwner(); // ignore if traced entity is rotor or hull
269 }
270
271 //------------------------------------------------------------------------------------------------
273 [RplRpc(RplChannel.Unreliable, RplRcver.Broadcast)]
274 protected void RPC_OnContactBroadcast(vector contactPos, vector contactNormal, int contactShapeIndex1)
275 {
276 TraceParam trace = new TraceParam();
277 trace.Start = contactPos + contactNormal;
278 trace.End = contactPos - contactNormal;
279 trace.Flags = TraceFlags.WORLD | TraceFlags.ENTS;
280
281 GetGame().GetWorld().TraceMove(trace, TraceFilter);
282
283 GameMaterial contactMat = trace.SurfaceProps;
284
285 EmitRotorParticles(contactPos, contactMat);
286 PlayRotorImpactSound(contactPos, contactShapeIndex1);
287 }
288
289 //------------------------------------------------------------------------------------------------
291 override bool FilterContact(IEntity owner, IEntity other, Contact contact)
292 {
293 if (!m_RotorHitZone)
294 return false;
295
296 return super.FilterContact(owner, other, contact);
297 }
298
299 //------------------------------------------------------------------------------------------------
300 override void OnFilteredContact(IEntity owner, IEntity other, Contact contact)
301 {
302 //compute damage
303 vector rotorTransform[4];
304 m_RotorHitZone.GetPointInfo().GetTransform(rotorTransform);
305
306 // GetComponentsDelayed may not have enough time to initialise members. To avoid a VME, initialise m_HelicopterSimulation
308 {
311 return;
312 }
313
314 float rotorRPM = m_HelicopterSimulation.RotorGetRPM(m_RotorHitZone.GetRotorIndex()) * 0.1;
315 float rotorRadius = m_RotorHitZone.GetRotorRadius();
316 float rotorCenterToContact = vector.Distance(rotorTransform[3], contact.Position);
317 float rotorRPMMultiplier = Math.Clamp(rotorCenterToContact / rotorRadius, 0, 1);
318 int rotorBladeCount = m_RotorHitZone.GetBladeCount();
319
320 if (rotorRadius <= 0)
321 rotorRadius = 1;
322 if (rotorBladeCount <= 0)
323 rotorBladeCount = 1;
324
325 float damage = rotorRPM * rotorRPMMultiplier / m_RotorHitZone.GetBladeCount() + contact.Impulse * m_fImpulseDamageMultiplier;
326 if (damage <= 0)
327 return;
328
329 ChimeraCharacter character = ChimeraCharacter.Cast(other);
330 if (!character && m_RootDamageManager && contact.Impulse >= m_RootDamageManager.GetMinImpulse())
331 m_RootDamageManager.ProcessCollision(new SCR_CollisionDamageContainer(GetOwner(), other, contact.Impulse, contact.VelocityBefore1, contact.VelocityAfter1, contact.VelocityBefore2, contact.VelocityAfter2, contact.Position, contact.Normal));
332
333 if (m_RotorHitZone.IsSpinning())
334 {
335 if (character)
336 DamageOther(other, damage, contact, rotorRPM);
337
338 RPC_OnContactBroadcast(contact.Position, contact.Normal, contact.ShapeIndex1);
339 Rpc(RPC_OnContactBroadcast, contact.Position, contact.Normal, contact.ShapeIndex1);
340 }
341
342 DamageRotors(damage);
343
344 super.OnFilteredContact(owner, other, contact);
345 }
346
347 //---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
348 // TODO: Call queue should not be needed there, it is because of hierarchy / slots
349 //------------------------------------------------------------------------------------------------
362 //---- REFACTOR NOTE END ----
363
364 //------------------------------------------------------------------------------------------------
365 override void OnPostInit(IEntity owner)
366 {
367 super.OnPostInit(owner);
368
369 // Do not do anything if the default hitzone is not rotor hitzone
370 m_RotorHitZone = SCR_RotorHitZone.Cast(GetDefaultHitZone());
371 if (!m_RotorHitZone)
372 return;
373
374 //---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
375 GetGame().GetCallqueue().CallLater(GetComponentsDelayed); //get components after init
376 //---- REFACTOR NOTE END ----
377
378 RplComponent rplComp = RplComponent.Cast(GetOwner().FindComponent(RplComponent));
379 if (!rplComp || rplComp.IsProxy())
380 return;
381
382 SetEventMask(GetOwner(), EntityEvent.CONTACT);
383 }
384}
ArmaReforgerScripted GetGame()
Definition game.c:1398
override bool FilterContact(IEntity owner, IEntity other, Contact contact)
Armor doesn't take collisiondamage.
vector direction
override void OnDamageStateChanged(EDamageState newState, EDamageState previousDamageState, bool isJIP)
void ParticleEffectEntity(IEntitySource src, IEntity parent)
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
ref ParticleEffectEntitySpawnParams m_ParticleSpawnParams
string m_sImpactSoundEvent
ParticleEffectEntity m_ParticleEffectEntity
SCR_RotorDamageManagerComponentClass m_HelicopterSimulation
float m_fCharacterImpulseMultiplier
ResourceName m_sDefaultParticlePath
SCR_RotorHitZone m_RotorHitZone
void GetComponentsDelayed()
void PlayRotorImpactSound(vector contactPos, int contactShapeIndex1)
override bool ShouldOverrideInstigator(notnull Instigator currentInstigator, notnull Instigator newInstigator)
void DamageOther(notnull IEntity other, float damage, notnull Contact contact, float rotorRPM)
SCR_VehicleDamageManagerComponent m_RootDamageManager
float m_fImpulseDamageMultiplier
const float MIN_ROTOR_DAMAGE
SoundComponent m_SoundComponent
void DamageRotors(float damage)
override bool ShouldCountAsHit(notnull BaseDamageContext damageContext)
Calculate whether bullets actually hit the rotor with RotorHitChance.
float m_fMinCharacterDamage
float m_fMaxCharacterDamage
override void OnFilteredContact(IEntity owner, IEntity other, Contact contact)
void EmitRotorParticles(vector contactPos, GameMaterial contactMat)
float m_fCharacterDamageMultiplier
float m_fRotorDamageMultiplier
void RPC_OnContactBroadcast(vector contactPos, vector contactNormal, int contactShapeIndex1)
Clients don't simulate physics so this rpc replicates collision information for particles,...
bool TraceFilter(notnull IEntity e)
void SCR_VehicleDamageManagerComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
proto external Managed FindComponent(typename typeName)
proto external IEntity GetRootParent()
Definition Math.c:13
MeshObject.
Definition MeshObject.c:34
enum EPhysicsLayerPresets Vehicle
Definition gameLib.c:24
IEntity GetOwner()
Owner entity of the fuel tank.
InstigatorType
SCR_FieldOfViewSettings Attribute
EntityEvent
Various entity events.
Definition EntityEvent.c:14
EDamageType
Definition EDamageType.c:13
EDamageState
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
SpinDirection
RotorState
Definition RotorState.c:13
TraceFlags
Definition TraceFlags.c:13