Merge pull request #3462 from acemod/medicalLoops

Cleanup medical PFHs
This commit is contained in:
Glowbal 2016-05-14 09:39:14 +02:00
commit 180a0f9d84
18 changed files with 276 additions and 165 deletions

View File

@ -16,7 +16,9 @@ PREP(addToLog);
PREP(addToTriageCard);
PREP(addUnconsciousCondition);
PREP(addUnloadPatientActions);
PREP(addVitalLoop);
PREP(adjustPainLevel);
PREP(bodyCleanupLoop);
PREP(canAccessMedicalEquipment);
PREP(canTreat);
PREP(canTreatCached);
@ -56,12 +58,14 @@ PREP(isMedic);
PREP(isMedicalVehicle);
PREP(isInStableCondition);
PREP(itemCheck);
PREP(medicationEffectLoop);
PREP(modifyMedicalAction);
PREP(onMedicationUsage);
PREP(onWoundUpdateRequest);
PREP(onPropagateWound);
PREP(parseConfigForInjuries);
PREP(playInjuredSound);
PREP(reviveStateLoop);
PREP(selectionNameToNumber);
PREP(serverRemoveBody);
PREP(setCardiacArrest);
@ -96,6 +100,7 @@ PREP(treatmentTourniquet);
PREP(treatmentTourniquetLocal);
PREP(useItem);
PREP(useItems);
PREP(vitalLoop);
PREP(displayPatientInformation);
PREP(displayTriageCard);
PREP(dropDownTriageCard);
@ -113,3 +118,4 @@ PREP(unconsciousPFH);
// Networked litter
PREP(createLitter);
PREP(handleCreateLitter);
PREP(litterCleanupLoop);

View File

@ -8,52 +8,10 @@
* ReturnValue:
* None
*
* Public: Yes
* Deprecated
*/
#include "script_component.hpp"
params ["_unit", ["_force", false]];
ACE_DEPRECATED("ace_medical_fnc_addToInjuredCollection","3.7.0","ace_medical_fnc_addVitalLoop");
if ([_unit] call FUNC(hasMedicalEnabled) || _force) then {
if !(local _unit) exitWith {
["addToInjuredCollection", _unit, [_unit, _force]] call EFUNC(common,targetEvent);
};
if ((_unit getVariable[QGVAR(addedToUnitLoop),false] || !alive _unit) && !_force) exitWith{};
_unit setVariable [QGVAR(addedToUnitLoop), true, true];
[{
params ["_args", "_idPFH"];
_args params ["_unit", "_interval"];
_interval = ACE_time - _interval;
(_this select 0) set [1, ACE_time];
if (!alive _unit || !local _unit) then {
[_idPFH] call CBA_fnc_removePerFrameHandler;
if (!local _unit) then {
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];
};
} else {
[_unit, _interval] call FUNC(handleUnitVitals);
private "_pain";
_pain = _unit getVariable [QGVAR(pain), 0];
if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then {
// This introduces wierd unconscious behaviour for basic medical and possibly also advanced.
// TODO This is disabled as it's considered non critical code.
// We will need to decide if we want unconscious triggered on high pain levels or if we can get rid of this entirely.
/*if (_pain > 0.7 && {random(1) > 0.6}) then {
[_unit] call FUNC(setUnconscious);
};*/
[_unit, _pain] call FUNC(playInjuredSound);
};
};
}, 1, [_unit, ACE_time]] call CBA_fnc_addPerFrameHandler;
};
_this call FUNC(addVitalLoop);

View File

