Skip to content

Instantly share code, notes, and snippets.

@nickludlam
Created July 1, 2013 21:53
Show Gist options
  • Save nickludlam/5904971 to your computer and use it in GitHub Desktop.
Save nickludlam/5904971 to your computer and use it in GitHub Desktop.
Fatigue system for ArmA3
#ifdef __RUNNING_FATIGUE__
private["_cumulativePlayerFatigue", "_maxEntries", "_sleepInterval", "_fatigueRecoveryLevel", "_fatigueWarningThreshold", "_fatigueExhaustionThreshold", "_extraThirstDecrement", "_tiredEffectApplied", "_exhaustedEffectApplied", "_msg"];
[] spawn {
//diag_log format ["DEBUG: Starting fatigue checks"];
// We sample every _sleepInterval, and keep _maxEntries samples in total. An average is calculated,
// and then we determine if its over _fatigueWarningLevel or _fatigueExhaustionThreshold
// MATHS!
_cumulativePlayerFatigue = [];
_defaultMaxEntries = 18; // Number of entries in our averaging array
_sleepInterval = 10; // Sleep between sampling fatigue
_fatigueRecoveryLevel = 0.45; // Value above which we give the player recovery message
_fatigueTiredThreshold = 0.92; // UI transition warning
_fatigueWarningThreshold = 0.98; // Value above which we warn the player
_fatigueExhaustionThreshold = 1; // Value above which the avg fatigue will cause thirst
_extraThirstDecrement = 4; // Value to decrement each period from the player's water level
_extraHungerDecrement = 1; // Value to decrement each period from the player'spawn food level
// State
_triggeredTiredMessage = 0;
_triggeredExhaustionMode = 0;
// scaling
_scaleFactor = 1;
// PP Effects for tired / exhausted
_hndl = ppEffectCreate ["colorCorrections", 1999];
_tiredEffectApplied = 0;
_exhaustedEffectApplied = 0;
while {true} do
{
// 3 mins of running unemcumbered gets you to 1.0 fagigue
// 2 minutes of running with a full loadout + ghillie gets the same
waitUntil {!respawnDialogActive};
// If the player is a fresh spawn
if (fatigueLevel == 0) then
{
// reset our array
_cumulativePlayerFatigue = [];
_triggeredExhaustionMode = 0;
_triggeredTiredMessage = 0;
};
curFatigueLevel = getFatigue player;
diag_log format ["curFatigueLevel %1", curFatigueLevel];
// Used later
_unit = player;
_speed = sqrt ( (velocity _unit select 0)^2 + (velocity _unit select 1)^2 + (velocity _unit select 2)^2 );
diag_log format ["_speed %1", _speed];
// Weapon count
_hasPrimary = primaryWeapon player;
_hasSecondary = secondaryWeapon player;
_maxEntries = _defaultMaxEntries;
if (_hasPrimary != "" or _hasSecondary != "") then {
if (_hasSecondary != "") then {
diag_log "Player has secondary";
_maxEntries = _maxEntries - 10;
} else {
diag_log "Player has primary";
_maxEntries = _maxEntries - 2;
};
};
diag_log format ["_maxEntries is now %1", _maxEntries];
// Different mechanics once we're exhausted.
// We only come out of exhaustion mode when curFatigueLevel < _fatigueRecoveryLevel
if (_triggeredExhaustionMode == 1) then {
diag_log "In exhaustion mode";
if (curFatigueLevel < _fatigueRecoveryLevel) then
{
// Allow full recovery if you're below 50% fatigue
diag_log "Player recovered";
//player globalChat "Fast recovery!";
_tiredEffectApplied = 0;
_exhaustedEffectApplied = 0;
_hndl ppEffectEnable true;
_hndl ppEffectAdjust [1, 1, 0.0, [0, 0, 0, 0], [1, 1, 1, 1], [0.5, 0.5, 0.5, 0.5]];
_hndl ppEffectCommit 3;
// reset
fatigueLevel = 0;
} else {
// Not recovered yet
if (_speed == 0) then {
// Player still. Do not deduct water/food penalty
diag_log "Player still. Resting";
fatigueLevel = FATIGUE_RESTING;
} else {
// If they're still moving, deduct the penalty
diag_log "Still exhausted";
fatigueLevel = FATIGUE_EXHAUSTED;
// Player is exhausted, decrement food and water
thirstLevel = thirstLevel - _extraThirstDecrement;
hungerLevel = hungerLevel - _extraHungerDecrement;
// Have they died yet?
if (hungerLevel < 2 or thirstLevel < 2) then {
if(hungerLevel < 2) then {player setDamage 1.31337; hint parseText "<t size='2' color='#ff0000'>Warning</t><br/><br/>You have starved to death.";};
if(thirstLevel < 2) then {player setDamage 1.31337; hint parseText "<t size='2' color='#ff0000'>Warning</t><br/><br/>You have died from dehydration.";};
} else {
// If they're not dead, issue the warning
_daytime = daytime;
if (_daytime > 11 and _daytime < 18) then {
// Day time = overheating
_msg = "You're sweating profusely! You need to stop and cool down, otherwise your food and water levels will drop rapidly";
_hint = parseText format ["<t align='center' color='#FF0000'><img size='3' color='#ff0000' image='images\running_icon_128.paa'/></t><br/><t align='center' color='#FF0000' size='1.75'>FATIGUE WARNING!</t><br/><t align='center' color='#ffffff'>%1</t>", _msg];
hint _hint;
} else {
// Night time = tiredness / fatigue
_msg = "You feel exhausted! You need to stop an rest now, otherwise your food and water levels will drop rapidly";
_hint = parseText format ["<t align='center' color='#FF0000'><img size='3' color='#ff0000' image='images\running_icon_128.paa'/></t><br/><t align='center' color='#FF0000' size='1.75'>FATIGUE WARNING!</t><br/><t align='center' color='#ffffff'>%1</t>", _msg];
hint _hint;
};
};
};
};
} else {
diag_log "Not in exhaustion mode";
diag_log format ["_cumulativePlayerFatigue resized by %1", _maxEntries];
_cumulativePlayerFatigue = [curFatigueLevel] + _cumulativePlayerFatigue;
_cumulativePlayerFatigue resize _maxEntries;
diag_log format ["_cumulativePlayerFatigue = %1", _cumulativePlayerFatigue];
// Average the samples we have of fatigue
_total = 0;
{
// Prevent adding nil values
if (_x > 0) then
{
_total = _total + _x;
};
} forEach _cumulativePlayerFatigue;
// calc mean avg
_avgFatigueLevel = _total / _maxEntries;
diag_log format ["avgFatigueLevel = %1", _avgFatigueLevel];
// How high is the level currently?
if (_avgFatigueLevel > _fatigueTiredThreshold) then
{
if (_avgFatigueLevel >= _fatigueExhaustionThreshold) then
{
// Exhaustion mode engage!
diag_log "Triggering exhaustion mode now!";
_triggeredExhaustionMode = 1;
_triggeredTiredMessage = 1;
if (_exhaustedEffectApplied == 0) then {
_hndl ppEffectEnable true;
_hndl ppEffectAdjust [0.7, 1.1, 0, [0, 0, 0, 0], [1, 1, 1, 0.4], [0.5, 0.5, 0.5, 0.5]];
_hndl ppEffectCommit 3;
_exhaustedEffectApplied = 1;
//player globalChat "_exhaustedEffectApplied=1";
};
}
else
{
if (_avgFatigueLevel > _fatigueWarningThreshold) then {
// Fire once
if (_triggeredTiredMessage == 0) then
{
diag_log "Triggering tired message";
_triggeredTiredMessage = 1;
if (_tiredEffectApplied == 0) then {
_hndl ppEffectEnable true;
_hndl ppEffectAdjust [1, 1, 0.0, [0, 0, 0, 0], [1, 1, 1, 0.6], [0.5, 0.5, 0.5, 0.5]];
_hndl ppEffectCommit 3;
_tiredEffectApplied = 1;
//player globalChat "_tiredEffectApplied=1";
};
// Special value
fatigueLevel = FATIGUE_TIRED;
_daytime = daytime;
if (_daytime > 11 and _daytime < 18) then {
// Day time = overheating
hint "You're starting to feel hot and tired. Slow down";
} else {
// Night time = tiredness / fatigue
hint "You're getting tired from the relentless pace. Slow down";
};
} else {
diag_log "Tired or resting";
// If we're here, we've triggered the tired message
// but we're not exhausted, so you're either tired or resting
if (_speed < 1.6) then {
// 1.55 = walking pace
fatigueLevel = FATIGUE_RESTING;
} else {
fatigueLevel = FATIGUE_TIRED;
};
};
} else {
diag_log "Silent tired warning";
fatigueLevel = FATIGUE_TIRED;
};
};
}
else
{
diag_log format ["Average fatigue %1", _avgFatigueLevel];
if (_tiredEffectApplied == 1 or _exhaustedEffectApplied == 1) then {
_tiredEffectApplied = 0;
_exhaustedEffectApplied = 0;
_triggeredTiredMessage = 1;
_hndl ppEffectEnable true;
_hndl ppEffectAdjust [1, 1, 0.0, [0, 0, 0, 0], [1, 1, 1, 1], [0.5, 0.5, 0.5, 0.5]];
_hndl ppEffectCommit 3;
//player globalChat "reset applied effects";
} else {
// If we're in our normal state, disable the ppeffect
_hndl ppEffectEnable false;
};
// Regular value
fatigueLevel = _avgFatigueLevel;
};
};
//player globalChat format ["curFatigueLevel: %1. fatigueLevel: %2. Array: %3", curFatigueLevel, fatigueLevel, _cumulativePlayerFatigue];
sleep _sleepInterval;
};
ppEffectDestroy _hndl;
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment