Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions addons/advanced_fatigue/XEH_PREP.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
PREP(addDutyFactor);
PREP(createStaminaBar);
PREP(getAnimDuty);
PREP(getMaximumSpeed);
PREP(getMetabolicCosts);
PREP(handleEffects);
PREP(handlePlayerChanged);
Expand Down
26 changes: 26 additions & 0 deletions addons/advanced_fatigue/XEH_postInit.sqf
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
#include "script_component.hpp"
if (!hasInterface) exitWith {};

#ifdef DEBUG_MODE_FULL
onEachFrame {
Copy link
Copy Markdown
Member

@bux bux Nov 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this be a separate function?

#ifdef DEBUG_MODE_FULL
call FUNC(renderDebugLines);
#endif

so one could run this without having a debug build?

Copy link
Copy Markdown
Contributor Author

@ulteq ulteq Nov 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can do that.

But the other debug info (shown via systemChat and hintSilent) is more helpful.

Should we try to move all of the debug output into a function?

private _normal = surfaceNormal (getPosWorld ACE_player);
private _beg = (getPosWorld ACE_player) vectorAdd (_normal vectorMultiply 0.5);
private _end = _beg vectorAdd (_normal vectorMultiply 2.0);
drawLine3D [ASLToATL _beg, ASLToATL _end, [0,1,0,1]];

private _side = vectorNormalized (_normal vectorCrossProduct [0, 0, 1]);
private _end = _beg vectorAdd (_side vectorMultiply 2.0);
drawLine3D [ASLToATL _beg, ASLToATL _end, [0,0,1,1]];

private _up = vectorNormalized (_normal vectorCrossProduct _side);
private _end = _beg vectorAdd (_up vectorMultiply 2.0);
drawLine3D [ASLToATL _beg, ASLToATL _end, [1,0,0,1]];

private _movementVector = vectorNormalized (velocity ACE_player);
private _end = _beg vectorAdd (_movementVector vectorMultiply 2.0);
drawLine3D [ASLToATL _beg, ASLToATL _end, [1,1,0,1]];

private _sideVector = vectorNormalized (_movementVector vectorCrossProduct _normal);
_sideVector set[2, 0];
private _end = _beg vectorAdd (_sideVector vectorMultiply 2.0);
drawLine3D [ASLToATL _beg, ASLToATL _end, [0,1,1,1]];
};
#endif

