diff --git a/addons/medical/ACE_Settings.hpp b/addons/medical/ACE_Settings.hpp index 83496ab255..5522b9e32b 100644 --- a/addons/medical/ACE_Settings.hpp +++ b/addons/medical/ACE_Settings.hpp @@ -257,11 +257,6 @@ class ACE_Settings { typeName = "BOOL"; value = 0; }; - class GVAR(moveUnitsFromGroupOnUnconscious) { - category = CSTRING(Category_Medical); - typeName = "BOOL"; - value = 0; - }; class GVAR(menuTypeStyle) { category = CSTRING(Category_Medical); displayName = CSTRING(menuTypeDisplay); diff --git a/addons/medical/functions/fnc_getBloodLoss.sqf b/addons/medical/functions/fnc_getBloodLoss.sqf index 1a7e3968d8..ef2447edb8 100644 --- a/addons/medical/functions/fnc_getBloodLoss.sqf +++ b/addons/medical/functions/fnc_getBloodLoss.sqf @@ -10,19 +10,17 @@ * * Public: No */ - #include "script_component.hpp" -// TODO Only use this calculation if medium or higher, otherwise use vanilla calculations (for basic medical). params ["_unit"]; private _totalBloodLoss = 0; private _tourniquets = _unit getVariable [QGVAR(tourniquets), [0,0,0,0,0,0]]; + { - if ((_tourniquets select (_x select 2)) == 0) then { + if (_tourniquets select (_x select 2) == 0) then { // total bleeding ratio * percentage of injury left _totalBloodLoss = _totalBloodLoss + ((_x select 4) * (_x select 3)); - // (((BLOODLOSS_SMALL_WOUNDS * (_x select 0))) + ((BLOODLOSS_MEDIUM_WOUNDS * (_x select 1))) + ((BLOODLOSS_LARGE_WOUNDS * (_x select 2))) * (_cardiacOutput / DEFAULT_CARDIAC_OUTPUT)); }; } forEach (_unit getVariable [QGVAR(openWounds), []]); diff --git a/addons/medical/functions/fnc_getBloodVolumeChange.sqf b/addons/medical/functions/fnc_getBloodVolumeChange.sqf index 321e4639f5..1d48c9916d 100644 --- a/addons/medical/functions/fnc_getBloodVolumeChange.sqf +++ b/addons/medical/functions/fnc_getBloodVolumeChange.sqf @@ -11,29 +11,33 @@ * * Public: No */ - #include "script_component.hpp" params ["_unit", "_syncValues"]; private _bloodVolume = _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]; -private _bloodVolumeChange = -([_unit] call FUNC(getBloodLoss)); +private _bloodVolumeChange = -(_unit call FUNC(getBloodLoss)); if (!isNil {_unit getVariable QGVAR(ivBags)}) then { - if (_bloodVolume < 100) then { + if (_bloodVolume < DEFAULT_BLOOD_VOLUME) then { private _bloodBags = _unit getVariable [QGVAR(ivBags), []]; + _bloodBags = _bloodBags apply { _x params ["_bagVolumeRemaining"]; + private _bagChange = IV_CHANGE_PER_SECOND min _bagVolumeRemaining; // absolute value of the change in miliLiters _bagVolumeRemaining = _bagVolumeRemaining - _bagChange; - _bloodVolumeChange = _bloodVolumeChange + _bagChange; + _bloodVolumeChange = _bloodVolumeChange + (_bagChange / 1000); + if (_bagVolumeRemaining < 0.01) then { [] } else { [_bagVolumeRemaining]; }; }; + _bloodBags = _bloodBags - [[]]; // remove empty bags + if (_bloodBags isEqualTo []) then { _unit setVariable [QGVAR(ivBags), nil, true]; // no bags left - clear variable (always globaly sync this) } else { @@ -44,4 +48,4 @@ if (!isNil {_unit getVariable QGVAR(ivBags)}) then { }; }; -_bloodVolumeChange; +_bloodVolumeChange diff --git a/addons/medical/functions/fnc_handleUnitVitals.sqf b/addons/medical/functions/fnc_handleUnitVitals.sqf index 6ff9ed6d98..54f7682ee6 100644 --- a/addons/medical/functions/fnc_handleUnitVitals.sqf +++ b/addons/medical/functions/fnc_handleUnitVitals.sqf @@ -14,16 +14,18 @@ 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)); +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), DEFAULT_BLOOD_VOLUME]) + ([_unit, _syncValues] call FUNC(getBloodVolumeChange)); -_bloodVolume = _bloodVolume max 0; +_bloodVolume = (_bloodVolume max 0) min DEFAULT_BLOOD_VOLUME; _unit setVariable [QGVAR(bloodVolume), _bloodVolume, _syncValues]; @@ -45,12 +47,13 @@ if (_bloodVolume < BLOOD_VOLUME_HAS_LOST_SOME) then { }; }; -TRACE_3("ACE_DEBUG",[_unit] call FUNC(getBloodLoss),_unit getVariable QGVAR(isBleeding),_unit); -private _bloodLoss = [_unit] call FUNC(getBloodLoss); +private _bloodLoss = _unit call FUNC(getBloodLoss); +TRACE_3("ACE_DEBUG",_bloodLoss,_unit getVariable QGVAR(isBleeding),_unit); if (_bloodLoss > 0) then { _unit setVariable [QGVAR(bloodloss), _bloodLoss, _syncValues]; [_unit, "TakenInjury"] call FUNC(stateEvent); + if !(_unit getVariable [QGVAR(isBleeding), false]) then { _unit setVariable [QGVAR(isBleeding), true, true]; }; @@ -77,13 +80,12 @@ if (_bloodVolume < BLOOD_VOLUME_DEAD) exitWith { }; if ([_unit] call EFUNC(common,isAwake)) then { - if (_bloodVolume < BLOOD_VOLUME_UNCONSCIOUS) then { - if (random(1) > 0.9) then { - [_unit, true, 15 + random(20)] call FUNC(setUnconscious); - }; + if (_bloodVolume < BLOOD_VOLUME_UNCONSCIOUS && {random 1 < BLOOD_LOSS_KNOCK_OUT_CHANCE}) exitWith { + [_unit, true, BLOOD_LOSS_KNOCK_OUT_DURATION] 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 @@ -96,8 +98,10 @@ if (GVAR(level) == 1) 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); @@ -142,3 +146,4 @@ if (GVAR(level) >= 2) then { }; }; }; +*/ diff --git a/addons/medical/functions/fnc_setUnconscious.sqf b/addons/medical/functions/fnc_setUnconscious.sqf index 369ca894d2..55e108efef 100644 --- a/addons/medical/functions/fnc_setUnconscious.sqf +++ b/addons/medical/functions/fnc_setUnconscious.sqf @@ -9,7 +9,7 @@ * 3: Force AI Unconscious (skip random death chance) (default: false) * * ReturnValue: - * nil + * Success? * * Example: * [bob, true] call ace_medical_fnc_setUnconscious; @@ -19,36 +19,43 @@ #include "script_component.hpp" -#define DEFAULT_DELAY (round(random(10)+5)) - // only run this after the settings are initialized if !(EGVAR(common,settingsInitFinished)) exitWith { EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(setUnconscious), _this]; }; -params ["_unit", ["_set", true], ["_minUnconsciousTime", DEFAULT_DELAY], ["_force", false]]; +params ["_unit", ["_knockOut", true], ["_minUnconsciousTime", DEFAULT_KNOCK_OUT_DELAY], ["_force", false]]; -if (_set isEqualTo (_unit getVariable ["ACE_isUnconscious", false])) exitWith {}; +if (isNull _unit || {!(_unit isKindOf "CAManBase")}) exitWith {false}; -if !(_set) exitWith { - _unit setVariable ["ACE_isUnconscious", false, true]; +if (!local _unit) exitWith { + [QGVAR(setUnconscious), [_unit, _knockOut, _minUnconsciousTime, _force], _unit] call CBA_fnc_targetEvent; + true +}; + +// use maximum for wake up time +if (_knockOut) then { + _unit setVariable [QGVAR(wakeUpTime), (CBA_missionTime + _minUnconsciousTime) max (_unit getVariable [QGVAR(wakeUpTime), 0])]; +}; + +if (_knockOut isEqualTo (_unit getVariable [QGVAR(isUnconscious), false])) exitWith {false}; + +// --- wake up +if !(_knockOut) exitWith { + _unit setVariable [QGVAR(isUnconscious), false, true]; if (_unit getVariable [QGVAR(inReviveState), false]) then { _unit setVariable [QGVAR(inReviveState), nil, true]; }; [_unit, false] call EFUNC(medical_engine,setUnconsciousAnim); - ["ace_unconscious", [_unit, false]] call CBA_fnc_globalEvent; + + true }; -if (isNull _unit || {!(_unit isKindOf "CAManBase")}) exitWith {}; - -if (!local _unit) exitWith { - [QGVAR(setUnconscious), [_unit, _set, _minUnconsciousTime, _force], _unit] call CBA_fnc_targetEvent; -}; - -_unit setVariable ["ACE_isUnconscious", true, true]; +// --- knock out +_unit setVariable [QGVAR(isUnconscious), true, true]; if (_unit == ACE_player) then { if (visibleMap) then {openMap false}; @@ -59,6 +66,7 @@ if (_unit == ACE_player) then { }; // if we have unconsciousness for AI disabled, we will kill the unit instead +/* private _isDead = false; if (!([_unit, GVAR(remoteControlledAI)] call EFUNC(common,isPlayer)) && !_force) then { @@ -71,37 +79,25 @@ if (!([_unit, GVAR(remoteControlledAI)] call EFUNC(common,isPlayer)) && !_force) }; if (_isDead) exitWith {}; +*/ -// 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); -}; +[_unit, true] call EFUNC(medical_engine,setUnconsciousAnim); +[_unit, "Unconscious", []] call FUNC(stateEvent); +["ace_unconscious", [_unit, true]] call CBA_fnc_globalEvent; -// Delay Unconscious so the AI dont instant stop shooting on the unit #3121 +// auto wake up [{ params ["_unit"]; - if (_unit getVariable ["ACE_isUnconscious", false]) then { - [_unit, "setCaptive", "ace_unconscious", true] call EFUNC(common,statusEffect_set); - }; -}, _unit, 3] call CBA_fnc_waitAndExecute; + private _time = _unit getVariable [QGVAR(wakeUpTime), 0]; -[_unit, true] call EFUNC(medical_engine,setUnconsciousAnim); - -[_unit, "Unconscious", []] call FUNC(stateEvent); - -["ace_unconscious", [_unit, true]] call CBA_fnc_globalEvent; - -// auto wake up, testing @todo -[{ - params ["_unit", "_time"]; - - !(_unit getVariable ["ACE_isUnconscious", false]) || {CBA_missionTime > _time} + !(_unit getVariable [QGVAR(isUnconscious), false]) || {CBA_missionTime > _time} }, { params ["_unit"]; - if (_unit getVariable ["ACE_isUnconscious", false]) then { + if (_unit getVariable [QGVAR(isUnconscious), false]) then { [_unit, false] call FUNC(setUnconscious); }; -}, [_unit, CBA_missionTime + _minUnconsciousTime]] call CBA_fnc_waitUntilAndExecute; +}, _unit] call CBA_fnc_waitUntilAndExecute; + +true diff --git a/addons/medical/script_macros_medical.hpp b/addons/medical/script_macros_medical.hpp index ec89dd39fc..e8132a9c8a 100644 --- a/addons/medical/script_macros_medical.hpp +++ b/addons/medical/script_macros_medical.hpp @@ -19,14 +19,22 @@ // 0.077 l/kg * 80kg = 6.16l #define DEFAULT_BLOOD_VOLUME 6.0 // in liters -#define BLOOD_VOLUME_HAS_LOST_SOME 5.900 // lost 100ml -#define BLOOD_VOLUME_HAS_LOST_MUCH 5.500 // lost 500ml +#define BLOOD_VOLUME_HAS_LOST_SOME 5.700 // lost 5% blood, Class I Hemorrhage +#define BLOOD_VOLUME_HAS_LOST_MUCH 5.100 // lost 15% blood, Class II Hemorrhage -#define BLOOD_VOLUME_UNCONSCIOUS 3.6 // in liters -#define BLOOD_VOLUME_DEAD 1.8 // in liters -#define BLOOD_VOLUME_CARDIAC_ARREST 1.2 // in liters +#define BLOOD_VOLUME_UNCONSCIOUS 4.200 // lost 30% blood, Class III Hemorrhage +#define BLOOD_VOLUME_DEAD 3.600 // lost 40% blood, Class IV Hemorrhage +#define BLOOD_VOLUME_CARDIAC_ARREST 1.2 // TBD // IV Change per second calculation: -// 250ml should take 60 seconds to fill. 250/60 = 4.166. -// Basic medical is 10x (will take 6 seconds for 250ml) -#define IV_CHANGE_PER_SECOND ([41.66, 4.166] select (GVAR(level) >= 2)) +// 250ml should take 60 seconds to fill. 250ml/60s = 4.166ml/s. +#define IV_CHANGE_PER_SECOND 4.166 // in milliliters per second + +// chance per second to get knocked out due to blood loss +#define BLOOD_LOSS_KNOCK_OUT_CHANCE 0.1 // 10% + +// duration in seconds to stay knocked out due to blood loss +#define BLOOD_LOSS_KNOCK_OUT_DURATION (15 + random 20) + +// --- unconsciousness +#define DEFAULT_KNOCK_OUT_DELAY (5 + random 10) diff --git a/addons/medical_engine/functions/fnc_setUnconsciousAnim.sqf b/addons/medical_engine/functions/fnc_setUnconsciousAnim.sqf index b52948a9c4..fd60902729 100644 --- a/addons/medical_engine/functions/fnc_setUnconsciousAnim.sqf +++ b/addons/medical_engine/functions/fnc_setUnconsciousAnim.sqf @@ -50,6 +50,6 @@ if (_isUnconscious) then { if (animationState _unit == "unconscious" && {lifeState _unit != "INCAPACITATED"}) then { [_unit, "AmovPpneMstpSnonWnonDnon", 2] call EFUNC(common,doAnimation); }; - }, _unit] call CBA_fnc_execNextFrame; + }, _unit, 0.5] call CBA_fnc_waitAndExecute; }; }; diff --git a/addons/medical_treatment/ACE_Medical_Treatment.hpp b/addons/medical_treatment/ACE_Medical_Treatment.hpp index 94a1796aa1..2fcbcc7d19 100644 --- a/addons/medical_treatment/ACE_Medical_Treatment.hpp +++ b/addons/medical_treatment/ACE_Medical_Treatment.hpp @@ -1,5 +1,5 @@ -class ACE_Medical_Treatment { +class ADDON { class Bandaging { // Field dressing is normal average treatment // packing bandage is average treatment, higher reopen change, longer reopening delay diff --git a/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp b/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp index c9652beeb2..d7ddf1d329 100644 --- a/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp +++ b/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp @@ -54,7 +54,7 @@ class GVAR(Actions) { treatmentLocations[] = {QGVAR(useLocation_basicEpi)}; }; class BloodIV: Bandage { - displayName = ECSTRING(medical,Transfuse_Blood); + displayName = ECSTRING(medical,Actions_Blood4_1000); displayNameProgress = ECSTRING(medical,Transfusing_Blood); allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"}; allowSelfTreatment = 0; @@ -62,17 +62,16 @@ class GVAR(Actions) { requiredMedic = 1; treatmentTime = 12; items[] = {"ACE_bloodIV"}; - callbackSuccess = QFUNC(treatmentBloodbag); - // callbackSuccess = QFUNC(treatmentIV); + callbackSuccess = QFUNC(treatmentIV); animationCaller = "AinvPknlMstpSnonWnonDnon_medic1"; litter[] = {}; }; class BloodIV_500: BloodIV { - category = "advanced"; + displayName = ECSTRING(medical,Actions_Blood4_500); items[] = {"ACE_bloodIV_500"}; }; class BloodIV_250: BloodIV { - category = "advanced"; + displayName = ECSTRING(medical,Actions_Blood4_250); items[] = {"ACE_bloodIV_250"}; }; class BodyBag: Bandage { diff --git a/addons/medical_treatment/XEH_postInit.sqf b/addons/medical_treatment/XEH_postInit.sqf index e3020fd5c6..c6a8078ea7 100644 --- a/addons/medical_treatment/XEH_postInit.sqf +++ b/addons/medical_treatment/XEH_postInit.sqf @@ -12,7 +12,6 @@ if (isServer) then { [QGVAR(treatmentMorphineLocal), FUNC(treatmentMorphineLocal)] call CBA_fnc_addEventHandler; //[QGVAR(treatmentEpipenLocal), FUNC(treatmentEpipenLocal)] call CBA_fnc_addEventHandler; [QGVAR(treatmentMedicationLocal), FUNC(treatmentMedicationLocal)] call CBA_fnc_addEventHandler; -[QGVAR(treatmentBloodbagLocal), FUNC(treatmentBloodbagLocal)] call CBA_fnc_addEventHandler; [QGVAR(treatmentIVLocal), FUNC(treatmentIVLocal)] call CBA_fnc_addEventHandler; [QGVAR(treatmentCPRLocal), FUNC(treatmentCPRLocal)] call CBA_fnc_addEventHandler; [QGVAR(treatmentFullHealLocal), FUNC(treatmentFullHealLocal)] call CBA_fnc_addEventHandler; diff --git a/addons/medical_treatment/functions/fnc_treatmentIVLocal.sqf b/addons/medical_treatment/functions/fnc_treatmentIVLocal.sqf index 6324abd126..de4ec719bb 100644 --- a/addons/medical_treatment/functions/fnc_treatmentIVLocal.sqf +++ b/addons/medical_treatment/functions/fnc_treatmentIVLocal.sqf @@ -22,18 +22,25 @@ private _bloodVolume = _target getVariable [QEGVAR(medical,bloodVolume), DEFAULT if (_bloodVolume >= DEFAULT_BLOOD_VOLUME) exitWith {}; // Find the proper attributes for the used IV -private _config = (configFile >> "ace_medical_treatment" >> "IV"); +private _config = configFile >> QUOTE(ADDON) >> "IV"; private _volumeAdded = getNumber (_config >> "volume"); -private _typeOf = getText (_config >> "type"); +private _type = getText (_config >> "type"); if (isClass (_config >> _treatmentClassname)) then { - _config = (_config >> _treatmentClassname); - if (isNumber (_config >> "volume")) then { _volumeAdded = getNumber (_config >> "volume");}; - if (isText (_config >> "type")) then { _typeOf = getText (_config >> "type"); }; + _config = _config >> _treatmentClassname; + + if (isNumber (_config >> "volume")) then { + _volumeAdded = getNumber (_config >> "volume"); + }; + + if (isText (_config >> "type")) then { + _type = getText (_config >> "type"); + }; } else { ERROR("IV Treatment Classname not found"); }; private _bloodBags = _target getVariable [QEGVAR(medical,ivBags), []]; -_bloodBags pushBack [_volumeAdded]; // Future BagType: [_volumeAdded, _typeOf] +_bloodBags pushBack [_volumeAdded]; // Future BagType: [_volumeAdded, _type] + _target setVariable [QEGVAR(medical,ivBags), _bloodBags, true];