Work done on medical states

This commit is contained in:
Glowbal 2016-07-07 11:46:55 +02:00
parent e8eb729e04
commit d0236a007a
13 changed files with 680 additions and 6 deletions

View File

@ -1,6 +1,6 @@
class ACE_Medical_StateMachine { class ACE_Medical_StateMachine {
class Default { class Default {
onState = QUOTE(DFUNC(handleDefaultState)); onState = QUOTE(DFUNC(handleStateDefault));
onStateEntered = ""; onStateEntered = "";
onStateLeaving = ""; onStateLeaving = "";
class Injury { class Injury {
@ -17,7 +17,7 @@ class ACE_Medical_StateMachine {
}; };
}; };
class Injured { class Injured {
onState = QUOTE(DFUNC(handleInjuredState)); onState = QUOTE(DFUNC(handleStateInjured));
onStateEntered = ""; onStateEntered = "";
onStateLeaving = ""; onStateLeaving = "";
@ -39,7 +39,7 @@ class ACE_Medical_StateMachine {
}; };
}; };
class Unconscious { class Unconscious {
onState = QUOTE(DFUNC(handleUnconciousState)); onState = QUOTE(DFUNC(handleStateUnconscious));
onStateEntered = QUOTE(DFUNC(enteredUnconscious)); // set unconscious animation & state onStateEntered = QUOTE(DFUNC(enteredUnconscious)); // set unconscious animation & state
onStateLeaving = QUOTE(DFUNC(leavingUnconscious)); // leave unconscious animation & state onStateLeaving = QUOTE(DFUNC(leavingUnconscious)); // leave unconscious animation & state
class WakeUpFromKnockDown { class WakeUpFromKnockDown {
@ -61,7 +61,7 @@ class ACE_Medical_StateMachine {
onStateEntered = "(_this select 0) setDamage 1"; // killing a unit also exits the state machine for this unit onStateEntered = "(_this select 0) setDamage 1"; // killing a unit also exits the state machine for this unit
}; };
class Revive { class Revive {
onState = QUOTE(DFUNC(handleReviveState)); onState = QUOTE(DFUNC(handleStateRevive));
onStateEntered = QUOTE(DFUNC(enteredRevive)); // set unconscious animation & state onStateEntered = QUOTE(DFUNC(enteredRevive)); // set unconscious animation & state
onStateLeaving = QUOTE(DFUNC(leavingRevive)); // leave unconscious animation & state onStateLeaving = QUOTE(DFUNC(leavingRevive)); // leave unconscious animation & state
class FullHeal { class FullHeal {

View File

@ -0,0 +1,114 @@
/*
* Author: Glowbal
* Handle entering an unconscious state.
*
* Arguments:
* 0: The unit that will be put in an unconscious state <OBJECT>
* 1: Set unconsciouns <BOOL> (default: true)
* 2: Minimum unconscious time <NUMBER> (default: (round(random(10)+5)))
* 3: Force AI Unconscious (skip random death chance) <BOOL> (default: false)
*
* ReturnValue:
* nil
*
* Public: no
*/
#include "script_component.hpp"
#define DEFAULT_DELAY (round(random(10)+5))
params ["_unit", "_event", "_args"];
private ["_animState", "_originalPos", "_startingTime", "_isDead"];
//params ["_unit", ["_set", true], ["_minWaitingTime", DEFAULT_DELAY], ["_force", false]];
if !(!(isNull _unit) && {(_unit isKindOf "CAManBase") && ([_unit] call EFUNC(common,isAwake))}) exitWith{
// TODO log error, already in an unconsicous state or dead?
};
_unit setVariable ["ACE_isUnconscious", true, true];
// Disabled to not run with the 1.62 vanilla medical changes.
// _unit setUnconscious true;
// Ensure the map is closed when entering the unconscious state
if (_unit == ACE_player) then {
if (visibleMap) then {openMap false};
while {dialog} do {
closeDialog 0;
};
};
// if we have unconsciousness for AI disabled, we will kill the unit instead
_isDead = false;
if (!([_unit, GVAR(remoteControlledAI)] call EFUNC(common,isPlayer)) && !_force) then {
_enableUncon = _unit getVariable [QGVAR(enableUnconsciousnessAI), GVAR(enableUnconsciousnessAI)];
if (_enableUncon == 0 or {_enableUncon == 1 and (random 1) < 0.5}) then {
//[_unit, true] call FUNC(setDead);
// TODO raise fatal event
_isDead = true;
};
};
if (_isDead) exitWith {};
// If a unit has the launcher out, it will sometimes start selecting the primairy weapon while unconscious,
// therefor we force it to select the primairy weapon before going unconscious
if ((vehicle _unit) isKindOf "StaticWeapon") then {
[_unit] call EFUNC(common,unloadPerson);
};
if (animationState _unit in ["ladderriflestatic","laddercivilstatic"]) then {
_unit action ["ladderOff", (nearestBuilding _unit)];
};
if (vehicle _unit == _unit) then {
if (primaryWeapon _unit == "") then {
_unit addWeapon "ACE_FakePrimaryWeapon";
};
_unit selectWeapon (primaryWeapon _unit);
};
// We are storing the current animation, so we can use it later on when waking the unit up inside a vehicle
if (vehicle _unit != _unit) then {
_unit setVariable [QGVAR(vehicleAwakeAnim), [(vehicle _unit), (animationState _unit)]];
};
//Save current stance:
_originalPos = unitPos _unit;
_unit setUnitPos "DOWN";
[_unit, true] call EFUNC(common,disableAI);
// So the AI does not get stuck, we are moving the unit to a temp group on its own.
//Unconscious units shouldn't be put in another group #527:
if (GVAR(moveUnitsFromGroupOnUnconscious)) then {
[_unit, true, "ACE_isUnconscious", side group _unit] call EFUNC(common,switchToGroupSide);
};
// Delay Unconscious so the AI dont instant stop shooting on the unit #3121
if (GVAR(delayUnconCaptive) == 0) then {
[_unit, "setCaptive", "ace_unconscious", true] call EFUNC(common,statusEffect_set);
} else {
[{
params ["_unit"];
if (_unit getVariable ["ACE_isUnconscious", false]) then {
[_unit, "setCaptive", "ace_unconscious", true] call EFUNC(common,statusEffect_set);
};
},[_unit], GVAR(delayUnconCaptive)] call CBA_fnc_waitAndExecute;
};
_anim = [_unit] call EFUNC(common,getDeathAnim);
[_unit, _anim, 1, true] call EFUNC(common,doAnimation);
[{
params ["_unit", "_anim"];
if ((_unit getVariable "ACE_isUnconscious") and (animationState _unit != _anim)) then {
[_unit, _anim, 2, true] call EFUNC(common,doAnimation);
};
}, [_unit, _anim], 0.5, 0] call CBA_fnc_waitAndExecute;
_startingTime = CBA_missionTime;
// gets started in the handle unconscious state
// [DFUNC(unconsciousPFH), 0.1, [_unit, _originalPos, _startingTime, _minWaitingTime, false, vehicle _unit isKindOf "ParachuteBase"] ] call CBA_fnc_addPerFrameHandler;
// unconscious can't talk
[_unit, "isUnconscious"] call EFUNC(common,muteUnit);
["ace_unconscious", [_unit, true]] call CBA_fnc_globalEvent;

View File

@ -0,0 +1,25 @@
/*
* Author: Glowbal
* Called when a unit is killed
*
* Arguments:
* 0: The Unit <OBJECT>
*
* ReturnValue:
* None
*
* Public: No
*/
#include "script_component.hpp"
private "_openWounds";
params ["_unit"];
if (!local _unit) exitWith {};
_unit setVariable [QGVAR(pain), 0];
if (GVAR(level) >= 2) then {
_unit setVariable [QGVAR(heartRate), 0];
_unit setVariable [QGVAR(bloodPressure), [0, 0]];
_unit setVariable [QGVAR(airwayStatus), 0];
};

View File

@ -0,0 +1,34 @@
/*
* Author: Glowbal
* Called when a unit switched locality
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Is local <BOOL>
*
* ReturnValue:
* None
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_local"];
if (_local) then {
// If the unit had a loop tracking its vitals, restart it locally
if (_unit getVariable[QGVAR(addedToUnitLoop),false]) then {
[_unit, true] call FUNC(addVitalLoop);
};
if ((_unit getVariable ["ACE_isUnconscious",false]) && {count (_unit getVariable [QGVAR(unconsciousArguments), []]) >= 6}) then {
private "_arguments";
_arguments = (_unit getVariable [QGVAR(unconsciousArguments), []]);
_arguments set [2, CBA_missionTime];
[DFUNC(unconsciousPFH), 0.1, _arguments ] call CBA_fnc_addPerFrameHandler;
_unit setVariable [QGVAR(unconsciousArguments), nil, true];
};
};

View File

@ -0,0 +1,42 @@
/*
* Author: Glowbal, esteldunedain
* Medication effect loop for an injection.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Name of the Variable that is affected <STRING>
* 2: Proportion of the effect applied <NUMBER>
* 3: Rate at which the effect is applied <NUMBER>
* 4: Viscosity adjustment rate <NUMBER>
* 5: Pain reduction rate <NUMBER>
*
* ReturnValue:
* None
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_variableName", "_amountDecreased","_decreaseRate", "_viscosityAdjustmentRate", "_painReduceRate"];
// If the unit died the loop is finished
if (!alive _unit) exitWith {};
// If locality changed finish the local loop
if (!local _unit) exitWith {};
// Apply medicinal effect
private _usedMeds = (_unit getVariable [_variableName, 0]) - _decreaseRate;
_unit setVariable [_variableName, _usedMeds];
// Restore the viscosity while the medication is leaving the system
_unit setVariable [QGVAR(peripheralResistance), ((_unit getVariable [QGVAR(peripheralResistance), 100]) - _viscosityAdjustmentRate) max 0];
_unit setVariable [QGVAR(painSuppress), ((_unit getVariable [QGVAR(painSuppress), 0]) - _painReduceRate) max 0];
// Exit if the medication has finished it's effect
_amountDecreased = _amountDecreased + _decreaseRate;
if (_amountDecreased >= 1 || (_usedMeds <= 0) || !alive _unit) exitWith {};
// Schedule the loop to be executed again 1 sec later
[DFUNC(medicationEffectLoop), [_unit, _variableName, _amountDecreased, _decreaseRate, _viscosityAdjustmentRate, _painReduceRate], 1] call CBA_fnc_waitAndExecute;

View File

@ -0,0 +1,24 @@
#include "script_component.hpp"
params ["_unit", "_stateName", "_lastTime"];
// If the unit died the loop is finished
if (!alive _unit) exitWith {};
// If locality changed, broadcast the last medical state and finish the local loop
if (!local _unit) exitWith {
if (GVAR(level) >= 2) then {
_unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true];
_unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true];
};
_unit setVariable [QGVAR(bloodVolume), _unit getVariable [QGVAR(bloodVolume), 100], true];
};
[_unit, CBA_missionTime - _lastTime] call FUNC(handleUnitVitals);
private _pain = _unit getVariable [QGVAR(pain), 0];
if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then {
[_unit, _pain] call FUNC(playInjuredSound);
};

View File

@ -0,0 +1,24 @@
#include "script_component.hpp"
params ["_unit", "_stateName", "_lastTime"];
// If the unit died the loop is finished
if (!alive _unit) exitWith {};
// If locality changed, broadcast the last medical state and finish the local loop
if (!local _unit) exitWith {
if (GVAR(level) >= 2) then {
_unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true];
_unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true];
};
_unit setVariable [QGVAR(bloodVolume), _unit getVariable [QGVAR(bloodVolume), 100], true];
};
[_unit, CBA_missionTime - _lastTime] call FUNC(handleUnitVitals);
private _pain = _unit getVariable [QGVAR(pain), 0];
if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then {
[_unit, _pain] call FUNC(playInjuredSound);
};

View File

@ -0,0 +1,24 @@
#include "script_component.hpp"
params ["_unit", "_stateName", "_lastTime"];
// If the unit died the loop is finished
if (!alive _unit) exitWith {};
// If locality changed, broadcast the last medical state and finish the local loop
if (!local _unit) exitWith {
if (GVAR(level) >= 2) then {
_unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true];
_unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true];
};
_unit setVariable [QGVAR(bloodVolume), _unit getVariable [QGVAR(bloodVolume), 100], true];
};
[_unit, CBA_missionTime - _lastTime] call FUNC(handleUnitVitals);
private _pain = _unit getVariable [QGVAR(pain), 0];
if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then {
[_unit, _pain] call FUNC(playInjuredSound);
};

View File

@ -0,0 +1,24 @@
#include "script_component.hpp"
params ["_unit", "_stateName", "_lastTime"];
// If the unit died the loop is finished
if (!alive _unit) exitWith {};
// If locality changed, broadcast the last medical state and finish the local loop
if (!local _unit) exitWith {
if (GVAR(level) >= 2) then {
_unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true];
_unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true];
};
_unit setVariable [QGVAR(bloodVolume), _unit getVariable [QGVAR(bloodVolume), 100], true];
};
[_unit, CBA_missionTime - _lastTime] call FUNC(handleUnitVitals);
private _pain = _unit getVariable [QGVAR(pain), 0];
if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then {
[_unit, _pain] call FUNC(playInjuredSound);
};

View File

@ -0,0 +1,126 @@
#include "script_component.hpp"
params ["_unit", "_args"];
_args params ["_originalPos", "_startingTime", "_minWaitingTime", "_hasMovedOut", "_parachuteCheck"];
TRACE_6("ACE_DEBUG_Unconscious_handling",_unit, _originalPos, _startingTime, _minWaitingTime, _hasMovedOut, _parachuteCheck);
if (!alive _unit) exitWith { // TODO on exit unconscious
if ("ACE_FakePrimaryWeapon" in (weapons _unit)) then {
TRACE_1("Removing fake weapon [on death]",_unit);
_unit removeWeapon "ACE_FakePrimaryWeapon";
};
if (GVAR(moveUnitsFromGroupOnUnconscious)) then {
[_unit, false, "ACE_isUnconscious", side group _unit] call EFUNC(common,switchToGroupSide);
};
[_unit, "setCaptive", "ace_unconscious", false] call EFUNC(common,statusEffect_set);
[_unit, false] call EFUNC(common,disableAI);
//_unit setUnitPos _originalPos;
//_unit setUnconscious false;
[_unit, "isUnconscious"] call EFUNC(common,unmuteUnit);
["ace_unconscious", [_unit, false]] call CBA_fnc_globalEvent;
TRACE_3("ACE_DEBUG_Unconscious_Exit",_unit, (!alive _unit) , "ace_unconscious");
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
// In case the unit is no longer in an unconscious state, we are going to check if we can already reset the animation
if !(_unit getVariable ["ACE_isUnconscious",false]) exitWith {
TRACE_7("ACE_DEBUG_Unconscious_PFH",_unit, _args, [_unit] call FUNC(isBeingCarried), [_unit] call FUNC(isBeingDragged), _idPFH, _unit getVariable QGVAR(unconsciousArguments),animationState _unit);
// TODO, handle this with carry instead, so we can remove the PFH here.
// Wait until the unit isn't being carried anymore, so we won't end up with wierd animations
if !(([_unit] call FUNC(isBeingCarried)) || ([_unit] call FUNC(isBeingDragged))) then {
if ("ACE_FakePrimaryWeapon" in (weapons _unit)) then {
TRACE_1("Removing fake weapon [on wakeup]",_unit);
_unit removeWeapon "ACE_FakePrimaryWeapon";
};
if (vehicle _unit == _unit) then {
if (animationState _unit == "AinjPpneMstpSnonWrflDnon") then {
[_unit,"AinjPpneMstpSnonWrflDnon_rolltofront", 2] call EFUNC(common,doAnimation);
[_unit,"amovppnemstpsnonwnondnon", 1] call EFUNC(common,doAnimation);
} else {
[_unit,"amovppnemstpsnonwnondnon", 2] call EFUNC(common,doAnimation);
};
} else {
_vehicle = vehicle _unit;
_oldVehicleAnimation = _unit getVariable [QGVAR(vehicleAwakeAnim), []];
_awakeInVehicleAnimation = "";
if (((count _oldVehicleAnimation) > 0) && {(_oldVehicleAnimation select 0) == _vehicle}) then {
_awakeInVehicleAnimation = _oldVehicleAnimation select 1;
};
//Make sure we have a valid, non-terminal animation:
if ((_awakeInVehicleAnimation != "") && {(getNumber (configFile >> "CfgMovesMaleSdr" >> "States" >> _awakeInVehicleAnimation >> "terminal")) == 0}) then {
[_unit, _awakeInVehicleAnimation, 2] call EFUNC(common,doAnimation);
} else {
//Don't have a valid animation saved, reset the unit animation with a moveInXXX
TRACE_1("No Valid Animation, doing seat reset", _awakeInVehicleAnimation);
_slotInfo = [];
{if ((_x select 0) == _unit) exitWith {_slotInfo = _x;};} forEach (fullCrew _vehicle);
if (_slotInfo isEqualTo []) exitWith {ERROR("No _slotInfo?");};
//Move the unit out:
_unit setPosASL ((getPosASL _unit) vectorAdd [0,0,100]);
//Move the unit back into old seat:
if ((_slotInfo select 1) == "driver") then {
_unit moveInDriver _vehicle;
} else {
if ((_slotInfo select 1) == "cargo") then {
_unit moveInCargo [_vehicle, (_slotInfo select 2)];
} else {
_unit moveInTurret [_vehicle, (_slotInfo select 3)];
};
};
};
};
_unit setVariable [QGVAR(vehicleAwakeAnim), nil];
// Now we can leave our unconsicous state
["ace_unconscious", [_unit, false]] call CBA_fnc_globalEvent;
// EXIT PFH
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
if (!_hasMovedOut) then {
// Reset the unit back to the previous captive state.
[_unit, "setCaptive", "ace_unconscious", false] call EFUNC(common,statusEffect_set);
// Swhich the unit back to its original group
//Unconscious units shouldn't be put in another group #527:
if (GVAR(moveUnitsFromGroupOnUnconscious)) then {
[_unit, false, "ACE_isUnconscious", side group _unit] call EFUNC(common,switchToGroupSide);
};
[_unit, false] call EFUNC(common,disableAI);
_unit setUnitPos _originalPos; // This is not position but stance (DOWN, MIDDLE, UP)
_unit setUnconscious false;
[_unit, "isUnconscious"] call EFUNC(common,unmuteUnit);
// ensure this statement runs only once
_args set [4, true];
};
};
if (_parachuteCheck) then {
if !(vehicle _unit isKindOf "ParachuteBase") then {
[_unit, [_unit] call EFUNC(common,getDeathAnim), 1, true] call EFUNC(common,doAnimation);
_args set [5, false];
};
};
if (!local _unit) exitWith {
TRACE_6("ACE_DEBUG_Unconscious_PFH",_unit, _args, _startingTime, _minWaitingTime, _idPFH, _unit getVariable QGVAR(unconsciousArguments));
_args set [3, _minWaitingTime - (CBA_missionTime - _startingTime)];
_unit setVariable [QGVAR(unconsciousArguments), _args, true];
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
// Ensure we are waiting at least a minimum period before checking if we can wake up the unit again, allows for temp knock outs
if ((CBA_missionTime - _startingTime) >= _minWaitingTime) exitWith {
TRACE_2("ACE_DEBUG_Unconscious_Temp knock outs",_unit, [_unit] call FUNC(getUnconsciousCondition));
if (!([_unit] call FUNC(getUnconsciousCondition))) then {
_unit setVariable ["ACE_isUnconscious", false, true];
};
};

View File

@ -0,0 +1,156 @@
/*
* Author: Glowbal
* Updates the vitals. Is expected to be called every second.
*
* Arguments:
* 0: The Unit <OBJECT>
*
* ReturnValue:
* <NIL>
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_interval"];
TRACE_3("ACE_DEBUG",_unit,_interval,_unit);
if (_interval == 0) exitWith {};
private _lastTimeValuesSynced = _unit getVariable [QGVAR(lastMomentValuesSynced), 0];
private _syncValues = (CBA_missionTime - _lastTimeValuesSynced >= (10 + floor(random(10))) && GVAR(keepLocalSettingsSynced));
if (_syncValues) then {
_unit setVariable [QGVAR(lastMomentValuesSynced), CBA_missionTime];
};
private _bloodVolume = (_unit getVariable [QGVAR(bloodVolume), 100]) + ([_unit] call FUNC(getBloodVolumeChange));
_bloodVolume = _bloodVolume max 0;
_unit setVariable [QGVAR(bloodVolume), _bloodVolume, _syncValues];
TRACE_3("ACE_DEBUG",_bloodVolume,_syncValues,_unit);
// Set variables for synchronizing information across the net
if (_bloodVolume < 100) then {
if (_bloodVolume < 90) then {
TRACE_4("ACE_DEBUG",_bloodVolume,_unit getVariable QGVAR(hasLostBlood),_syncValues,_unit);
if (_unit getVariable [QGVAR(hasLostBlood), 0] != 2) then {
_unit setVariable [QGVAR(hasLostBlood), 2, true];
};
} else {
TRACE_4("ACE_DEBUG", _bloodVolume,_unit getVariable QGVAR(hasLostBlood),_syncValues,_unit);
if (_unit getVariable [QGVAR(hasLostBlood), 0] != 1) then {
_unit setVariable [QGVAR(hasLostBlood), 1, true];
};
};
} else {
TRACE_4("ACE_DEBUG",_bloodVolume,_unit getVariable QGVAR(hasLostBlood),_syncValues,_unit);
if (_unit getVariable [QGVAR(hasLostBlood), 0] != 0) then {
_unit setVariable [QGVAR(hasLostBlood), 0, true];
};
};
TRACE_3("ACE_DEBUG",[_unit] call FUNC(getBloodLoss),_unit getVariable QGVAR(isBleeding),_unit);
if (([_unit] call FUNC(getBloodLoss)) > 0) then {
if !(_unit getVariable [QGVAR(isBleeding), false]) then {
_unit setVariable [QGVAR(isBleeding), true, true];
};
} else {
if (_unit getVariable [QGVAR(isBleeding), false]) then {
_unit setVariable [QGVAR(isBleeding), false, true];
};
};
private _painStatus = _unit getVariable [QGVAR(pain), 0];
TRACE_4("ACE_DEBUG",_painStatus,_unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(painSuppress),_unit);
if (_painStatus > (_unit getVariable [QGVAR(painSuppress), 0])) then {
if !(_unit getVariable [QGVAR(hasPain), false]) then {
_unit setVariable [QGVAR(hasPain), true, true];
};
} else {
if (_unit getVariable [QGVAR(hasPain), false]) then {
_unit setVariable [QGVAR(hasPain), false, true];
};
};
if (_bloodVolume < 30) exitWith {
[_unit] call FUNC(setDead);
};
if ([_unit] call EFUNC(common,isAwake)) then {
if (_bloodVolume < 60) then {
if (random(1) > 0.9) then {
[_unit, true, 15 + random(20)] call FUNC(setUnconscious);
};
};
};
if (GVAR(level) == 1) then {
TRACE_5("ACE_DEBUG_BASIC_VITALS",_painStatus,_unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit);
// reduce pain
if (_painStatus > 0) then {
_unit setVariable [QGVAR(pain), (_painStatus - 0.001 * _interval) max 0, _syncValues];
};
// reduce painkillers
if (_unit getVariable [QGVAR(morphine), 0] > 0) then {
_unit setVariable [QGVAR(morphine), ((_unit getVariable [QGVAR(morphine), 0]) - 0.0015 * _interval) max 0, _syncValues];
};
};
// handle advanced medical, with vitals
if (GVAR(level) >= 2) then {
TRACE_6("ACE_DEBUG_ADVANCED_VITALS",_painStatus,_bloodVolume, _unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit);
// Handle pain due tourniquets, that have been applied more than 120 s ago
private _oldTourniquets = (_unit getVariable [QGVAR(tourniquets), []]) select {_x > 0 && {CBA_missionTime - _x > 120}};
// Increase pain at a rate of 0.001 units/s per old tourniquet
_painStatus = _painStatus + (count _oldTourniquets) * 0.001 * _interval;
// Set the vitals
private _heartRate = (_unit getVariable [QGVAR(heartRate), 80]) + (([_unit] call FUNC(getHeartRateChange)) * _interval);
_unit setVariable [QGVAR(heartRate), _heartRate max 0, _syncValues];
private _bloodPressure = [_unit] call FUNC(getBloodPressure);
_unit setVariable [QGVAR(bloodPressure), _bloodPressure, _syncValues];
_painReduce = [0.001, 0.002] select (_painStatus > 5);
// @todo: replace this and the rest of the setVariable with EFUNC(common,setApproximateVariablePublic)
_unit setVariable [QGVAR(pain), (_painStatus - _painReduce * _interval) max 0, _syncValues];
TRACE_8("ACE_DEBUG_ADVANCED_VITALS",_painStatus,_painReduce,_heartRate,_bloodVolume,_bloodPressure,_interval,_syncValues,_unit);
// Check vitals for medical status
// TODO check for in revive state instead of variable
_bloodPressure params ["_bloodPressureL", "_bloodPressureH"];
if (!(_unit getVariable [QGVAR(inCardiacArrest),false])) then {
if (_heartRate < 10 || _bloodPressureH < 30 || _bloodVolume < 20) then {
[_unit, true, 10+ random(20)] call FUNC(setUnconscious); // safety check to ensure unconsciousness for units if they are not dead already.
};
if ((_bloodPressureH > 260)
|| {_bloodPressureL < 40 && ({_heartRate > 190})}
|| {(_bloodPressureH > 145 && {_heartRate > 150})}) then {
if (random(1) > 0.7) then {
[_unit] call FUNC(setCardiacArrest);
};
};
if (_heartRate > 200 || (_heartRate < 20)) then {
[_unit] call FUNC(setCardiacArrest);
};
};
// syncing any remaining values
if (_syncValues) then {
TRACE_3("ACE_DEBUG_IVBAGS_SYNC",GVAR(IVBags),_syncValues,_unit);
{
private "_value";
_value = _unit getVariable _x;
if !(isNil "_value") then {
_unit setVariable [_x,(_unit getVariable [_x, 0]), true];
};
} forEach GVAR(IVBags);
};
};

View File

@ -0,0 +1,81 @@
/*
* Author: Glowbal
* Play the injured sound for a unit if the unit is damaged. The sound broadcasted across MP.
* Will not play if the unit has already played a sound within to close a time frame.
* Delay: With minimal damage (below 1), the delay is (10 + random(50)) seconds. Otherwise it is 60 seconds / damage.
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Amount of Pain <NUMBER>
*
* ReturnValue:
* None
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_pain"];
if (!local _unit || !GVAR(enableScreams)) exitWith{};
// Lock if the unit is already playing a sound.
if ((_unit getVariable [QGVAR(playingInjuredSound),false])) exitWith {};
_unit setVariable [QGVAR(playingInjuredSound),true];
// Play the sound if there is any damage present.
if (_pain > 0 && {[_unit] call EFUNC(common,isAwake)}) exitWith {
// Classnames of the available sounds.
private _availableSounds_A = [
"WoundedGuyA_01",
"WoundedGuyA_02",
"WoundedGuyA_03",
"WoundedGuyA_04",
"WoundedGuyA_05",
"WoundedGuyA_06",
"WoundedGuyA_07",
"WoundedGuyA_08"
];
private _availableSounds_B = [
"WoundedGuyB_01",
"WoundedGuyB_02",
"WoundedGuyB_03",
"WoundedGuyB_04",
"WoundedGuyB_05",
"WoundedGuyB_06",
"WoundedGuyB_07",
"WoundedGuyB_08"
];
private _availableSounds_C = [
"WoundedGuyC_01",
"WoundedGuyC_02",
"WoundedGuyC_03",
"WoundedGuyC_04",
"WoundedGuyC_05"
];
private _sound = "";
// Select the to be played sound based upon damage amount.
if (_pain > 0.5) then {
if (random(1) > 0.5) then {
_sound = selectRandom _availableSounds_A;
} else {
_sound = selectRandom _availableSounds_B;
};
} else {
_sound = selectRandom _availableSounds_B;
};
// Play the sound
playSound3D [(getArray(configFile >> "CfgSounds" >> _sound >> "sound") select 0) + ".wss", objNull, false, getPos _unit, 15, 1, 25]; // +2db, 15 meters.
// Figure out what the delay will be before it is possible to play a sound again.
private _delay = (30 - (random(25) * _pain)) max (3.5 + random(2));
// Clean up the lock
[{
(_this select 0) setVariable [QGVAR(playingInjuredSound), nil];
}, [_unit], _delay, _delay] call CBA_fnc_waitAndExecute;
};
// Clean up in case there has not been played any sounds.
_unit setVariable [QGVAR(playingInjuredSound), nil];

View File

@ -1,7 +1,7 @@
#include "script_component.hpp" #include "script_component.hpp"
// Delay between state runs // Delay between state runs
#define DELAY 10 #define DELAY 1
#define DEFAULT_STATE [0, "Default", {}, {}, {}, []] #define DEFAULT_STATE [0, "Default", {}, {}, {}, []]
GVAR(monitoredUnitsList) = []; GVAR(monitoredUnitsList) = [];
@ -30,7 +30,7 @@ GVAR(monitoredUnitsListIsSorted) = false;
_unit setvariable [QGVAR(state), _unitState]; _unit setvariable [QGVAR(state), _unitState];
[_unit, _name] call _handler; [_unit, _name, _lastTime] call _handler;
} else { } else {
_delete = true; _delete = true;
GVAR(monitoredUnitsList) set [_forEachIndex, objNull]; GVAR(monitoredUnitsList) set [_forEachIndex, objNull];