["ace_settingsInitialized", {
if (!GVAR(enabled)) exitWith {};

Expand Down
2 changes: 1 addition & 1 deletion addons/advanced_fatigue/functions/fnc_getAnimDuty.sqf
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Author: BaerMitUmlaut
* Calculates the duty of the current animation.
* Calculates the duty ('postureWeight') of the current animation.
*
* Arguments:
* 0: Unit <OBJECT>
Expand Down
93 changes: 93 additions & 0 deletions addons/advanced_fatigue/functions/fnc_getMaximumSpeed.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Author: BaerMitUmlaut, Ruthberg
* Calculates the current maximum movement speed for a unit.
* Calculation is done according to the Pandolf/Wojtowicz formulas.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Power <NUMBER>
* 2: Forward Angle <NUMBER>
* 3: Side Angle <NUMBER>
*
* Return Value:
* Speed <NUMBER>
*
* Example:
* [player, 840, 0, 0] call ace_advanced_fatigue_fnc_getMaximumSpeed
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_power", "_fwdAngle", "_sideAngle"];

private _gearMass = 0 max (((_unit getVariable [QEGVAR(movement,totalLoad), loadAbs _unit]) / 22.046 - 3.5) * GVAR(loadFactor));
private _terrainGradient = abs(_fwdAngle);
private _terrainFactor = 1;

private _duty = GVAR(animDuty);
{
if (_x isEqualType 0) then {
_duty = _duty * _x;
} else {
_duty = _duty * (_unit call _x);
};
} forEach (GVAR(dutyList) select 1);

if (!GVAR(isSwimming)) then {
if (_fwdAngle < 0) then {
_terrainGradient = 0.15 * _terrainGradient;
};
if ((getPosATL _unit) select 2 < 0.01) then {
private _sideGradient = abs(_sideAngle / 45) min 1;
_terrainFactor = 1 + _sideGradient ^ 4;
};
};

private _fnc_getRunningSpeed = {
params ["_power", "_gearMass", "_terrainFactor", "_terrainGradient", "_duty"];
private _p = _power / 0.23;
_p = _p - 2.10 * SIM_BODYMASS;
_p = _p - 4 * (SIM_BODYMASS + _gearMass) * (_gearMass / SIM_BODYMASS) ^ 2;
_p = _p / (_terrainFactor * (SIM_BODYMASS + _gearMass));
(1 / 30 * (-11 * _terrainGradient + sqrt(121 * (_terrainGradient ^ 2) + 1000 * _p)))
};

private _fnc_getWalkingSpeed = {
params ["_power", "_gearMass", "_terrainFactor", "_terrainGradient", "_duty"];
private _p = _power / 0.23;
_p = _p - 1.05 * SIM_BODYMASS;
_p = _p - 2 * (SIM_BODYMASS + _gearMass) * (_gearMass / SIM_BODYMASS) ^ 2;
_p = _p / (_terrainFactor * (SIM_BODYMASS + _gearMass));
(1 / 115 * (-33 * _terrainGradient + sqrt(1089 * (_terrainGradient ^ 2) + 11500 * _p)))
};

/*
private _fnc_getRunningSpeed = {
params ["_power", "_gearMass", "_terrainFactor", "_terrainGradient", "_duty"];
private _numerator = 3.6 * - (_power / (0.23 * _duty));
_numerator = _numerator - 2.1 * SIM_BODYMASS;
_numerator = _numerator - 4 * (_gearMass + SIM_BODYMASS) * (_gearMass / SIM_BODYMASS) ^ 2;
private _denominator = _terrainFactor * (_gearMass + SIM_BODYMASS);
private _radicand = ((0.66 * _terrainGradient) ^ 2) - _numerator / _denominator;
private _v = -0.66 * _terrainGradient + sqrt(_radicand);
_v / 1.8
};

private _fnc_getWalkingSpeed = {
params ["_power", "_gearMass", "_terrainFactor", "_terrainGradient", "_duty"];
private _numerator = 4.6 * - (_power / (0.23 * _duty));
_numerator = _numerator - 1.05 * SIM_BODYMASS;
_numerator = _numerator - 2 * (_gearMass + SIM_BODYMASS) * (_gearMass / SIM_BODYMASS) ^ 2;
private _denominator = _terrainFactor * (_gearMass + SIM_BODYMASS);
private _radicand = ((0.66 * _terrainGradient) ^ 2) - _numerator / _denominator;
private _v = -0.66 * _terrainGradient + sqrt(_radicand);
_v / 2.3
};
*/

private _speed = [_power, _gearMass, _terrainFactor, _terrainGradient, _duty] call _fnc_getRunningSpeed;
if (_speed < 2) then {
_speed = [_power, _gearMass, _terrainFactor, _terrainGradient, _duty] call _fnc_getWalkingSpeed;
};

_speed
49 changes: 34 additions & 15 deletions addons/advanced_fatigue/functions/fnc_getMetabolicCosts.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,25 @@
* Arguments:
* 0: Unit <OBJECT>
* 1: Speed <NUMBER>
* 2: Forward Angle <NUMBER>
* 3: Side Angle <NUMBER>
*
* Return Value:
* Metabolic cost <NUMBER>
*
* Example:
* [player, 3.3] call ace_advanced_fatigue_fnc_getMetabolicCosts
* [player, 3.3, 0, 0] call ace_advanced_fatigue_fnc_getMetabolicCosts
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_velocity"];
params ["_unit", "_speed", "_fwdAngle", "_sideAngle"];

private _gearMass = ((_unit getVariable [QEGVAR(movement,totalLoad), loadAbs _unit]) / 22.046) * GVAR(loadFactor);
private _gearMass = 0 max (((_unit getVariable [QEGVAR(movement,totalLoad), loadAbs _unit]) / 22.046 - 3.5) * GVAR(loadFactor));
private _terrainGradient = abs(_fwdAngle);
private _terrainFactor = 1;

private _terrainAngle = asin (1 - ((surfaceNormal getPosASL _unit) select 2));
private _terrainGradient = (_terrainAngle / 45 min 1) * 5 * GVAR(terrainGradientFactor);
private _duty = GVAR(animDuty);

{
if (_x isEqualType 0) then {
_duty = _duty * _x;
Expand All @@ -32,20 +33,38 @@ private _duty = GVAR(animDuty);
};
} forEach (GVAR(dutyList) select 1);

if (GVAR(isSwimming)) then {
_terrainGradient = 0;
if (!GVAR(isSwimming)) then {
if (_fwdAngle < 0) then {
_terrainGradient = 0.15 * _terrainGradient;
};
if ((getPosATL _unit) select 2 < 0.01) then {
private _sideGradient = abs(_sideAngle / 45) min 1;
_terrainFactor = 1 + _sideGradient ^ 4;
};
};

if (_velocity > 2) then {
if (_speed > 2) then {
#ifdef DEBUG_MODE_FULL
private _baseline = 2.10 * SIM_BODYMASS + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + (SIM_BODYMASS + _gearMass) * 0.90 * (_speed ^ 2);
private _graded = 2.10 * SIM_BODYMASS + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + _terrainFactor * (SIM_BODYMASS + _gearMass) * (0.90 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient);
private _terrainImpact = abs((_graded / _baseline) - 1);
hintSilent format["FwdAngle: %1 | SideAngle: %2 \n TerrainFactor: %3 | TerrainGradient: %4 \n TerrainImpact: %5 \n Speed: %6 | CarriedLoad: %7 \n Duty: %8 | Work: %9", _fwdAngle toFixed 1, _sideAngle toFixed 1, _terrainFactor toFixed 2, _terrainGradient toFixed 1, _terrainImpact toFixed 2, _speed toFixed 2, _gearMass toFixed 1, _duty toFixed 2, round(_graded * BIOMECH_EFFICIENCY * _duty)];
#endif
(
2.10 * SIM_BODYMASS
+ 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2)
+ (SIM_BODYMASS + _gearMass) * (0.90 * (_velocity ^ 2) + 0.66 * _velocity * _terrainGradient)
) * 0.23 * _duty
+ 4 * (SIM_BODYMASS + _gearMass) * (_gearMass / SIM_BODYMASS) ^ 2
+ _terrainFactor * (SIM_BODYMASS + _gearMass) * (0.90 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient)
) * BIOMECH_EFFICIENCY * _duty
} else {
#ifdef DEBUG_MODE_FULL
private _baseline = 1.05 * SIM_BODYMASS + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + (SIM_BODYMASS + _gearMass) * 1.15 * (_speed ^ 2);
private _graded = 1.05 * SIM_BODYMASS + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + _terrainFactor * (SIM_BODYMASS + _gearMass) * (1.15 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient);
private _terrainImpact = abs((_graded / _baseline) - 1);
hintSilent format["FwdAngle: %1 | SideAngle: %2 \n TerrainFactor: %3 | TerrainGradient: %4 \n TerrainImpact: %5 \n Speed: %6 | CarriedLoad: %7 \n Duty: %8 | Work: %9", _fwdAngle toFixed 1, _sideAngle toFixed 1, _terrainFactor toFixed 2, _terrainGradient toFixed 1, _terrainImpact toFixed 2, _speed toFixed 2, _gearMass toFixed 1, _duty toFixed 2, round(_graded * BIOMECH_EFFICIENCY * _duty)];
#endif
(
1.05 * SIM_BODYMASS
+ 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2)
+ (SIM_BODYMASS + _gearMass) * (1.15 * (_velocity ^ 2) + 0.66 * _velocity * _terrainGradient)
) * 0.23 * _duty
+ 2 * (SIM_BODYMASS + _gearMass) * (_gearMass / SIM_BODYMASS) ^ 2
+ _terrainFactor * (SIM_BODYMASS + _gearMass) * (1.15 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient)
) * BIOMECH_EFFICIENCY * _duty
};
55 changes: 35 additions & 20 deletions addons/advanced_fatigue/functions/fnc_handleEffects.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,32 @@
* Arguments:
* 0: Unit <OBJECT>
* 1: Fatigue <NUMBER>
* 2: Speed <NUMBER>
* 3: Overexhausted <BOOL>
* 2: Respiratory Rate <NUMBER>
* 3: Current Speed <NUMBER>
* 4: Max Run Speed <NUMBER>
* 5: Max Sprint Speed <NUMBER>
* 6: Forward Angle <NUMBER>
* 7: Side Angle <NUMBER>
*
* Return Value:
* None
*
* Example:
* [_player, 0.5, 3.3, true] call ace_advanced_fatigue_fnc_handleEffects
* [_player, 0.5, 3.3, true, 0, 0] call ace_advanced_fatigue_fnc_handleEffects
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_fatigue", "_speed", "_overexhausted"];

