Dayz Explorer 1.29.162510
Loading...
Searching...
No Matches
staminahandler.c
Go to the documentation of this file.
10
11
12/**@class Stamina Consumer
13 * @brief Holds information about Stamina Consumer
14 *
15 * @param[in] threshold value needed to allow consume stamina
16 * @param[in] state keeps state of the consumer non-depleted/depleted
17 */
19{
20 protected float m_ActivationThreshold;
21 protected float m_DrainThreshold
22 protected bool m_State;
23
24 void StaminaConsumer(float threshold, float threshold2, bool state)
25 {
26 m_ActivationThreshold = threshold; //can be activated if above this threshold
27 m_DrainThreshold = threshold2; //can continually drain until it reaches this threshold
28 m_State = state;
29 }
30
31 bool GetState() { return m_State; }
32 void SetState(bool state) { m_State = state; }
33
35 void SetActivationThreshold(float threshold) { m_ActivationThreshold = threshold; }
36
37 float GetDrainThreshold() { return m_DrainThreshold; }
38 void SetDrainThreshold(float threshold) { m_DrainThreshold = threshold; }
39}
40
42{
44
49
50 void RegisterConsumer(EStaminaConsumers consumer, float threshold, float depletion_threshold = -1)
51 {
52 if (depletion_threshold == -1)
53 {
54 depletion_threshold = threshold;
55 }
56
57 if ( !m_StaminaConsumers.Contains(consumer) )
58 {
60 StaminaConsumer sc = new StaminaConsumer(threshold, depletion_threshold, true);
61 m_StaminaConsumers.Set(consumer, sc);
62 }
63 }
64
65 bool HasEnoughStaminaFor(EStaminaConsumers consumer, float curStamina, bool isDepleted, float cap)
66 {
68 if (m_StaminaConsumers && m_StaminaConsumers.Find(consumer, sc))
69 {
70 if (consumer != EStaminaConsumers.SPRINT)
71 {
72 if (isDepleted || (curStamina < sc.GetDrainThreshold()))
73 {
74 sc.SetState(false);
75 return false;
76 }
77 }
78 else
79 {
80 if (!isDepleted)
81 {
82 if (sc.GetState())
83 {
84 sc.SetState(true);
85 return true;
86 }
87 }
88 else
89 {
90 sc.SetState(false);
91 return false;
92 }
93 }
94
95 if (curStamina > sc.GetDrainThreshold() || curStamina == cap) //Sometimes player can't go up to drain threshold
96 {
97 sc.SetState(true);
98 return true;
99 }
100 }
101
102 return false;
103 }
104
105 bool HasEnoughStaminaToStart(EStaminaConsumers consumer, float curStamina, bool isDepleted, float cap)
106 {
108 if (m_StaminaConsumers && m_StaminaConsumers.Find(consumer, sc))
109 {
110 if ((isDepleted || (curStamina < sc.GetActivationThreshold() && curStamina < cap)))
111 {
112 sc.SetState(false);
113 return false;
114 }
115 else
116 {
117 sc.SetState(true);
118 return true;
119 }
120 }
121
122 return false;
123 }
124}
125
126
135class StaminaModifier
136{
137 bool m_InUse = false;
140
141 void StaminaModifier(int type, float min, float max, float cooldown, float startTime = 0, float duration = 0)
142 {
143 m_Type = type;
144 m_MinValue = min;
145 m_MaxValue = max;
146 m_Cooldown = cooldown;
147 m_StartTimeAdjustment = startTime;
148 m_Duration = duration;
149 m_Tick = 1;
150 }
151
152 int GetType() { return m_Type; }
153
154 float GetMinValue() { return m_MinValue; }
155 void SetMinValue(float val) { m_MinValue = val; }
156
157 float GetMaxValue() { return m_MaxValue; }
158 void SetMaxValue(float val) { m_MaxValue = val; }
159
160 float GetCooldown() { return m_Cooldown; }
161 void SetCooldown(float val) { m_Cooldown = val; }
162
163 float GetStartTime() { return m_StartTime; } //Actual game time (progressive modifiers only)
164 void SetStartTime(float val) { m_StartTime = val; }
165
166 float GetStartTimeAdjustment() {return m_StartTimeAdjustment;} //adjustment to current time (progressive modifiers only)
167
168 float GetDuration() { return m_Duration; }
170
171 bool IsInUse() { return m_InUse; }
172 void SetInUse(bool val) { m_InUse = val; }
173
174 float GetRunTime() { return m_ProgressTime; }
175 void AddRunTime(float val) { m_ProgressTime += val; }
176 void SetRunTimeTick(float val) { m_Tick = val; }
178}
179
181{
182 protected ref SMDataExponential m_SMDataEx;
183
184 float GetBaseValue() { return m_SMDataEx.m_BaseValue; }
185 float GetExponent() { return m_SMDataEx.m_Exponent; }
186 float GetMultiplier() { return m_SMDataEx.m_Multiplier; }
187 override float GetCooldown() { return m_SMDataEx.m_Cooldown; }
188 override float GetStartTimeAdjustment() { return m_SMDataEx.m_StartTimeAdjustment; }
189 override float GetDuration() { return m_SMDataEx.m_Duration; }
190 override float GetDurationAdjusted() { return m_SMDataEx.m_Duration / m_Tick; }
191
192 void SetData(SMDataExponential data) { m_SMDataEx = data; }
193}
194
196{
197 const int FIXED = 0;
198 const int RANDOMIZED = 1;
199 const int LINEAR = 2; //Useful ONLY for regular, over-time stamina drain
200 const int EXPONENTIAL = 3; //Useful ONLY for regular, over-time stamina drain
201
203
208
210 void RegisterFixed(EStaminaModifiers modifier, float value, float cooldown = GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION)
211 {
212 if ( !m_StaminaModifiers.Contains(modifier) )
213 {
215 StaminaModifier sm = new StaminaModifier(FIXED, -1, value, cooldown);
216 m_StaminaModifiers.Set(modifier, sm);
217 }
218 }
219
221 void RegisterRandomized(EStaminaModifiers modifier, float minValue, float maxValue, float cooldown = GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION)
222 {
223 if ( !m_StaminaModifiers.Contains(modifier) )
224 {
226 StaminaModifier sm = new StaminaModifier(RANDOMIZED, minValue, maxValue, cooldown);
227 m_StaminaModifiers.Set(modifier, sm);
228 }
229 }
230
232 void RegisterLinear(EStaminaModifiers modifier, float startValue, float endValue, float startTime, float duration, float cooldown = GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION)
233 {
234 StaminaModifier sm = new StaminaModifier(LINEAR, startValue, endValue, cooldown, startTime, duration);
235 m_StaminaModifiers.Set(modifier, sm);
236 }
237
239 void RegisterExponential(EStaminaModifiers modifier, float startValue, float exponent, float startTime, float duration, float cooldown = GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION)
240 {
241 StaminaModifier sm = new StaminaModifier(EXPONENTIAL, startValue, exponent, cooldown, startTime, duration);
242 m_StaminaModifiers.Set(modifier, sm);
243 }
244
246 void RegisterExponentialEx(EStaminaModifiers modifier, SMDataExponential data)
247 {
248 StaminaModifierExponential smex = new StaminaModifierExponential(EXPONENTIAL, data.m_BaseValue, data.m_Exponent, data.m_Cooldown, data.m_StartTimeAdjustment, data.m_Duration);
249 smex.SetData(data);
250 m_StaminaModifiers.Set(modifier, smex);
251 }
252
254 {
255 return m_StaminaModifiers.Get(modifier);
256 }
257}
258
259typedef Param1<float> StaminaCooldownParams;
260
262{
263 protected const float STAMINA_GAIN_THRESHOLD = 25.0;
264 protected const float STAMINA_GAIN_MODIFIER = 10.0;
265
266 protected bool m_InitUpdate;
267 protected float m_PlayerLoad;
268 protected float m_StaminaDelta;
269 protected float m_Stamina;
270 protected float m_StaminaSynced; //guaranteed to be identical on server and client
271 protected float m_StaminaCap;
272 protected float m_StaminaCapSynced; //guaranteed to be identical on server and client
273 protected float m_StaminaDepletionMultiplierNext; // value being sent via SJ
274 protected float m_StaminaRecoveryMultiplierNext; // value being sent via SJ
275 protected float m_StaminaDepletion;
276 protected float m_StaminaDepletionMultiplier; //controls depletion rate
277 protected float m_StaminaRecoveryMultiplier; //controls recovery rate
278 protected float m_Time;
280 protected ref HumanMovementState m_State;
283
284 protected bool m_StaminaDepleted;
285
287 ref set<EStaminaMultiplierTypes> m_ActiveDepletionModifiers;
288
290 ref set<EStaminaMultiplierTypes> m_ActiveRecoveryModifiers;
291
292 protected bool m_IsInCooldown;
293
296
297 protected float m_LastPlayerLoad = -1;
298
301
303
304 // Movement state caching members
305 protected int m_LastCommandTypeId = -1;
306 protected int m_LastMovementIdx = -1;
307 protected int m_LastStanceIdx = -1;
308 protected bool m_MovementStateChanged = true; // Force initial processing
309
310 #ifdef DIAG_DEVELOPER
311 protected bool m_StaminaDisabled;
312 protected float m_DebugTimer = 0;
313 protected int m_LastPoolInUse = 0;
314 #endif
315
317 {
318 if (g_Game.IsServer() || !g_Game.IsMultiplayer())
319 m_StaminaParams = new Param3<float,float,bool>(0, 0, false);
320
321 m_State = new HumanMovementState();
322 m_Player = player;
323
324 m_InitUpdate = false;
325 m_Stamina = CfgGameplayHandler.GetStaminaMax();
326 m_StaminaSynced = CfgGameplayHandler.GetStaminaMax();
327 m_StaminaCap = CfgGameplayHandler.GetStaminaMax();
328 m_StaminaCapSynced = CfgGameplayHandler.GetStaminaMax();
334 m_Time = 0;
335 m_StaminaDepleted = false;
336 m_IsInCooldown = false;
337 m_HumanMoveSettings = m_Player.GetDayZPlayerType().CommandMoveSettingsW();
339
342
344
345 //----------------- depletion --------------------
347 m_ActiveDepletionModifiers = new set<EStaminaMultiplierTypes>;
348
349 //----------------- recovery --------------------
351 m_ActiveRecoveryModifiers = new set<EStaminaMultiplierTypes>;
352
353 Init();
354 }
355
357 {
358 if (m_CooldownMap)
359 {
360 m_CooldownMap.Clear();
361 }
362 }
363
364 void Init()
365 {
366 //----------------- depletion --------------------
367 m_RegisteredDepletionModifiers.Insert(EStaminaMultiplierTypes.MASK, MaskMdfr.STAMINA_DEPLETION_MODIFIER);
368 m_RegisteredDepletionModifiers.Insert(EStaminaMultiplierTypes.FATIGUE, FatigueMdfr.STAMINA_DEPLETION_MULTIPLIER);
369 m_RegisteredDepletionModifiers.Insert(EStaminaMultiplierTypes.EPINEPHRINE, EpinephrineMdfr.STAMINA_DEPLETION_MULTIPLIER);
370 m_RegisteredDepletionModifiers.Insert(EStaminaMultiplierTypes.VOMIT_EXHAUSTION, VomitSymptom.STAMINA_DEPLETION_MULTIPLIER);
371 m_RegisteredDepletionModifiers.Insert(EStaminaMultiplierTypes.DISEASE_PNEUMONIA, PneumoniaMdfr.STAMINA_DEPLETION_MULTIPLIER);
372
373 //----------------- recovery --------------------
374 m_RegisteredRecoveryModifiers.Insert(EStaminaMultiplierTypes.MASK, MaskMdfr.STAMINA_RECOVERY_MODIFIER);
375 m_RegisteredRecoveryModifiers.Insert(EStaminaMultiplierTypes.FATIGUE, FatigueMdfr.STAMINA_RECOVERY_MULTIPLIER);
376 m_RegisteredRecoveryModifiers.Insert(EStaminaMultiplierTypes.DROWNING, DrowningMdfr.STAMINA_RECOVERY_MULTIPLIER);
377 m_RegisteredRecoveryModifiers.Insert(EStaminaMultiplierTypes.VOMIT_EXHAUSTION, VomitSymptom.STAMINA_RECOVERY_MULTIPLIER);
378 m_RegisteredRecoveryModifiers.Insert(EStaminaMultiplierTypes.DISEASE_PNEUMONIA, PneumoniaMdfr.STAMINA_RECOVERY_MULTIPLIER);
379 }
380
382 {
383 if (m_RegisteredDepletionModifiers.Contains(type))
384 {
385 m_ActiveDepletionModifiers.Insert(type);
387 }
388 else
389 {
390 Error("attempting to activate unregistered depletion modifier");
391 }
392 }
393
395 {
396 int index = m_ActiveDepletionModifiers.Find(type);
397 if (index != -1)
398 {
399 m_ActiveDepletionModifiers.Remove(index);
401 }
402 }
403
405 {
406 float value = 1;
407
408 foreach (int multiplier: m_ActiveDepletionModifiers)
409 {
410 value *= m_RegisteredDepletionModifiers.Get(multiplier);
411 }
412
413 if (value != m_StaminaDepletionMultiplier)
415 }
416
418 {
419 if (m_RegisteredRecoveryModifiers.Contains(type))
420 {
421 m_ActiveRecoveryModifiers.Insert(type);
423 }
424 else
425 {
426 Error("attempting to activate unregistered recovery modifier");
427 }
428 }
429
431 {
432 int index = m_ActiveRecoveryModifiers.Find(type);
433 if (index != -1)
434 {
435 m_ActiveRecoveryModifiers.Remove(index);
437 }
438 }
439
441 {
442 float value = 1;
443
444 foreach (int multiplier: m_ActiveRecoveryModifiers)
445 {
446 value *= m_RegisteredRecoveryModifiers.Get(multiplier);
447 }
448
449 if (value != m_StaminaRecoveryMultiplier)
450 {
452 }
453 }
454
455 // Check if movement state has changed since last frame
456 protected bool HasMovementStateChanged()
457 {
458 // Only call GetMovementState if we need to check for changes
459 m_Player.GetMovementState(m_State);
460
461 bool changed = (m_State.m_CommandTypeId != m_LastCommandTypeId || m_State.m_iMovement != m_LastMovementIdx || m_State.m_iStanceIdx != m_LastStanceIdx);
462
463 if (changed)
464 {
465 // Update cached values
466 m_LastCommandTypeId = m_State.m_CommandTypeId;
467 m_LastMovementIdx = m_State.m_iMovement;
468 m_LastStanceIdx = m_State.m_iStanceIdx;
469 }
470
471 return changed;
472 }
473
474 void Update(float deltaT, int pCurrentCommandID)
475 {
476 #ifdef DIAG_DEVELOPER
477 if (m_StaminaDisabled)
478 return;
479 #endif
480
481 if (!m_Player)
482 return;
483
484 // Process cooldowns - subtract deltaT and remove expired ones
485 array<int> expiredCooldowns = new array<int>();
486 foreach (int modifier, StaminaCooldownParams cooldownParams : m_CooldownMap)
487 {
488 cooldownParams.param1 -= deltaT;
489 if (cooldownParams.param1 <= 0)
490 {
491 expiredCooldowns.Insert(modifier);
492 }
493 }
494
495 // Remove expired cooldowns
496 foreach (int expiredModifier : expiredCooldowns)
497 {
498 ResetCooldown(expiredModifier);
499 }
500
501 // Reset so we get current bonus value once in this update loop and then reuse the cached value within this update call
503
504 // Check if movement state has changed
506
507 bool isAiOrSingleplayer = m_Player.IsAuthorityOwner();
508 bool isServerOrSingleplayer = m_Player.IsAuthority();
509
510 // Calculates actual max stamina based on player's load
511 if (isServerOrSingleplayer)
512 {
514 m_PlayerLoad = m_Player.GetWeightEx();
516 {
519 }
520 }
521 else
522 {
523 PlayerBaseMove move = PlayerBaseMove.Cast(m_Player.GetNextMove());
524 if (move)
525 {
526 move.m_fStaminaValue = m_Stamina;
527 move.m_fStaminaCapacity = m_StaminaCap;
528 }
529 }
530
531 if (isAiOrSingleplayer)
532 {
535 }
536
537 // Process movement if: state changed, we have stamina delta, in cooldown, not initialized, or stamina is bewlow cap
540
541 // Sets current stamina & stores + syncs data with client
542 ProcessStaminaChanges(deltaT, isServerOrSingleplayer);
543
546
547 m_StaminaDelta = 0;
548 m_StaminaDepletion = 0; // resets depletion modifier
550 if (!m_InitUpdate)
551 m_InitUpdate = true;
552 }
553
554 protected void ProcessMovementState()
555 {
556 switch (m_State.m_CommandTypeId)
557 {
558 case DayZPlayerConstants.COMMANDID_MOVE:
560 break;
561 case DayZPlayerConstants.COMMANDID_LADDER:
563 break;
564 case DayZPlayerConstants.COMMANDID_SWIM:
566 break;
567 case DayZPlayerConstants.COMMANDID_FALL:
568 case DayZPlayerConstants.COMMANDID_MELEE2:
569 case DayZPlayerConstants.COMMANDID_CLIMB:
570 break;
571 default:
572 if (!m_IsInCooldown)
573 {
574 m_StaminaDelta = GameConstants.STAMINA_GAIN_IDLE_PER_SEC;
575 }
576 break;
577 }
578 }
579
580 protected void ProcessStaminaChanges(float deltaT, bool isServerOrSingleplayer)
581 {
582 // Calculate stamina changes
583 float temp = m_StaminaDelta * deltaT;
584 if (temp < 0)
585 {
587 }
588 else
589 {
591 }
592
593 // Apply stamina depletion first, then add/subtract the delta
594 float newStamina = m_Stamina - m_StaminaDepletion + temp;
595
596 // Clamp to valid range
597 m_Stamina = Math.Max(0, Math.Min(newStamina, m_StaminaCap));
598
599 // Handle floating-point precision issues - snap to cap if very close
600 if (m_Stamina > (m_StaminaCap - 0.01) && temp > 0)
601 {
603 }
604
605 if (isServerOrSingleplayer)
606 {
607 m_Player.GetStatStamina().Set(m_Stamina);
608 m_Time += deltaT;
609
610 if (m_Time >= GameConstants.STAMINA_SYNC_RATE)
611 {
612 m_Time = 0;
614 }
615 }
616
617 #ifndef SERVER
619 #endif
620 }
621
623 {
625 if (m_PlayerLoad >= CfgGameplayHandler.GetStaminaWeightLimitThreshold())
626 {
627 m_StaminaCap = Math.Max((CfgGameplayHandler.GetStaminaMax() - (((m_PlayerLoad - CfgGameplayHandler.GetStaminaWeightLimitThreshold())/GameConstants.STAMINA_KG_TO_GRAMS) * CfgGameplayHandler.GetStaminaKgToStaminaPercentPenalty())), CfgGameplayHandler.GetStaminaMinCap());
628 }
629 else
630 {
631 m_StaminaCap = CfgGameplayHandler.GetStaminaMax();
632 }
633
635 }
636
638 void OnSyncJuncture(int pJunctureID, ParamsReadContext pCtx)
639 {
640 switch (pJunctureID)
641 {
642 case DayZPlayerSyncJunctures.SJ_STAMINA:
643 float stamina;
644 float staminaCap;
645 bool cooldown;
646
647 if (!pCtx.Read(stamina) || !pCtx.Read(staminaCap) || !pCtx.Read(cooldown))
648 {
649 return;
650 }
651
652 m_Stamina = stamina; //?
653 m_StaminaSynced = stamina;
654 m_StaminaCap = staminaCap;
655 m_StaminaCapSynced = staminaCap;
656
657 if (m_Player.GetInstanceType() != DayZPlayerInstanceType.INSTANCETYPE_CLIENT)
658 {
659 return;
660 }
661
662 if (staminaCap != m_StaminaCap)
663 {
664 m_StaminaCap = staminaCap;
665 }
666
667 m_IsInCooldown = cooldown;
668 m_Player.SetStamina(m_Stamina, m_StaminaCap);
669 break;
670
671 case DayZPlayerSyncJunctures.SJ_STAMINA_MISC:
673 break;
674 }
675 }
676
677 protected void StaminaProcessor_Move(HumanMovementState pHumanMovementState)
678 {
679 switch (pHumanMovementState.m_iMovement)
680 {
681 case DayZPlayerConstants.MOVEMENTIDX_SPRINT: //sprint
682 if (pHumanMovementState.m_iStanceIdx == DayZPlayerConstants.STANCEIDX_ERECT)
683 {
684 m_StaminaDelta = -GameConstants.STAMINA_DRAIN_STANDING_SPRINT_PER_SEC * CfgGameplayHandler.GetSprintStaminaModifierErc();
685 SetCooldown(GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION);
686 break;
687 }
688 else if ( pHumanMovementState.m_iStanceIdx == DayZPlayerConstants.STANCEIDX_CROUCH)
689 {
690 m_StaminaDelta = -GameConstants.STAMINA_DRAIN_CROUCHED_SPRINT_PER_SEC * CfgGameplayHandler.GetSprintStaminaModifierCro();
691 SetCooldown(GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION);
692 break;
693 }
694
695 m_StaminaDelta = GameConstants.STAMINA_GAIN_JOG_PER_SEC;
696 break;
697
698 case DayZPlayerConstants.MOVEMENTIDX_RUN: //jog
699 if (m_Player.GetCurrentWaterLevel() >= m_HumanMoveSettings.m_fWaterLevelSpeedRectrictionHigh)
700 {
701 m_StaminaDelta = -GameConstants.STAMINA_DRAIN_STANDING_SPRINT_PER_SEC * CfgGameplayHandler.GetSprintStaminaModifierErc();
702 break;
703 }
704
705 if (!m_IsInCooldown)
706 {
707 m_StaminaDelta = (GameConstants.STAMINA_GAIN_JOG_PER_SEC + CalcStaminaGainBonus());
708 }
709 break;
710
711 case DayZPlayerConstants.MOVEMENTIDX_WALK: //walk
712 if (!m_IsInCooldown)
713 {
714 m_StaminaDelta = (GameConstants.STAMINA_GAIN_WALK_PER_SEC + CalcStaminaGainBonus());
715 }
716 break;
717
718 case DayZPlayerConstants.MOVEMENTIDX_IDLE: //idle
719 if (m_Player.IsRolling())
720 {
721 m_StaminaDelta = GameConstants.STAMINA_GAIN_ROLL_PER_SEC;
722 break;
723 }
724
725 if (!m_IsInCooldown)
726 {
727 m_StaminaDelta = (GameConstants.STAMINA_GAIN_IDLE_PER_SEC + CalcStaminaGainBonus());
728 }
729 break;
730
731 default:
732 if (!m_IsInCooldown)
733 {
734 m_StaminaDelta = GameConstants.STAMINA_GAIN_IDLE_PER_SEC;
735 }
736 break;
737 }
738 }
739
740 protected void StaminaProcessor_Ladder(HumanMovementState pHumanMovementState)
741 {
742 switch (pHumanMovementState.m_iMovement)
743 {
744 case 2: //climb up (fast)
745 m_StaminaDelta = -GameConstants.STAMINA_DRAIN_LADDER_FAST_PER_SEC * CfgGameplayHandler.GetSprintLadderStaminaModifier();
746 SetCooldown(GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION);
747 break;
748
749 case 1: //climb up (slow)
750 if (!m_IsInCooldown)
751 {
752 m_StaminaDelta = (GameConstants.STAMINA_GAIN_LADDER_PER_SEC + CalcStaminaGainBonus());
753 }
754 break;
755
756 default:
757 if (!m_IsInCooldown)
758 {
759 m_StaminaDelta = GameConstants.STAMINA_GAIN_IDLE_PER_SEC + CalcStaminaGainBonus();
760 }
761 break;
762 }
763 }
764
765 protected void StaminaProcessor_Swimming(HumanMovementState pHumanMovementState)
766 {
767 switch (pHumanMovementState.m_iMovement)
768 {
769 case 3: //swim fast
770 m_StaminaDelta = -GameConstants.STAMINA_DRAIN_SWIM_FAST_PER_SEC * CfgGameplayHandler.GetSprintSwimmingStaminaModifier();
771 SetCooldown(GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION);
772 break;
773
774 case 2: //swim slow
775 if (!m_IsInCooldown)
776 {
777 m_StaminaDelta = (GameConstants.STAMINA_GAIN_SWIM_PER_SEC + CalcStaminaGainBonus());
778 }
779 break;
780
781 default:
782 if (!m_IsInCooldown)
783 {
784 m_StaminaDelta = GameConstants.STAMINA_GAIN_IDLE_PER_SEC + CalcStaminaGainBonus();
785 }
786 break;
787 }
788 }
789
791 protected void SyncStaminaEx()
792 {
794 }
795
797 protected void SyncStamina(float stamina, float stamina_cap, bool cooldown)
798 {
799 m_Player.GetStatStamina().Set(stamina);
801 pCtx.Write(stamina);
802 pCtx.Write(stamina_cap);
803 pCtx.Write(cooldown);
804 m_Player.SendSyncJuncture(DayZPlayerSyncJunctures.SJ_STAMINA,pCtx);
805 }
806
809 {
811
813 pCtx.Write(p.param1);
814 pCtx.Write(p.param2);
815 m_Player.SendSyncJuncture(DayZPlayerSyncJunctures.SJ_STAMINA_MISC,pCtx);
816 }
817
820 {
821 float depletionMultiplier;
822 float recoveryMultiplier;
823 if (!pCtx.Read(depletionMultiplier) || !pCtx.Read(recoveryMultiplier))
824 {
825 return;
826 }
827
828 m_StaminaDepletionMultiplier = depletionMultiplier;
829 m_StaminaRecoveryMultiplier = recoveryMultiplier;
830 }
831
833 {
835
836 m_StaminaConsumers.RegisterConsumer(
837 EStaminaConsumers.HOLD_BREATH,
838 GameConstants.STAMINA_HOLD_BREATH_THRESHOLD_ACTIVATE,
839 GameConstants.STAMINA_HOLD_BREATH_THRESHOLD_DRAIN,
840 );
841 m_StaminaConsumers.RegisterConsumer(
842 EStaminaConsumers.SPRINT,
843 CfgGameplayHandler.GetStaminaMinCap() + 15,
844 );
845 m_StaminaConsumers.RegisterConsumer(
846 EStaminaConsumers.JUMP,
847 GameConstants.STAMINA_JUMP_THRESHOLD,
848 );
849 m_StaminaConsumers.RegisterConsumer(
850 EStaminaConsumers.VAULT,
851 GameConstants.STAMINA_VAULT_THRESHOLD,
852 );
853 m_StaminaConsumers.RegisterConsumer(
854 EStaminaConsumers.CLIMB,
855 GameConstants.STAMINA_CLIMB_THRESHOLD,
856 );
857 m_StaminaConsumers.RegisterConsumer(
858 EStaminaConsumers.MELEE_HEAVY,
859 GameConstants.STAMINA_MELEE_HEAVY_THRESHOLD,
860 );
861 m_StaminaConsumers.RegisterConsumer(
862 EStaminaConsumers.MELEE_EVADE,
863 GameConstants.STAMINA_MELEE_EVADE_THRESHOLD,
864 );
865 m_StaminaConsumers.RegisterConsumer(
867 GameConstants.STAMINA_ROLL_THRESHOLD,
868 );
869 m_StaminaConsumers.RegisterConsumer(
870 EStaminaConsumers.DROWN,
871 0,
872 );
873 m_StaminaConsumers.RegisterConsumer(
875 0,
876 );
877 }
878
880 {
882
884 m_StaminaModifiers.RegisterExponentialEx(
885 EStaminaModifiers.HOLD_BREATH,
886 data,
887 );
888 m_StaminaModifiers.RegisterExponentialEx(
889 EStaminaModifiers.PUSH_CAR,
890 data,
891 );
892 m_StaminaModifiers.RegisterFixed(
893 EStaminaModifiers.DROWN,
894 10,
895 );
896 m_StaminaModifiers.RegisterFixed(
898 GameConstants.STAMINA_DRAIN_JUMP * CfgGameplayHandler.GetObstacleTraversalStaminaModifier(),
899 );
900 m_StaminaModifiers.RegisterFixed(
901 EStaminaModifiers.VAULT,
902 GameConstants.STAMINA_DRAIN_VAULT * CfgGameplayHandler.GetObstacleTraversalStaminaModifier(),
903 );
904 m_StaminaModifiers.RegisterFixed(
905 EStaminaModifiers.CLIMB,
906 GameConstants.STAMINA_DRAIN_CLIMB * CfgGameplayHandler.GetObstacleTraversalStaminaModifier(),
907 );
908 m_StaminaModifiers.RegisterFixed(
909 EStaminaModifiers.MELEE_LIGHT,
910 GameConstants.STAMINA_DRAIN_MELEE_LIGHT * CfgGameplayHandler.GetMeleeStaminaModifier(),
911 );
912 m_StaminaModifiers.RegisterFixed(
913 EStaminaModifiers.MELEE_HEAVY,
914 GameConstants.STAMINA_DRAIN_MELEE_HEAVY * CfgGameplayHandler.GetMeleeStaminaModifier(),
915 );
916 m_StaminaModifiers.RegisterFixed(
917 EStaminaModifiers.OVERALL_DRAIN,
918 CfgGameplayHandler.GetStaminaMax(),
919 5.0,
920 );
921 m_StaminaModifiers.RegisterRandomized(
922 EStaminaModifiers.MELEE_EVADE, 3 * CfgGameplayHandler.GetMeleeStaminaModifier(),
923 GameConstants.STAMINA_DRAIN_MELEE_EVADE * CfgGameplayHandler.GetMeleeStaminaModifier(),
924 );
925 m_StaminaModifiers.RegisterFixed(
927 GameConstants.STAMINA_DRAIN_ROLL,
928 );
929 }
930
932 protected float CalcStaminaGainBonus()
933 {
936
937 if (m_StaminaDepletion > 0)
938 {
940 }
942 {
944 }
945 else
946 {
947 m_CachedStaminaGainBonus = GameConstants.STAMINA_GAIN_BONUS_CAP;
948 }
949
952 }
953
954 protected void ApplyExhaustion()
955 {
957 HumanCommandAdditives ad = m_Player.GetCommandModifier_Additives();
958
959 float exhaustion_value = 1;
960 if (m_StaminaCap != 0)
961 {
962 exhaustion_value = 1 - ((m_Stamina / (m_StaminaCap * 0.01)) * 0.01);
963 }
964
965 exhaustion_value = Math.Min(1, exhaustion_value);
966 if (ad)
967 {
968 // do not apply exhaustion on local client if player is in ADS/Optics (camera shakes)
969 if (m_Player.GetInstanceType() == DayZPlayerInstanceType.INSTANCETYPE_CLIENT && (m_Player.IsInOptics() || m_Player.IsInIronsights()))
970 {
971 ad.SetExhaustion(0, true);
972 }
973 else
974 {
975 ad.SetExhaustion(exhaustion_value, true);
976 }
977 }
978 }
979
981 protected void CheckStaminaState()
982 {
983 if (m_Stamina <= 0)
984 {
985 m_StaminaDepleted = true;
987 if (!m_IsInCooldown)
988 {
989 // set this only once
990 SetCooldown(GameConstants.STAMINA_REGEN_COOLDOWN_EXHAUSTION);
991 }
992 }
993 else
994 {
995 m_StaminaDepleted = false;
996 }
997 }
998
1000 protected void SetCooldown(float time, int modifier = -1)
1001 {
1002 StaminaCooldownParams cooldown;
1003 if (!m_CooldownMap.Find(modifier, cooldown))
1004 {
1005 cooldown = new StaminaCooldownParams(0);
1006 m_CooldownMap.Insert(modifier, cooldown);
1007 }
1008
1009 m_IsInCooldown = true;
1010 cooldown.param1 = time; // Set remaining time
1011 }
1012
1013 protected void ResetCooldown(int modifier = -1)
1014 {
1015 StaminaModifier sm = m_StaminaModifiers.GetModifierData(modifier);
1016 if (sm)
1017 {
1018 sm.SetStartTime(-1);
1019 sm.ResetRunTime();
1020 sm.SetInUse(false);
1021 }
1022
1023 // Remove from cooldown map
1024 m_CooldownMap.Remove(modifier);
1025
1026 // Update cooldown state based on remaining active cooldowns
1027 m_IsInCooldown = (m_CooldownMap.Count() > 0);
1028 }
1029
1030 // ---------------------------------------------------
1032 {
1033 return m_StaminaConsumers.HasEnoughStaminaFor(consumer, m_StaminaSynced, m_StaminaDepleted, m_StaminaCapSynced);
1034 }
1035
1037 {
1038 return m_StaminaConsumers.HasEnoughStaminaToStart(consumer, m_StaminaSynced, m_StaminaDepleted, m_StaminaCapSynced);
1039 }
1040
1041 void SetStamina(float stamina_value)
1042 {
1043 m_Stamina = Math.Clamp(stamina_value, 0, CfgGameplayHandler.GetStaminaMax());
1044 SyncStaminaEx();
1045 }
1046
1048 {
1049 return m_Stamina;
1050 }
1051
1053 {
1054 return m_Stamina / GetStaminaMax();
1055 }
1056
1058 {
1059 return m_StaminaSynced;
1060 }
1061
1063 {
1064 return GetSyncedStamina() / GetStaminaMax();
1065 }
1066
1068 {
1069 return m_StaminaCap;
1070 }
1071
1073 {
1074 return m_StaminaCapSynced;
1075 }
1076
1078 {
1079 return CfgGameplayHandler.GetStaminaMax();
1080 }
1081
1082 // Only used internaly in this class, use ActivateDepletionModifier/DeactivateDepletionModifier instead
1090
1091 // Only used internaly in this class, use ActivateRecoveryModifier/DeactivateRecoveryModifier instead
1099
1101 {
1103 }
1104
1106 {
1108 }
1109
1110 void DepleteStaminaEx(EStaminaModifiers modifier, float dT = -1, float coef = 1.0)
1111 {
1112 #ifdef DIAG_DEVELOPER
1113 if (m_StaminaDisabled)
1114 return;
1115 #endif
1116 float val = 0.0;
1117 float current_time = m_Player.GetSimulationTimeStamp();
1118 float valueProgress;
1119 StaminaModifier sm = m_StaminaModifiers.GetModifierData(modifier);
1120
1121 // select by modifier type and drain stamina
1122 switch (sm.GetType())
1123 {
1124 case m_StaminaModifiers.FIXED:
1125 if (dT == -1)
1126 {
1127 dT = 1;
1128 }
1129 m_StaminaDepletion += sm.GetMaxValue() * dT * coef;
1130
1131 break;
1132
1133 case m_StaminaModifiers.RANDOMIZED:
1134 val = Math.RandomFloat(sm.GetMinValue(), sm.GetMaxValue());
1135 m_StaminaDepletion += val * coef;
1136
1137 break;
1138
1139 case m_StaminaModifiers.LINEAR:
1140 if (!sm.IsInUse())
1141 {
1142 sm.SetStartTime(current_time + sm.GetStartTimeAdjustment()/dT);
1143 sm.SetRunTimeTick(dT);
1144 sm.SetInUse(true);
1145 }
1146 valueProgress = Math.Clamp((current_time - sm.GetStartTime())/sm.GetDurationAdjusted(), 0, 1 );
1147 val = Math.Lerp(sm.GetMinValue(), sm.GetMaxValue(), valueProgress);
1148 m_StaminaDepletion += val * coef;
1149
1150 break;
1151
1152 case m_StaminaModifiers.EXPONENTIAL:
1154 if (!Class.CastTo(smex,sm))
1155 {
1156 ErrorEx("StaminaModifierExponential not found for modifier type: " + sm.GetType());
1157 break;
1158 }
1159
1160 if (!smex.IsInUse())
1161 {
1162 smex.SetStartTime(current_time + smex.GetStartTimeAdjustment()/dT);
1163 smex.SetRunTimeTick(dT);
1164 smex.SetInUse(true);
1165 }
1166 valueProgress = Math.Clamp((current_time - smex.GetStartTime())/smex.GetDurationAdjusted(), 0, 1 );
1167 float exp;
1168 if (Math.AbsFloat(smex.GetBaseValue()) < 1)
1169 {
1170 exp = 1 - Math.Lerp(0, smex.GetExponent(), valueProgress);
1171 val = Math.Pow(smex.GetBaseValue(),exp);
1172 }
1173 else
1174 {
1175 exp = Math.Lerp(Math.Min(0, smex.GetExponent()), Math.Max(0, smex.GetExponent()), valueProgress);
1176 val = Math.Pow(smex.GetBaseValue(),exp) + smex.GetBaseValue() - 1;
1177 }
1178
1179 m_StaminaDepletion += val * smex.GetMultiplier() * coef;
1180
1181 break;
1182 }
1183
1185 SetCooldown(sm.GetCooldown(),modifier);
1186
1188 m_StaminaDepletion = Math.Clamp(m_StaminaDepletion, 0, CfgGameplayHandler.GetStaminaMax());
1189 }
1190
1191 // ADD these new methods - don't remove any existing ones
1192 void ObtainState(PlayerBaseOwnerState state)
1193 {
1194 // we are writing the state data for stamina to the move, use 'GetNextMove'
1195 }
1196
1197 void ObtainMove(PlayerBaseMove move)
1198 {
1199 // unused
1200 }
1201
1202 void RewindState(PlayerBaseOwnerState state, PlayerBaseMove move)
1203 {
1204 m_Stamina = move.m_fStaminaValue;
1205 m_StaminaCap = move.m_fStaminaCapacity;
1206 }
1207
1208 void ReplayMove(PlayerBaseMove move)
1209 {
1210 // mimick receiving of sync juncture
1211 if (move.m_bStaminaSynced)
1212 {
1213 m_StaminaSynced = move.m_fStaminaSyncedValue;
1214 m_StaminaCapSynced = move.m_fStaminaSyncedCapacity;
1215
1218 }
1219
1220 m_StaminaDepletion = move.m_fStaminaDepletion;
1221
1222 Update(move.GetTimeSlice(), m_Player.GetCurrentCommandID());
1223 }
1224
1225 #ifdef DIAG_DEVELOPER
1226 void SetStaminaDisabled(bool value)
1227 {
1228 m_StaminaDisabled = value;
1229 }
1230 #endif
1231
1233 //DEPRECATED BELOW
1235 protected bool m_Debug;
1236
1237 [Obsolete("No replacement")]
1238 void DepleteStamina(EStaminaModifiers modifier, float dT = -1)
1239 {
1240 DepleteStaminaEx(modifier,dT);
1241 }
1242
1243 [Obsolete("Deprecated use, StaminaHandler uses SyncJunctures now!")]
1244 void OnRPC(float stamina, float stamina_cap, bool cooldown);
1245}
eBleedingSourceType m_Type
eBleedingSourceType GetType()
float m_Duration
Super root of all classes in Enforce script.
Definition enscript.c:11
Definition mask.c:2
Definition enmath.c:7
Base Param Class with no parameters. Used as general purpose parameter overloaded with Param1 to Para...
Definition param.c:12
void RegisterConsumer(EStaminaConsumers consumer, float threshold, float depletion_threshold=-1)
ref map< EStaminaConsumers, ref StaminaConsumer > m_StaminaConsumers
bool HasEnoughStaminaToStart(EStaminaConsumers consumer, float curStamina, bool isDepleted, float cap)
bool HasEnoughStaminaFor(EStaminaConsumers consumer, float curStamina, bool isDepleted, float cap)
float m_StaminaDepletionMultiplier
void StaminaProcessor_Ladder(HumanMovementState pHumanMovementState)
void RegisterStaminaModifiers()
ref HumanMovementState m_State
void StaminaProcessor_Swimming(HumanMovementState pHumanMovementState)
float GetDepletionMultiplier()
void ReplayMove(PlayerBaseMove move)
void RecalculateRecoveryMultiplier()
void DepleteStamina(EStaminaModifiers modifier, float dT=-1)
float m_StaminaDepletionMultiplierNext
void DepleteStaminaEx(EStaminaModifiers modifier, float dT=-1, float coef=1.0)
void SetDepletionMultiplier(float val)
void SetRecoveryMultiplier(float val)
void RecalculateStaminaCap()
float m_StaminaRecoveryMultiplier
ref set< EStaminaMultiplierTypes > m_ActiveDepletionModifiers
float GetSyncedStaminaCap()
void SyncAdditionalStaminaInfo(Param par)
Method to sync more info for stamina manager. Template parameter means it is very extendable for furt...
ref StaminaModifiers m_StaminaModifiers
void OnSyncJuncture(int pJunctureID, ParamsReadContext pCtx)
called from PlayerBase - syncs stamina values on server with client AND sets the value to match on se...
void CheckStaminaState()
check if the stamina is completely depleted
void DeactivateRecoveryModifier(EStaminaMultiplierTypes type)
void RegisterStaminaConsumers()
float m_StaminaRecoveryMultiplierNext
bool HasEnoughStaminaFor(EStaminaConsumers consumer)
void StaminaHandler(PlayerBase player)
const float STAMINA_GAIN_MODIFIER
ref map< int, ref StaminaCooldownParams > m_CooldownMap
PlayerBase m_Player
float GetRecoveryMultiplier()
bool m_IsStaminaGainBonusCached
void OnRPC(float stamina, float stamina_cap, bool cooldown)
float CalcStaminaGainBonus()
Calulates stamina regain bonus coef based on current stamina cap and level and caches it during one U...
ref set< EStaminaMultiplierTypes > m_ActiveRecoveryModifiers
const float STAMINA_GAIN_THRESHOLD
ref Param3< float, float, bool > m_StaminaParams
void RecalculateDepletionMultiplier()
bool HasMovementStateChanged()
void StaminaProcessor_Move(HumanMovementState pHumanMovementState)
float GetStaminaNormalized()
float GetSyncedStaminaNormalized()
void SyncStaminaEx()
stamina sync - server part
void ProcessStaminaChanges(float deltaT, bool isServerOrSingleplayer)
void DeactivateDepletionModifier(EStaminaMultiplierTypes type)
void ObtainMove(PlayerBaseMove move)
float m_CachedStaminaGainBonus
bool HasEnoughStaminaToStart(EStaminaConsumers consumer)
void ProcessMovementState()
void SetCooldown(float time, int modifier=-1)
set cooldown timer between each consume of stamina
void SetStamina(float stamina_value)
void ReadAdditionalStaminaInfo(ParamsReadContext pCtx)
Order of read parameters must match the order of writing above.
void ObtainState(PlayerBaseOwnerState state)
void RewindState(PlayerBaseOwnerState state, PlayerBaseMove move)
ref StaminaConsumers m_StaminaConsumers
void ActivateDepletionModifier(EStaminaMultiplierTypes type)
SHumanCommandMoveSettings m_HumanMoveSettings
void ResetCooldown(int modifier=-1)
void SyncStamina(float stamina, float stamina_cap, bool cooldown)
stamina sync - server part
ref map< EStaminaMultiplierTypes, float > m_RegisteredRecoveryModifiers
void ActivateRecoveryModifier(EStaminaMultiplierTypes type)
ref map< EStaminaMultiplierTypes, float > m_RegisteredDepletionModifiers
void Update(float deltaT, int pCurrentCommandID)
override float GetStartTimeAdjustment()
void SetData(SMDataExponential data)
override float GetDurationAdjusted()
ref SMDataExponential m_SMDataEx
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
DayZGame g_Game
Definition dayzgame.c:3942
DayZPlayerInstanceType
defined in C++
DayZPlayerConstants
defined in C++
Definition dayzplayer.c:602
EStaminaConsumers
EStaminaModifiers
Serializer ParamsReadContext
Definition gameplay.c:15
void Error(string err)
Messagebox with error message.
Definition endebug.c:90
enum ShapeType ErrorEx
void Obsolete(string msg="")
Definition enscript.c:371
float GetRunTime()
Definition tools.c:323
float GetDuration()
Definition tools.c:313
void Update()
Definition radialmenu.c:518
class SHumanGlobalSettings SHumanCommandMoveSettings()
enum EObjectTemperatureState m_State
class PlayerStatBase m_MinValue
T m_MaxValue
void StaminaConsumer(float threshold, float threshold2, bool state)
const int RANDOMIZED
m_ActivationThreshold
EStaminaMultiplierTypes
float GetMinValue()
void SetMaxValue(float val)
const int LINEAR
DISEASE_PNEUMONIA
float m_ProgressTime
void StaminaModifier(int type, float min, float max, float cooldown, float startTime=0, float duration=0)
void RegisterLinear(EStaminaModifiers modifier, float startValue, float endValue, float startTime, float duration, float cooldown=GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION)
register lerped modifier - depletes stamina for startValue, and, after a startTime,...
void SetActivationThreshold(float threshold)
void ResetRunTime()
FATIGUE
float m_Tick
void SetStartTime(float val)
void SetInUse(bool val)
StaminaModifierExponential FIXED
m_InUse
void StaminaConsumers()
void SetDrainThreshold(float threshold)
float m_StartTimeAdjustment
void SetState(bool state)
ref map< EStaminaModifiers, ref StaminaModifier > m_StaminaModifiers
void RegisterExponentialEx(EStaminaModifiers modifier, SMDataExponential data)
register exponential modifier, extended parameters
float GetMaxValue()
float GetStartTimeAdjustment()
bool IsInUse()
float m_Multiplier
float m_StartTime
VOMIT_EXHAUSTION
float GetDrainThreshold()
const int EXPONENTIAL
float GetActivationThreshold()
Param1< float > StaminaCooldownParams
void SetRunTimeTick(float val)
void StaminaModifiers()
void SetMinValue(float val)
void RegisterExponential(EStaminaModifiers modifier, float startValue, float exponent, float startTime, float duration, float cooldown=GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION)
register exponential modifier - depletes stamina for startValue, and, after a startTime,...
void RegisterFixed(EStaminaModifiers modifier, float value, float cooldown=GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION)
register single value modifier - depletes stamina for that value
EPINEPHRINE
float GetStartTime()
void SetCooldown(float val)
bool GetState()
returns one of STATE_...
StaminaModifier GetModifierData(EStaminaModifiers modifier)
MASK
float GetCooldown()
float GetDurationAdjusted()
float m_Cooldown
void AddRunTime(float val)
void RegisterRandomized(EStaminaModifiers modifier, float minValue, float maxValue, float cooldown=GameConstants.STAMINA_REGEN_COOLDOWN_DEPLETION)
register randomized modifier - stamina will be depleted by value between min and max value;