Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_ChimeraCharacter.c
Go to the documentation of this file.
2{
3 [Attribute("{00B4F7EE9753F658}Configs\CharacterLinking\BushTypeSlow.conf", UIWidgets.ResourceNamePicker, category: "Foliage Slowdown")]
5
6 [Attribute("0 0 10 5", uiwidget: UIWidgets.CurveDialog, desc: "Relation of foliage height and the slowing effect", category: "Foliage Slowdown", params: "10 1 0 0")]
8 // the curve helps us calculate the appropriate slowdown from a foliage entity using its type and the (weighted) height
9 // it goes back up near the end to make trees less of a hindrance as their branches are usually less dense than bushes
10
12
13 //------------------------------------------------------------------------------------------------
18
19 //------------------------------------------------------------------------------------------------
21 {
23 {
24 Resource container = BaseContainerTools.LoadContainer(m_sBushSlowTypeCfgPath);
25 if (container)
26 s_BushSlowTypeCfg = SCR_BushTypeSlowConfig.Cast(BaseContainerTools.CreateInstanceFromContainer(container.GetResource().ToBaseContainer()));
27 }
28
29 return s_BushSlowTypeCfg;
30 }
31}
32
33class SCR_ChimeraCharacter : ChimeraCharacter
34{
36 float m_fFaceAlphaTest = 0; // Used to fade away the head when getting close with the 3rd person camera
37
39 FactionAffiliationComponent m_pFactionComponent;
40
42 SCR_CharacterPerceivableComponent m_pPerceivableComponent;
43
44 [Attribute(defvalue: "1", desc: "Can this character be recruited by players"), RplProp(), NonSerialized()]
45 protected bool m_bRecruitable;
46
48 protected ref array<IEntity> m_aContacts;
49
51 protected bool m_bIsRecruited = 0;
52
53 protected static const string SIGNAL_NAME_SPECIAL_CONTACT = "SpecialContact";
54 protected static const string SIGNAL_NAME_SPECIAL_ENTITY_HEIGHT = "SpecialContactEntityHeight";
55
57 protected float m_fTargetSpeed, m_fCurrentSpeed = 1;
58
59 //------------------------------------------------------------------------------------------------
60 override void EOnInit(IEntity owner)
61 {
62 m_pFactionComponent = FactionAffiliationComponent.Cast(FindComponent(FactionAffiliationComponent));
63 m_pPerceivableComponent = SCR_CharacterPerceivableComponent.Cast(FindComponent(CharacterPerceivableComponent));
64 }
65
66 //------------------------------------------------------------------------------------------------
68 {
70 return m_pFactionComponent.GetAffiliatedFaction();
71
72 return null;
73 }
74
75 //------------------------------------------------------------------------------------------------
77 {
78 Faction faction = GetFaction();
79 if (!faction)
80 return string.Empty;
81
82 return faction.GetFactionKey();
83 }
84
85 //------------------------------------------------------------------------------------------------
87 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
88 protected void RPC_SetIllumination_BC(bool state, RplId rplId)
89 {
90 RplComponent sourceRplComp = RplComponent.Cast(Replication.FindItem(rplId));
91 if (!sourceRplComp)
92 return;
93
94 IEntity soundEntity = sourceRplComp.GetEntity();
95 if (!soundEntity)
96 return;
97
98 SoundComponent soundComp = SoundComponent.Cast(soundEntity.FindComponent(SoundComponent));
99 if (!soundComp)
100 return;
101
102 if (state)
103 soundComp.SoundEvent(SCR_SoundEvent.SOUND_SCOPE_ILLUM_ON);
104 else
105 soundComp.SoundEvent(SCR_SoundEvent.SOUND_SCOPE_ILLUM_OFF);
106 }
107
108 //------------------------------------------------------------------------------------------------
109 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
110 protected void RPC_SetIllumination_S(bool state, RplId rplId)
111 {
112 RPC_SetIllumination_BC(state, rplId);
113 //Broadcast to everybody
114 Rpc(RPC_SetIllumination_BC, state, rplId);
115 }
116
117 //------------------------------------------------------------------------------------------------
118 void SetIllumination(bool illuminated, RplId rplId)
119 {
120 //Ask the server to broadcast to everybody.
121 Rpc(RPC_SetIllumination_S, illuminated, rplId);
122 }
123
124 //------------------------------------------------------------------------------------------------
126 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
127 protected void RPC_SetNewZoomLevel_BC(int zoomLevel, bool increased, RplId rplId)
128 {
129 WeaponComponent wpnComp = WeaponComponent.Cast(Replication.FindItem(rplId));
130 if (wpnComp)
131 {
132 IEntity wpnEntity = wpnComp.GetOwner();
133 if (wpnEntity)
134 {
135 WeaponSoundComponent wpnSoundComp = WeaponSoundComponent.Cast(wpnEntity.FindComponent(WeaponSoundComponent));
136 if (wpnSoundComp)
137 {
138 if (increased)
139 wpnSoundComp.SoundEvent(SCR_SoundEvent.SOUND_SCOPE_ZOOM_IN);
140 else
141 wpnSoundComp.SoundEvent(SCR_SoundEvent.SOUND_SCOPE_ZOOM_OUT);
142 }
143 }
144 }
145 }
146
147 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
148 protected void RPC_SetNewZoomLevel_S(int zoomLevel, bool increased, RplId rplId)
149 {
150 RPC_SetNewZoomLevel_BC(zoomLevel, increased, rplId);
151 //Broadcast to everybody
152 Rpc(RPC_SetNewZoomLevel_BC, zoomLevel, increased, rplId);
153 }
154
155 void SetNewZoomLevel(int zoomLevel, bool increased, RplId rplId)
156 {
157 Rpc(RPC_SetNewZoomLevel_S, zoomLevel, increased, rplId);
158 }
159
160 //------------------------------------------------------------------------------------------------
165 bool IsDriving(float minSpeedSq = -1)
166 {
167 if (!IsInVehicle())
168 return false;
169
170 CompartmentAccessComponent access = GetCompartmentAccessComponent();
171 if (!access)
172 return false;
173
174 PilotCompartmentSlot pilotSlot = PilotCompartmentSlot.Cast(access.GetCompartment());
175 if (!pilotSlot)
176 return false;
177
178 Vehicle vehicle = Vehicle.Cast(pilotSlot.GetOwner());
179 if (!vehicle)
180 return false;
181
182 if (vehicle.GetPilotCompartmentSlot() != pilotSlot)
183 return false;
184
185 if (minSpeedSq <= 0)
186 return true;
187
188 Physics physics = vehicle.GetPhysics();
189 if (!physics)
190 return false;
191
192 return physics.GetVelocity().LengthSq() >= minSpeedSq;
193 }
194
195 //------------------------------------------------------------------------------------------------
197 {
198 return m_bRecruitable;
199 }
200
201 //------------------------------------------------------------------------------------------------
202 void SetRecruitable(bool isRecruitable)
203 {
204 m_bRecruitable = isRecruitable;
205 Replication.BumpMe();
206 }
207
208 //------------------------------------------------------------------------------------------------
210 {
211 return m_bIsRecruited;
212 }
213
214 //------------------------------------------------------------------------------------------------
215 void SetRecruited(bool recruited)
216 {
217 m_bIsRecruited = recruited;
218 Replication.BumpMe();
219 }
220
221 //------------------------------------------------------------------------------------------------
223 override void OnSpecialContactsChagned(notnull array<IEntity> contacts)
224 {
226 if (!signalsMgr)
227 return;
228
229 RplComponent characterRplComp = GetRplComponent();
230 bool isAuthority = characterRplComp && !characterRplComp.IsProxy();
231
232 RplComponent changedEntityRplComp;
233 if (m_aContacts)
234 {
235 RplId changedEntityRplId;
236 for (int i = m_aContacts.Count() - 1; i >= 0; i--)
237 {
238 if (!m_aContacts.IsIndexValid(i) || contacts.Contains(m_aContacts[i]))
239 continue;
240
241 if (!isAuthority)
242 {
243 if (m_aContacts[i])
244 changedEntityRplComp = SCR_EntityHelper.GetEntityRplComponent(m_aContacts[i]);
245
246 if (changedEntityRplComp)
247 changedEntityRplId = changedEntityRplComp.Id();
248 else
249 changedEntityRplId = RplId.Invalid();
250
251 Rpc(Rpc_ContactChanged, changedEntityRplId, false);
252 }
253
255 }
256 }
257
258 float highestModifiedHeight, evaluationModHeight;
259
260 Tree currentTree;
261 ETreeSoundTypes currentTreeType = ETreeSoundTypes.None;
262
263 SCR_SpecialCollisionHandlerComponent specialCollisionComponent;
264 foreach (IEntity newContact : contacts)
265 {
266 if (m_aContacts && m_aContacts.Contains(newContact))
267 continue;
268
269 specialCollisionComponent = SCR_SpecialCollisionHandlerComponent.Cast(newContact.FindComponent(SCR_SpecialCollisionHandlerComponent));
270 if (!specialCollisionComponent)
271 {
272 currentTree = Tree.Cast(newContact);
273 if (!currentTree) // checking if the entity is a bush or a tree
274 continue;
275
276 vector mins, maxs;
277 newContact.GetBounds(mins, maxs);
278
279 currentTreeType = TreeClass.Cast(currentTree.GetPrefabData()).SoundType;
280 evaluationModHeight = GetModifiedBushHeight(maxs[1]-mins[1] , currentTreeType);
281
282 if (evaluationModHeight > highestModifiedHeight)
283 highestModifiedHeight = evaluationModHeight;
284
285 continue;
286 }
287
288 if (!isAuthority)
289 {
290 changedEntityRplComp = SCR_EntityHelper.GetEntityRplComponent(newContact);
291 if (changedEntityRplComp)
292 Rpc(Rpc_ContactChanged, changedEntityRplComp.Id(), true);
293 }
294
295 AddNewContact(newContact);
296 }
297
298 CalculateAndSetSlowdown(highestModifiedHeight);
299 }
300
301 //------------------------------------------------------------------------------------------------
302 protected float GetModifiedBushHeight(float foliageHeight, ETreeSoundTypes treeType = ETreeSoundTypes.Bush)
303 {
304 // some types of bushes are thicker than others so using the height and type of foliage we approximate the slowdown
306
307 return foliageHeight * classData.GetBushSlowTypeCfg().GetHeightSlowEffectModifier(treeType);
308 }
309
310 //------------------------------------------------------------------------------------------------
311 protected void CalculateAndSetSlowdown(float bushModdedHeight)
312 {
314
315 // calculate the slow effect based on the modified height on the curve
316 float bushSlow = LegacyCurve.Curve(
317 ECurveType.CurveProperty2D,
318 bushModdedHeight,
319 classData.GetFoliageHeightSlowdownCurve())[1];
320
321 SetSpeedLimit(this, bushSlow);
322 }
323
324 //------------------------------------------------------------------------------------------------
325 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
326 protected void Rpc_ContactChanged(RplId changedEntityRplId, bool wasAdded)
327 {
328 if (RplId.Invalid() == changedEntityRplId)
329 {//remove contact with entity that no longer exists
331 return;
332 }
333
334 RplComponent rplComp = RplComponent.Cast(Replication.FindItem(changedEntityRplId));
335 if (!rplComp)
336 return;
337
338 IEntity changedEntity = rplComp.GetEntity();
339 if (!changedEntity)
340 return;
341
342 if (wasAdded && (!m_aContacts || !m_aContacts.Contains(changedEntity)))
343 AddNewContact(changedEntity);
344 else if (!wasAdded && m_aContacts && m_aContacts.Contains(changedEntity))
345 RemoveOldContact(changedEntity);
346 }
347
348 //------------------------------------------------------------------------------------------------
349 protected void AddNewContact(notnull IEntity newContact)
350 {
351 if (!m_aContacts)
352 m_aContacts = {};
353
354 m_aContacts.Insert(newContact);
355
356 array <SCR_SpecialCollisionDamageEffect> specialDamageEffects = {};
357
358 SCR_SpecialCollisionHandlerComponent specialCollisionComponent = SCR_SpecialCollisionHandlerComponent.Cast(newContact.FindComponent(SCR_SpecialCollisionHandlerComponent));
359 if (!specialCollisionComponent)
360 return;
361
362 SCR_SpecialCollisionHandlerComponentClass data = SCR_SpecialCollisionHandlerComponentClass.Cast(specialCollisionComponent.GetComponentData(newContact));
363 if (!data)
364 return;
365
366 RplComponent characterRplComp = GetRplComponent();
367 bool isAuthority = characterRplComp && characterRplComp.Role() == RplRole.Authority;
368 if (isAuthority)
369 {
371 if (!damageMgr)
372 return;
373
374 data.GetSpecialCollisionDamageEffects(specialDamageEffects);
375
376 foreach (SCR_SpecialCollisionDamageEffect effect : specialDamageEffects)
377 {
378 effect.SetResponsibleEntity(newContact);
379 damageMgr.AddSpecialContactEffect(effect);
380 }
381 }
382
383 specialCollisionComponent.OnContactStart(this);
385 if (!signalsMgr)
386 return;
387
388 int contactSignalId = signalsMgr.AddOrFindMPSignal(SIGNAL_NAME_SPECIAL_CONTACT, 1, 1);
389 if (contactSignalId < 0 || data.GetContactType() < 1)
390 return;
391
392 signalsMgr.SetSignalValue(contactSignalId, data.GetContactType());
393
394 int heightSignalId = signalsMgr.AddOrFindMPSignal(SIGNAL_NAME_SPECIAL_ENTITY_HEIGHT, 0.2, 1);
395 if (heightSignalId < 0)
396 return;
397
398 signalsMgr.SetSignalValue(heightSignalId, specialCollisionComponent.GetContactHeight());
399 }
400
401 //------------------------------------------------------------------------------------------------
402 protected void RemoveOldContact(IEntity oldContact = null)
403 {
404 if (!m_aContacts)
405 return;
406
407 m_aContacts.RemoveItemOrdered(oldContact);
408
409 RplComponent characterRplComp = GetRplComponent();
410 bool isAuthority = characterRplComp && characterRplComp.Role() == RplRole.Authority;
411 if (isAuthority)
412 {
414 if (!damageMgr)
415 return;
416
417 array<ref SCR_PersistentDamageEffect> effects = {};
418 damageMgr.GetPersistentEffects(effects);
419
421
422 foreach (SCR_PersistentDamageEffect effect : effects)
423 {
424 specialEffect = SCR_SpecialCollisionDamageEffect.Cast(effect);
425 if (!specialEffect)
426 continue;
427
428 if (oldContact == specialEffect.GetResponsibleEntity())
429 specialEffect.Terminate();
430 }
431 }
432
434 if (!signalsMgr)
435 return;
436
437 int contactSignalId = signalsMgr.FindSignal(SIGNAL_NAME_SPECIAL_CONTACT);
438 if (contactSignalId < 0)
439 return;
440
441 int heightSignalId = signalsMgr.FindSignal(SIGNAL_NAME_SPECIAL_ENTITY_HEIGHT);
442 if (m_aContacts.IsEmpty())
443 {
444 signalsMgr.SetSignalValue(contactSignalId, 0);
445 if (heightSignalId >= 0)
446 signalsMgr.SetSignalValue(heightSignalId, 0);
447
448 return;
449 }
450
451 IEntity lastContact;
452 for (int lastId = m_aContacts.Count() - 1; lastId >= 0; lastId--)
453 {
454 lastContact = m_aContacts[lastId];
455 if (lastContact)
456 break;
457
458 m_aContacts.Remove(lastId);
459 }
460
461 if (!lastContact)
462 {//if there is no other contact that should control the signals then we need to clear them
463 signalsMgr.SetSignalValue(contactSignalId, 0);
464 if (heightSignalId >= 0)
465 signalsMgr.SetSignalValue(heightSignalId, 0);
466
467 return;
468 }
469
470 SCR_SpecialCollisionHandlerComponent specialCollisionComponent;
472 if (!data)
473 return;
474
475 if (oldContact)
476 {
477 specialCollisionComponent = SCR_SpecialCollisionHandlerComponent.Cast(oldContact.FindComponent(SCR_SpecialCollisionHandlerComponent));
478 if (specialCollisionComponent)
479 {
480 specialCollisionComponent.OnContactEnd(this);
481 data = SCR_SpecialCollisionHandlerComponentClass.Cast(specialCollisionComponent.GetComponentData(oldContact));
482 }
483
484 if (data && signalsMgr.GetSignalValue(contactSignalId) != data.GetContactType())
485 return;//if something changed signal value then we should leave it as is
486
487 if (oldContact && lastContact.GetPrefabData() == oldContact.GetPrefabData())
488 return;//if last remaining contact is the same prefab as old contact then there is no reason to change values of signals
489 }
490
491 specialCollisionComponent = SCR_SpecialCollisionHandlerComponent.Cast(lastContact.FindComponent(SCR_SpecialCollisionHandlerComponent));
492 if (!specialCollisionComponent)
493 return;
494
495 data = SCR_SpecialCollisionHandlerComponentClass.Cast(specialCollisionComponent.GetComponentData(lastContact));
496 signalsMgr.SetSignalValue(contactSignalId, data.GetContactType());
497 if (heightSignalId < 0)
498 return;
499
500 float height;
501 if (data.GetContactType() != 0)
502 height = specialCollisionComponent.GetContactHeight();
503
504 signalsMgr.SetSignalValue(heightSignalId, height);
505 }
506
507 //------------------------------------------------------------------------------------------------
512 void SetSpeedLimit(Managed source, float limit)
513 {
514 m_mSpeedReferences.Set(source, limit);
515
516 float speedLimit = 1; // base speed of the player
517 float tempLimit;
518
519 for (int idx = m_mSpeedReferences.Count() - 1; idx >= 0; idx--)
520 {
521 if (!m_mSpeedReferences.GetKey(idx)) // check if source still exists
522 {
523 m_mSpeedReferences.RemoveElement(idx);
524 continue;
525 }
526
527 tempLimit = m_mSpeedReferences.GetElement(idx);
528
529 if (m_mSpeedReferences.GetElement(idx) == 1)
530 {
531 m_mSpeedReferences.RemoveElement(idx);
532 continue;
533 }
534
535 if (tempLimit < speedLimit)
536 speedLimit = tempLimit;
537 }
538
539 m_fTargetSpeed = speedLimit;
540
541 World world = GetGame().GetWorld();
543
544 if (m_fTargetSpeed < m_fCurrentSpeed) // speed decrease is more gradual but speed increase is instant
545 {
546 if (characterSlowdownSystem)
547 characterSlowdownSystem.Register(this);
548 }
549 else
550 {
551 if (characterSlowdownSystem)
552 characterSlowdownSystem.Unregister(this); // SlowdownSystem checks if it contains this class first
553 // we unregister for extra insurance nothing goes wrong
554 OverrideSpeed(speedLimit);
555 }
556 }
557
558 //------------------------------------------------------------------------------------------------
561 void UpdateSlowdown(float transitionTime)
562 {
563 float newSpeed = Math.Lerp(m_fCurrentSpeed, m_fTargetSpeed, transitionTime);
564
565 if (Math.AbsFloat(newSpeed - m_fTargetSpeed) < 0.01)
566 {
567 newSpeed = m_fTargetSpeed;
568 World world = GetGame().GetWorld();
570 if (s_System)
571 s_System.Unregister(this);
572 }
573
574 OverrideSpeed(newSpeed);
575 }
576
577 //------------------------------------------------------------------------------------------------
578 protected void OverrideSpeed(float speed)
579 {
580 m_fCurrentSpeed = speed;
581 GetCharacterController().OverrideMaxSpeed(speed);
582 }
583}
ArmaReforgerScripted GetGame()
Definition game.c:1398
SCR_CharacterControllerComponent GetCharacterController()
SCR_CacheNoteComponentClass ScriptComponentClass RplProp()] protected ref array< string > m_aLines
SCR_CampaignFaction GetFaction()
ref map< Managed, float > m_mSpeedReferences
void UpdateSlowdown(float transitionTime)
void RemoveOldContact(IEntity oldContact=null)
FactionAffiliationComponent m_pFactionComponent
override void OnSpecialContactsChagned(notnull array< IEntity > contacts)
This is called locally by the owner of the character.
SCR_ChimeraCharacterClass ChimeraCharacterClass NonSerialized()] float m_fFaceAlphaTest=0
void CalculateAndSetSlowdown(float bushModdedHeight)
void SetNewZoomLevel(int zoomLevel, bool increased, RplId rplId)
float m_fTargetSpeed
void SetSpeedLimit(Managed source, float limit)
void RPC_SetNewZoomLevel_BC(int zoomLevel, bool increased, RplId rplId)
Using RPC here because it is only for sound, so we don't care when weapon is streamed in.
void OverrideSpeed(float speed)
bool m_bRecruitable
void RPC_SetIllumination_BC(bool state, RplId rplId)
Using RPC here because it is only for sound, so we don't care when weapon is streamed in.
void SetIllumination(bool illuminated, RplId rplId)
float m_fCurrentSpeed
bool IsRecruited()
bool IsRecruitable()
void AddNewContact(notnull IEntity newContact)
float GetModifiedBushHeight(float foliageHeight, ETreeSoundTypes treeType=ETreeSoundTypes.Bush)
void SetRecruited(bool recruited)
SCR_CharacterPerceivableComponent m_pPerceivableComponent
void RPC_SetIllumination_S(bool state, RplId rplId)
bool IsDriving(float minSpeedSq=-1)
bool m_bIsRecruited
ref array< IEntity > m_aContacts
void Rpc_ContactChanged(RplId changedEntityRplId, bool wasAdded)
void SetRecruitable(bool isRecruitable)
void RPC_SetNewZoomLevel_S(int zoomLevel, bool increased, RplId rplId)
Get all prefabs that have the spawner data
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
FactionKey GetFactionKey()
SCR_VehicleDamageManagerComponentClass GetPrefabData()
SCR_VehicleDamageManagerComponent GetDamageManager()
Definition Math.c:22
proto external Managed FindComponent(typename typeName)
proto external EntityPrefabData GetPrefabData()
Definition Math.c:13
Main replication API.
Definition Replication.c:14
Object holding reference to resource. In destructor release the resource.
Definition Resource.c:25
Replication item identifier.
Definition RplId.c:14
Config file to keep track of the different foliage types and the weight of the slowdown effect.
float GetHeightSlowEffectModifier(ETreeSoundTypes treeType)
Get the weight of the slowdown effect of the given tree type.
void AddSpecialContactEffect(notnull SCR_SpecialCollisionDamageEffect effect)
A system to help with easing the slowdown effect applied to the character.
void Register(notnull SCR_ChimeraCharacter character)
void Unregister(notnull SCR_ChimeraCharacter character)
SCR_BushTypeSlowConfig GetBushSlowTypeCfg()
static ref SCR_BushTypeSlowConfig s_BushSlowTypeCfg
static RplComponent GetEntityRplComponent(notnull IEntity entity)
Definition Tree.c:11
Definition World.c:16
Definition Types.c:486
enum EPhysicsLayerPresets Vehicle
Definition gameLib.c:24
override void EOnInit(IEntity owner)
SCR_FieldOfViewSettings Attribute
RplComponent GetRplComponent()
Returns the replication component associated to this entity.
ECurveType
Definition ECurveType.c:13
RplRole
Role of replicated node (and all items in it) within the replication system.
Definition RplRole.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
ETreeSoundTypes