@ -0,0 +1,30 @@
/*
* Author: Glowbal
* Enabled the vitals loop for a unit.
*
* Arguments:
* 0: The Unit <OBJECT>
*
* ReturnValue:
* None
*
* Public: Yes
*/
#include "script_component.hpp"
params ["_unit", ["_force", false]];
if !([_unit] call FUNC(hasMedicalEnabled) || _force) exitWith {};
if !(local _unit) exitWith {
["addVitalLoop", _unit, [_unit, _force]] call EFUNC(common,targetEvent);
};
// Quit if the unit already has a vital loop, or is dead, unless it's forced
if ((_unit getVariable[QGVAR(addedToUnitLoop),false] || !alive _unit) && !_force) exitWith{};
// Schedule the loop to be executed again 1 sec later
// @todo: should the loop be started righ away instead?
_unit setVariable [QGVAR(addedToUnitLoop), true, true];
[DFUNC(vitalLoop), [_unit, ACE_time], 1] call EFUNC(common,waitAndExecute);

View File

@ -35,6 +35,6 @@ _pain = _pain max 0;
_unit setVariable [QGVAR(pain), _pain];
//Start up the vital watching (if not already running)
[_unit] call FUNC(addToInjuredCollection);
[_unit] call FUNC(addVitalLoop);
_pain

View File

@ -0,0 +1,30 @@
/*
* Author: Glowbal, esteldunedain
* Loop that cleans up litter
*
* Arguments:
* None
*
* ReturnValue:
* None
*
* Public: No
*/
#include "script_component.hpp"
{
TRACE_2("body",_x,isPlayer _x);
if ((!isNull _x) && {!isPlayer _x}) then {deleteVehicle _x};
} forEach GVAR(bodiesToDelete);
// deleteVehicle doesn't have instant results so it won't usualy be filtered until next run
GVAR(bodiesToDelete) = GVAR(bodiesToDelete) - [objNull];
// If no more bodies remain, exit the loop
if (GVAR(bodiesToDelete) isEqualTo []) exitWith {
TRACE_1("array emptied - rem PFEH",GVAR(bodiesToDelete));
};
// Schedule the loop to be executed again 20 sec later
[DFUNC(bodyCleanupLoop), [], 20] call EFUNC(common,waitAndExecute);

View File