#ifdef DEBUG_MODE_FULL
systemChat str _fatigue;
systemChat str vectorMagnitude velocity _unit;
#endif
params ["_unit", "_fatigue", "_respiratoryRate", "_currentSpeed", "_maxRunSpeed", "_maxSprintSpeed", "_fwdAngle", "_sideAngle"];

// - Audible effects ----------------------------------------------------------
GVAR(lastBreath) = GVAR(lastBreath) + 1;
if (_fatigue > 0.4 && {GVAR(lastBreath) > (_fatigue * -10 + 9)} && {!underwater _unit}) then {
if (_respiratoryRate > 0.4 && {GVAR(lastBreath) > (_respiratoryRate * -10 + 9)} && {!underwater _unit}) then {
switch (true) do {
case (_fatigue < 0.6): {
case (_respiratoryRate < 0.6): {
playSound (QGVAR(breathLow) + str(floor random 6));
};
case (_fatigue < 0.85): {
case (_respiratoryRate < 0.85): {
playSound (QGVAR(breathMid) + str(floor random 6));
};
default {
Expand Down Expand Up @@ -60,28 +59,44 @@ if (GVAR(ppeBlackoutLast) == 1) then {
if (GVAR(isSwimming)) exitWith {
_unit setAnimSpeedCoef linearConversion [0.7, 0.9, _fatigue, 1, 0.5, true];

if ((isSprintAllowed _unit) && {_fatigue > 0.7}) then {
if ((isSprintAllowed _unit) && _fatigue > 0.7) then {
[_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
} else {
if ((!isSprintAllowed _unit) && {_fatigue < 0.7}) then {
if ((!isSprintAllowed _unit) && _fatigue < 0.7) then {
[_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
};
};
};
if ((getAnimSpeedCoef _unit) != 1) then {
_unit setAnimSpeedCoef 1;

private _currentAnimCoef = getAnimSpeedCoef _unit;
if (_currentSpeed > 0.1) then {
if (_currentSpeed > 4 * _currentAnimCoef || _currentSpeed > GVAR(lastSpeed) + 0.8) then {
_unit setAnimSpeedCoef (0.70 max (_currentAnimCoef * ((_maxSprintSpeed / _currentSpeed) ^ 0.5)) min 1.0);
} else {
if (isForcedWalk _unit) then {
_unit setAnimSpeedCoef (0.80 max (_currentAnimCoef * ((_maxRunSpeed / _currentSpeed) ^ 0.5)) min 1.2);
} else {
_unit setAnimSpeedCoef (0.70 max (_currentAnimCoef * ((_maxRunSpeed / _currentSpeed) ^ 0.5)) min 1.0);
};
};
GVAR(lastSpeed) = _currentSpeed;
};

if (_overexhausted) then {
if (!isForcedWalk _unit && {_fatigue >= 1 || (_maxRunSpeed < 2.4 && _currentSpeed < 2.5 && _currentAnimCoef < 0.75)}) then {
_unit setAnimSpeedCoef 1.2;
[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
} else {
if (isForcedWalk _unit && {_fatigue < 0.7}) then {
if (isForcedWalk _unit && {_fatigue < 0.90 && _maxRunSpeed > 2.5}) then {
if (!isWalking _unit) then {
_unit setAnimSpeedCoef 0.90;
};
[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
} else {
if ((isSprintAllowed _unit) && {_fatigue > 0.7}) then {
if (isSprintAllowed _unit && {abs(_fwdAngle) > 20 || abs(_sideAngle) > 20 || (_maxSprintSpeed < 3.5 && _currentAnimCoef < 0.85)}) then {
_unit setAnimSpeedCoef 1;
[_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
} else {
if ((!isSprintAllowed _unit) && {_fatigue < 0.6}) then {
if (!isSprintAllowed _unit && {_fatigue < 0.8 && {abs(_fwdAngle) < 20 && abs(_sideAngle) < 20 && _maxSprintSpeed > 4.5}}) then {
[_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
};
};
Expand Down
19 changes: 15 additions & 4 deletions addons/advanced_fatigue/functions/fnc_handlePlayerChanged.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ if !(isNull _oldUnit) then {
_oldUnit setVariable [QGVAR(anReserve), GVAR(anReserve)];
_oldUnit setVariable [QGVAR(anFatigue), GVAR(anFatigue)];
_oldUnit setVariable [QGVAR(muscleDamage), GVAR(muscleDamage)];
_oldUnit setVariable [QGVAR(respiratoryRate), GVAR(respiratoryRate)];
};

_newUnit enableStamina false;
Expand All @@ -47,18 +48,28 @@ GVAR(ae2Reserve) = _newUnit getVariable [QGVAR(ae2Reserve), AE2_MAXRESERVE]
GVAR(anReserve) = _newUnit getVariable [QGVAR(anReserve), AN_MAXRESERVE];
GVAR(anFatigue) = _newUnit getVariable [QGVAR(anFatigue), 0];
GVAR(muscleDamage) = _newUnit getVariable [QGVAR(muscleDamage), 0];
GVAR(respiratoryRate) = _newUnit getVariable [QGVAR(respiratoryRate), 0];

// Clean variables for respawning units
{
_newUnit setVariable [_x, nil];
} forEach [QGVAR(ae1Reserve), QGVAR(ae2Reserve), QGVAR(anReserve), QGVAR(anFatigue), QGVAR(muscleDamage)];
} forEach [QGVAR(ae1Reserve), QGVAR(ae2Reserve), QGVAR(anReserve), QGVAR(anFatigue), QGVAR(muscleDamage), QGVAR(respiratoryRate)];

GVAR(VO2Max) = 35 + 20 * (_newUnit getVariable [QGVAR(performanceFactor), GVAR(performanceFactor)]);
GVAR(VO2MaxPower) = GVAR(VO2Max) * SIM_BODYMASS * 0.23 * JOULES_PER_ML_O2 / 60;
GVAR(VO2MaxPower) = GVAR(VO2Max) * SIM_BODYMASS * BIOMECH_EFFICIENCY * JOULES_PER_ML_O2 / 60;
GVAR(peakPower) = VO2MAX_STRENGTH * GVAR(VO2MaxPower);

GVAR(ae1PathwayPower) = GVAR(peakPower) / (13.3 + 16.7 + 113.3) * 13.3 * ANTPERCENT ^ 1.28 * 1.362;
GVAR(ae2PathwayPower) = GVAR(peakPower) / (13.3 + 16.7 + 113.3) * 16.7 * ANTPERCENT ^ 1.28 * 1.362;
GVAR(ae1PathwayPower) = GVAR(peakPower) / (AE1_ATP_RELEASE_RATE + AE2_ATP_RELEASE_RATE + AN_ATP_RELEASE_RATE) * AE1_ATP_RELEASE_RATE * ANTPERCENT ^ 1.28 * 1.362;
GVAR(ae2PathwayPower) = GVAR(peakPower) / (AE1_ATP_RELEASE_RATE + AE2_ATP_RELEASE_RATE + AN_ATP_RELEASE_RATE) * AE2_ATP_RELEASE_RATE * ANTPERCENT ^ 1.28 * 1.362;
GVAR(aePathwayPower) = GVAR(ae1PathwayPower) + GVAR(ae2PathwayPower);
GVAR(anPathwayPower) = GVAR(peakPower) - GVAR(aePathwayPower);

GVAR(aeWattsPerATP) = GVAR(ae1PathwayPower) / AE1_ATP_RELEASE_RATE;
GVAR(anWattsPerATP) = GVAR(anPathwayPower) / AN_ATP_RELEASE_RATE;

GVAR(respiratoryBufferDivisor) = (RESPIRATORY_BUFFER - 1) / RESPIRATORY_BUFFER;
GVAR(maxPowerFatigueRatio) = 0.057 / GVAR(peakPower);
GVAR(lastSpeed) = 0;

GVAR(ppeBlackoutLast) = 100;
GVAR(lastBreath) = 0;
Expand Down
Loading