@ -44,22 +44,7 @@ if((count GVAR(allCreatedLitter)) > _maxLitterCount ) then {
GVAR(allCreatedLitter) pushBack [ACE_time, [_litterObject]];
if(!GVAR(litterPFHRunning) && {GVAR(litterCleanUpDelay) > 0}) then {
// Start the litter cleanup loop
GVAR(litterPFHRunning) = true;
[{
{
_x params ["_time", "_objects"];
if (ACE_time - _time >= GVAR(litterCleanUpDelay)) then {
{
deleteVehicle _x;
} forEach _objects;
GVAR(allCreatedLitter) set[_forEachIndex, objNull];
};
} forEach GVAR(allCreatedLitter);
GVAR(allCreatedLitter) = GVAR(allCreatedLitter) - [objNull];
if ( (count GVAR(allCreatedLitter)) == 0) exitWith {
[(_this select 1)] call CBA_fnc_removePerFrameHandler;
GVAR(litterPFHRunning) = false;
};
}, 30, []] call CBA_fnc_addPerFrameHandler;
call FUNC(litterCleanupLoop);
};

View File

@ -102,8 +102,8 @@ if ((_minLethalDamage <= _newDamage) && {[_unit, [_effectiveSelectionName] call
_damageReturn = _damageReturn min 0.89;
};
[_unit] call FUNC(addToInjuredCollection);
// Start the loop that tracks the unit vitals
[_unit] call FUNC(addVitalLoop);
if (_unit getVariable [QGVAR(preventInstaDeath), GVAR(preventInstaDeath)]) exitWith {
private _delayedUnconsicous = false;

View File

@ -17,8 +17,9 @@
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(addToInjuredCollection);
[_unit, true] call FUNC(addVitalLoop);
};
if ((_unit getVariable ["ACE_isUnconscious",false]) && {count (_unit getVariable [QGVAR(unconsciousArguments), []]) >= 6}) then {

View File

@ -110,6 +110,11 @@ if (GVAR(level) >= 2) then {
};
};
// 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
_heartRate = (_unit getVariable [QGVAR(heartRate), 80]) + (([_unit] call FUNC(getHeartRateChange)) * _interval);
_unit setVariable [QGVAR(heartRate), _heartRate max 0, _syncValues];
@ -117,10 +122,11 @@ if (GVAR(level) >= 2) then {
_bloodPressure = [_unit] call FUNC(getBloodPressure);
_unit setVariable [QGVAR(bloodPressure), _bloodPressure, _syncValues];
if (_painStatus > 0 && {_painStatus < 10}) then {
_painReduce = if (_painStatus > 5) then {0.002} else {0.001};
_unit setVariable [QGVAR(pain), (_painStatus - _painReduce * _interval) max 0, _syncValues];
};
_painReduce = if (_painStatus > 5) then {0.002} else {0.001};
// @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);
// TODO Disabled until implemented fully
// Handle airway

View File

@ -0,0 +1,33 @@
/*
* Author: Glowbal, esteldunedain
* Loop that cleans up litter
*
* Arguments:
* None
*
* ReturnValue:
* None
*
* Public: No
*/
#include "script_component.hpp"
{
_x params ["_time", "_objects"];
if (ACE_time - _time >= GVAR(litterCleanUpDelay)) then {
{
deleteVehicle _x;
} forEach _objects;
GVAR(allCreatedLitter) set[_forEachIndex, objNull];
};
} forEach GVAR(allCreatedLitter);
GVAR(allCreatedLitter) = GVAR(allCreatedLitter) - [objNull];
// If no more litter remaining, exit the loop
if ( (count GVAR(allCreatedLitter)) == 0) exitWith {
GVAR(litterPFHRunning) = false;
};
// Schedule the loop to be executed again 30 sec later
[DFUNC(litterCleanupLoop), [], 30] call EFUNC(common,waitAndExecute);

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 EFUNC(common,waitAndExecute);

View File

@ -77,22 +77,5 @@ if (_hasOverDosed > 0 && GVAR(enableOverdosing)) then {
_decreaseAmount = 1 / _timeInSystem;
_viscosityAdjustment = _viscosityChange / _timeInSystem;
[{
params ["_args", "_idPFH"];
_args params ["_target", "_timeInSystem", "_variable", "_amountDecreased","_decreaseAmount", "_viscosityAdjustment", "_painReduce"];
private "_usedMeds";
_usedMeds = _target getVariable [_variable, 0];
_usedMeds = _usedMeds - _decreaseAmount;
_target setVariable [_variable, _usedMeds];
_amountDecreased = _amountDecreased + _decreaseAmount;
// Restoring the viscosity while the medication is leaving the system
_target setVariable [QGVAR(peripheralResistance), ((_target getVariable [QGVAR(peripheralResistance), 100]) - _viscosityAdjustment) max 0];
_target setVariable [QGVAR(painSuppress), ((_target getVariable [QGVAR(painSuppress), 0]) - _painReduce) max 0];
if (_amountDecreased >= 1 || (_usedMeds <= 0) || !alive _target) then {
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
_args set [3, _amountDecreased];
}, 1, [_target, _timeInSystem, _variable, 0, _decreaseAmount, _viscosityAdjustment, _painReduce / _timeInSystem] ] call CBA_fnc_addPerFrameHandler;
// Run the loop that computes the effect of the medication over time
[_target, _variable, 0, _decreaseAmount, _viscosityAdjustment, _painReduce / _timeInSystem] call FUNC(medicationEffectLoop);

View File

@ -0,0 +1,56 @@
/*
* Author: Glowbal, esteldunedain
* Loop that handles a unit in the revive state.
*
* Arguments:
* 0: Unit <OBJECT>
*
* ReturnValue:
* None
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit"]
// If locality changed finish the local loop
// @todo: reinitiate the loop elsewhere
if (!local _unit) exitWith {};
private _startTime = _unit getVariable [QGVAR(reviveStartTime), 0];
// Remove heartbeat
if (GVAR(level) >= 2) then {
if (_unit getVariable [QGVAR(heartRate), 60] > 0) then {
_unit setVariable [QGVAR(heartRate), 0];
};
};
// If we are in revive state in a blown up vehicle, try to unload so that people can access the body
if ((alive _unit) && {(vehicle _unit) != _unit} && {!alive (vehicle _unit)}) then {
TRACE_2("Unloading", _unit, vehicle _unit);
[_unit] call EFUNC(common,unloadPerson);
};
// If the timer run out, let the unit die and exit the loop
if (GVAR(maxReviveTime) > 0 && {ACE_time - _startTime > GVAR(maxReviveTime)}) exitwith {
_unit setVariable [QGVAR(inReviveState), nil, true];
_unit setVariable [QGVAR(reviveStartTime), nil];
[_unit, true] call FUNC(setDead);
};
// If the unit was taken out from revive state, exit the loop
if !(_unit getVariable [QGVAR(inReviveState), false]) exitwith {
// Revived without dieing, so in case we have lifes, remove one.
if (GVAR(amountOfReviveLives) > 0) then {
_lifesLeft = _unit getVariable[QGVAR(amountOfReviveLives), GVAR(amountOfReviveLives)];
_unit setVariable [QGVAR(amountOfReviveLives), _lifesLeft - 1, true];
};
_unit setVariable [QGVAR(reviveStartTime), nil];
};
// Schedule the loop to be executed again 1 sec later
[DFUNC(reviveStateLoop), [_unit], 1] call EFUNC(common,waitAndExecute);

View File

@ -26,23 +26,9 @@ TRACE_2("",_target,isPlayer _target);
if (isNil QGVAR(bodiesToDelete)) then {GVAR(bodiesToDelete) = [];};
GVAR(bodiesToDelete) pushBack _target;
//Start up PFEH to wait for bodies to be free to delete
if ((count GVAR(bodiesToDelete)) == 1) then {
TRACE_1("starting PFEH",GVAR(bodiesToDelete));
[{
{
TRACE_2("body",_x,isPlayer _x);
if ((!isNull _x) && {!isPlayer _x}) then {deleteVehicle _x};
} forEach GVAR(bodiesToDelete);
//deleteVehicle doesn't have instant results so it won't usualy be filtered until next run
GVAR(bodiesToDelete) = GVAR(bodiesToDelete) - [objNull];
if (GVAR(bodiesToDelete) isEqualTo []) then {
TRACE_1("array emptied - rem PFEH",GVAR(bodiesToDelete));
[_this select 1] call CBA_fnc_removePerFrameHandler;
};
}, 20, []] call CBA_fnc_addPerFrameHandler;
// Start up a loop to wait for bodies to be free to delete
if ((count GVAR(bodiesToDelete)) > 0) then {
[] call FUNC(bodyCleanupLoop);
};
nil

View File

@ -41,41 +41,8 @@ if (((_reviveVal == 1 && {[_unit] call EFUNC(common,isPlayer)} || _reviveVal ==
_unit setVariable [QGVAR(reviveStartTime), ACE_time];
[_unit, true] call FUNC(setUnconscious);
[{
private "_startTime";
params ["_args", "_idPFH"];
_args params ["_unit"];
_startTime = _unit getVariable [QGVAR(reviveStartTime), 0];
//If we are in reivie state in a blown up vehicle, try to unload so that people can access the body
if ((alive _unit) && {(vehicle _unit) != _unit} && {!alive (vehicle _unit)}) then {
TRACE_2("Unloading", _unit, vehicle _unit);
[_unit] call EFUNC(common,unloadPerson);
};
if (GVAR(maxReviveTime) > 0 && {ACE_time - _startTime > GVAR(maxReviveTime)}) exitwith {
[_idPFH] call CBA_fnc_removePerFrameHandler;
_unit setVariable [QGVAR(inReviveState), nil, true];
_unit setVariable [QGVAR(reviveStartTime), nil];
[_unit, true] call FUNC(setDead);
};
if !(_unit getVariable [QGVAR(inReviveState), false]) exitwith {
// revived without dieing, so in case we have lifes, remove one.
if (GVAR(amountOfReviveLives) > 0) then {
_lifesLeft = _unit getVariable[QGVAR(amountOfReviveLives), GVAR(amountOfReviveLives)];
_unit setVariable [QGVAR(amountOfReviveLives), _lifesLeft - 1, true];
};
_unit setVariable [QGVAR(reviveStartTime), nil];
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
if (GVAR(level) >= 2) then {
if (_unit getVariable [QGVAR(heartRate), 60] > 0) then {
_unit setVariable [QGVAR(heartRate), 0];
};
};
}, 1, [_unit] ] call CBA_fnc_addPerFrameHandler;
// Run the loop that tracks the revive state
[_unit ] call FUNC(reviveStateLoop);
false;
};

View File

@ -16,32 +16,12 @@
private ["_tourniquets", "_part", "_applyingTo"];
params ["_target", "_tourniquetItem", "_selectionName"];
[_target] call FUNC(addToInjuredCollection);
//If we're not already tracking vitals, start:
[_target] call FUNC(addVitalLoop);
_part = [_selectionName] call FUNC(selectionNameToNumber);
// Place a tourniquet on the bodypart
_tourniquets = _target getVariable [QGVAR(tourniquets), [0,0,0,0,0,0]];
_applyingTo = (_tourniquets select _part) + 1 + round(random(100));
_tourniquets set[_part, _applyingTo];
_tourniquets set [_part, CBA_missionTime];
_target setVariable [QGVAR(tourniquets), _tourniquets, true];
[{
params ["_args", "_idPFH"];
_args params ["_target", "_applyingTo", "_part", "_time"];
if (!alive _target) exitWith {
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
_tourniquets = _target getVariable [QGVAR(tourniquets), [0,0,0,0,0,0]];
if !((_tourniquets select _part) == _applyingTo) exitWith {
// Tourniquet has been removed
[_idPFH] call CBA_fnc_removePerFrameHandler;
};
if (ACE_time - _time > 120) then {
_target setVariable [QGVAR(pain), (_target getVariable [QGVAR(pain), 0]) + 0.005];
};
}, 5, [_target, _applyingTo, _part, ACE_time] ] call CBA_fnc_addPerFrameHandler;
true

View File

@ -92,7 +92,7 @@ _args call FUNC(createLitter);
//If we're not already tracking vitals, start:
if (!(_target getVariable [QGVAR(addedToUnitLoop),false])) then {
[_target] call FUNC(addToInjuredCollection);
[_target] call FUNC(addVitalLoop);
};
["medical_treatmentSuccess", [_caller, _target, _selectionName, _className]] call EFUNC(common,localEvent);

View File

@ -0,0 +1,48 @@
/*
* Author: Glowbal, esteldunedain
* Vital loop for a unit.
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Time of last computation <NUMBER>
*
* ReturnValue:
* None
*
* Public: No
*/
#include "script_component.hpp"
params ["_unit", "_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];
};
// Handle unit vitals
[_unit, ACE_time - _lastTime] call FUNC(handleUnitVitals);
// Play injured sounds
private _pain = _unit getVariable [QGVAR(pain), 0];
if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then {
// This introduces wierd unconscious behaviour for basic medical and possibly also advanced.
// TODO This is disabled as it's considered non critical code.
// We will need to decide if we want unconscious triggered on high pain levels or if we can get rid of this entirely.
/*if (_pain > 0.7 && {random(1) > 0.6}) then {
[_unit] call FUNC(setUnconscious);
};*/
[_unit, _pain] call FUNC(playInjuredSound);
};
// Schedule the loop to be executed again 1 sec later
[DFUNC(vitalLoop), [_unit, ACE_time], 1] call EFUNC(common,waitAndExecute);