diff --git a/addons/arsenal/functions/fnc_verifyLoadout.sqf b/addons/arsenal/functions/fnc_verifyLoadout.sqf index e7ce4fe0a6..12509333bb 100644 --- a/addons/arsenal/functions/fnc_verifyLoadout.sqf +++ b/addons/arsenal/functions/fnc_verifyLoadout.sqf @@ -211,7 +211,7 @@ for "_dataIndex" from 0 to 9 do { }; case 9: { - for "_subIndex" from 0 to 4 do { + for "_subIndex" from 0 to 5 do { private _item = (_loadout select _dataIndex) select _subIndex; if (_item != "") then { diff --git a/addons/common/XEH_postInit.sqf b/addons/common/XEH_postInit.sqf index 5efc75b8df..fd2c12e2c5 100644 --- a/addons/common/XEH_postInit.sqf +++ b/addons/common/XEH_postInit.sqf @@ -19,8 +19,8 @@ //Status Effect EHs: [QGVAR(setStatusEffect), {_this call FUNC(statusEffect_set)}] call CBA_fnc_addEventHandler; -["forceWalk", false, ["ACE_SwitchUnits", "ACE_Attach", "ACE_dragging", "ACE_Explosives", "ACE_Ladder", "ACE_Sandbag", "ACE_refuel", "ACE_rearm", "ACE_Trenches"]] call FUNC(statusEffect_addType); -["blockSprint", false, []] call FUNC(statusEffect_addType); +["forceWalk", false, ["ace_advanced_fatigue", "ACE_SwitchUnits", "ACE_Attach", "ACE_dragging", "ACE_Explosives", "ACE_Ladder", "ACE_Sandbag", "ACE_refuel", "ACE_rearm", "ACE_Trenches"]] call FUNC(statusEffect_addType); +["blockSprint", false, ["ace_advanced_fatigue", "ace_medical_fracture"]] call FUNC(statusEffect_addType); ["setCaptive", true, [QEGVAR(captives,Handcuffed), QEGVAR(captives,Surrendered)]] call FUNC(statusEffect_addType); ["blockDamage", false, ["fixCollision", "ACE_cargo"]] call FUNC(statusEffect_addType); ["blockEngine", false, ["ACE_Refuel"]] call FUNC(statusEffect_addType); diff --git a/addons/common/functions/fnc_arithmeticGetResult.sqf b/addons/common/functions/fnc_arithmeticGetResult.sqf index 418d510d66..e54f44fd27 100644 --- a/addons/common/functions/fnc_arithmeticGetResult.sqf +++ b/addons/common/functions/fnc_arithmeticGetResult.sqf @@ -6,7 +6,7 @@ * Arguments: * 0: Namespace * 1: Number Set ID - * 2: Operation (sum, product, min, max, avg) + * 2: Operation (sum, product, min, max, avg) (Case Sensitive) * * Return Value: * Value @@ -19,11 +19,19 @@ */ params ["_namespace", "_setID", "_op"]; -TRACE_3("params",_namespace,_setID,_op); +TRACE_3("arithmeticGetResult",_namespace,_setID,_op); private _data = (_namespace getVariable _setID) param [2, []]; switch (_op) do { + case ("max"): { + private _result = -1e99; + { + _result = _result max (call _x); + nil + } count _data; + _result // return + }; case ("sum"): { private _result = 0; { @@ -48,14 +56,6 @@ switch (_op) do { } count _data; _result // return }; - case ("max"): { - private _result = -1e99; - { - _result = _result max (call _x); - nil - } count _data; - _result // return - }; case ("avg"): { private _result = 0; { diff --git a/addons/medical/XEH_postInit.sqf b/addons/medical/XEH_postInit.sqf index 97b9ab0933..c2d202f567 100644 --- a/addons/medical/XEH_postInit.sqf +++ b/addons/medical/XEH_postInit.sqf @@ -1,12 +1,12 @@ // #define DEBUG_MODE_FULL #include "script_component.hpp" +[QEGVAR(medical,setUnconscious), LINKFUNC(setUnconscious)] call CBA_fnc_addEventHandler; + if (!hasInterface) exitWith {}; [missionNamespace, "ACE_setCustomAimCoef", QUOTE(ADDON), { - private _pain = GET_PAIN_PERCEIVED(ACE_player); - - linearConversion [0, 1, _pain, 1, 5, true]; + (linearConversion [0, 1, GET_PAIN_PERCEIVED(ACE_player), 1, 5, true]) + (ACE_player getVariable [QEGVAR(medical_engine,aimFracture), 0]) }] call EFUNC(common,arithmeticSetSource); #ifdef DEBUG_MODE_FULL diff --git a/addons/medical/config.cpp b/addons/medical/config.cpp index 0ba99d21f1..e3557fab40 100644 --- a/addons/medical/config.cpp +++ b/addons/medical/config.cpp @@ -6,7 +6,7 @@ class CfgPatches { units[] = {}; weapons[] = {}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"ace_common"}; + requiredAddons[] = {"ace_medical_engine"}; author = ECSTRING(common,ACETeam); authors[] = {"Glowbal", "KoffeinFlummi","Arcanum417"}; url = ECSTRING(main,URL); diff --git a/addons/medical/dev/watchVariable.sqf b/addons/medical/dev/watchVariable.sqf index 1c2e5eba71..4eeee668b0 100644 --- a/addons/medical/dev/watchVariable.sqf +++ b/addons/medical/dev/watchVariable.sqf @@ -3,7 +3,8 @@ ["medical", { // Hide when patient display is up because they might overlap - if (!isNull EGVAR(medical_gui,displayPatientInformationTarget)) exitWith {""}; + private _display = uiNamespace getVariable [QEGVAR(medical_gui,RscPatientInfo), displayNull]; + if (!isNull _display) exitWith {"Paused"}; private _unit = cursorTarget; if (!(_unit isKindOf "CAManBase")) then {_unit = cursorObject}; @@ -27,10 +28,13 @@ // Blood: private _bloodVolume = GET_BLOOD_VOLUME(_unit); + private _woundBleeding = GET_WOUND_BLEEDING(_unit); private _bloodLoss = GET_BLOOD_LOSS(_unit); - private _secondsToHeartstop = if (_bloodLoss != 0) then {format ["[Time Left: %1 sec]", (((_bloodVolume - BLOOD_VOLUME_CLASS_4_HEMORRHAGE) max 0) / _bloodLoss) toFixed 1]} else {""}; - _return pushBack format ["Blood: %1", _bloodVolume toFixed 3]; - _return pushBack format [" - [Loss: %1] %2", _bloodLoss toFixed 5, _secondsToHeartstop]; + private _hemorrhage = GET_HEMORRHAGE(_unit); + private _isBleeding = if (IS_BLEEDING(_unit)) then {"Bleeding"} else {""}; + private _secondsToHeartstop = if (_bloodLoss != 0) then {format ["[Time Left: %1 sec]", (((_bloodVolume - BLOOD_VOLUME_CLASS_4_HEMORRHAGE) max 0) / _bloodLoss) toFixed 0]} else {""}; + _return pushBack format ["Blood: %1 [Hemorrhage: %2] %3", _bloodVolume toFixed 3, _hemorrhage, _isBleeding]; + _return pushBack format [" - [W: %1 T: %2] %3", _woundBleeding toFixed 4, _bloodLoss toFixed 4, _secondsToHeartstop]; // Heart: private _cardiacOutput = [_unit] call EFUNC(medical_status,getCardiacOutput); @@ -43,15 +47,23 @@ private _pain = GET_PAIN(_unit); private _painSuppress = GET_PAIN_SUPPRESS(_unit); private _painLevel = GET_PAIN_PERCEIVED(_unit); - _return pushBack format ["Effective Pain: %1", _painLevel toFixed 3]; + private _isInPain = IS_IN_PAIN(_unit); + _return pushBack format ["Effective Pain: %1 [%2]", _painLevel toFixed 3, _isInPain]; _return pushBack format [" - [Pain: %1] [Suppress: %2]", _pain toFixed 3, _painSuppress toFixed 3]; // Damage: private _damage = _unit getVariable [QEGVAR(medical,bodyPartDamage), [0,0,0,0,0,0]]; private _limping = if (_unit getVariable [QEGVAR(medical,isLimping), false]) then {"[ Limping ]"} else {""}; - _return pushBack format ["Damage: [H: %1] [B: %2] %3", (_damage select 0) toFixed 2, (_damage select 1) toFixed 2, _limping]; + _return pushBack format ["Damage: [H: %1] [B: %2] %3", (_damage select 0) toFixed 2, (_damage select 1) toFixed 2]; _return pushBack format ["[LA:%1] [RA: %2] [LL:%3] [RL: %4]", (_damage select 2) toFixed 2, (_damage select 3) toFixed 2, (_damage select 4) toFixed 2, (_damage select 5) toFixed 2]; + _return pushBack format ["Hitpoints: [HHed:%1] [HBod: %2]", (_unit getHitPointDamage "HitHead") toFixed 2, (_unit getHitPointDamage "HitBody") toFixed 2]; + _return pushBack format ["[HHnd:%1] [HLeg: %2] %3", (_unit getHitPointDamage "HitHands") toFixed 2, (_unit getHitPointDamage "HitLegs") toFixed 2, _limping]; + + private _fractures = _unit getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]]; + private _canSprint = if (isSprintAllowed _unit) then {""} else {"[Sprint Blocked]"}; + _return pushBack format ["Fractures: %1 %2", _fractures, _canSprint]; + // Tourniquets: _return pushBack "------- Tourniquets: -------"; @@ -75,10 +87,25 @@ _return pushBack "------- Wounds: -------"; private _wounds = _unit getVariable [QEGVAR(medical,openWounds), []]; { - _x params ["", "_xClassID", "_xBodyPartN", "_xAmountOf", "_xBleeding", "_xDamage", "_xCategory"]; - _return pushBack format ["%1: [%2-%3] [x%4] [Bld: %5] [Dmg: %6]", ALL_SELECTIONS select _xBodyPartN, _xClassID, _xCategory, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2]; + _x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "_xBleeding", "_xDamage"]; + _return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", ALL_SELECTIONS select _xBodyPartN, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2]; } forEach _wounds; + // Bandaged Wounds: + _return pushBack "------- Bandaged Wounds: -------"; + private _wounds = _unit getVariable [QEGVAR(medical,bandagedWounds), []]; + { + _x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "_xBleeding", "_xDamage"]; + _return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", ALL_SELECTIONS select _xBodyPartN, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2]; + } forEach _wounds; + + // Stitched Wounds: + _return pushBack "------- Stitched Wounds: -------"; + private _wounds = _unit getVariable [QEGVAR(medical,stitchedWounds), []]; + { + _x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "_xBleeding", "_xDamage"]; + _return pushBack format ["%1: [%2] [x%3] [Bld: %4] [Dmg: %5]", ALL_SELECTIONS select _xBodyPartN, _xClassID, _xAmountOf toFixed 1, _xBleeding toFixed 4, _xDamage toFixed 2]; + } forEach _wounds; // IVs: _return pushBack "------- IVs: -------"; @@ -88,10 +115,43 @@ _return pushBack format ["%1: %2 [%3 ml]", ALL_SELECTIONS select _xBodyPartN, _xType, _xVolumeAdded]; } forEach _ivBags; + // Medications: + _return pushBack "------- Medications: -------"; + private _hrTargetAdjustment = 0; + private _painSupressAdjustment = 0; + private _peripheralResistanceAdjustment = 0; + private _medicationCounts = []; + private _rawMedications = (_unit getVariable [VAR_MEDICATIONS, []]) apply { + _x params ["_medication", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust"]; + private _timeInSystem = CBA_missionTime - _timeAdded; + private _index = _medicationCounts find _medication; + if (_index < 0) then { + _index = _medicationCounts pushBack _medication; + _medicationCounts pushBack 0 + }; + _medicationCounts set [(_index + 1), (_medicationCounts select (_index + 1)) + linearConversion [_timeTillMaxEffect, _maxTimeInSystem, _timeInSystem, 1, 0, true]]; + + private _effectRatio = (((_timeInSystem / _timeTillMaxEffect) ^ 2) min 1) * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem; + _hrTargetAdjustment = _hrTargetAdjustment + _hrAdjust * _effectRatio; + _painSupressAdjustment = _painSupressAdjustment + _painAdjust * _effectRatio; + _peripheralResistanceAdjustment = _peripheralResistanceAdjustment + _flowAdjust * _effectRatio; + format ["%1 [%2 / %3][%4][%5,%6,%7]",_medication,_timeInSystem toFixed 0,_maxTimeInSystem toFixed 0, _effectRatio toFixed 2, _hrAdjust toFixed 1, _painAdjust toFixed 2, _flowAdjust toFixed 1]; + }; + _return pushBack format ["Adjusts: [HR %1][PS %2][PR %3]", _hrTargetAdjustment toFixed 2, _painSupressAdjustment toFixed 2, _peripheralResistanceAdjustment toFixed 2]; + for "_i" from 0 to (count _medicationCounts) - 1 step 2 do { + _return pushBack format ["-%1: %2", _medicationCounts select _i, _medicationCounts select _i + 1]; + }; + _return pushBack "------- Medications Raw: -------"; + _return append _rawMedications; + + if (_unit isEqualTo ACE_player) then { + _return pushBack format ["ACE_setCustomAimCoef: %1", [missionNamespace, "ACE_setCustomAimCoef", "max"] call ace_common_fnc_arithmeticGetResult]; + }; + // Footer: _return pushBack ""; // Return: _return joinString "
" -}, [30]] call EFUNC(common,watchVariable); +}, [40]] call EFUNC(common,watchVariable); diff --git a/addons/medical/functions/fnc_addDamageToUnit.sqf b/addons/medical/functions/fnc_addDamageToUnit.sqf index a8df1f7b8c..d20f912936 100644 --- a/addons/medical/functions/fnc_addDamageToUnit.sqf +++ b/addons/medical/functions/fnc_addDamageToUnit.sqf @@ -23,7 +23,7 @@ // #define DEBUG_TESTRESULTS params [["_unit", objNull, [objNull]], ["_damageToAdd", -1, [0]], ["_bodyPart", "", [""]], ["_typeOfDamage", "", [""]], ["_instigator", objNull, [objNull]]]; -TRACE_5("params",_unit,_damageToAdd,_bodyPart,_typeOfDamage,_instigator); +TRACE_5("addDamageToUnit",_unit,_damageToAdd,_bodyPart,_typeOfDamage,_instigator); private _bodyPartIndex = ALL_BODY_PARTS find (toLower _bodyPart); if (isNull _unit || {!local _unit} || {!alive _unit}) exitWith {ERROR_1("addDamageToUnit - badUnit %1", _this); false}; diff --git a/addons/medical/functions/fnc_setUnconscious.sqf b/addons/medical/functions/fnc_setUnconscious.sqf index 602433a1d3..a073c9e9eb 100644 --- a/addons/medical/functions/fnc_setUnconscious.sqf +++ b/addons/medical/functions/fnc_setUnconscious.sqf @@ -24,7 +24,7 @@ if !(EGVAR(common,settingsInitFinished)) exitWith { EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(setUnconscious), _this]; }; -params ["_unit", ["_knockOut", true, [false]], ["_minWaitingTime", 0, [0]], ["_forcedWakup", false, [false]]]; +params [["_unit", objNull, [objNull]], ["_knockOut", true, [false]], ["_minWaitingTime", 0, [0]], ["_forcedWakup", false, [false]]]; TRACE_4("setUnconscious",_unit,_knockOut,_minWaitingTime,_forcedWakup); if ((isNull _unit) || {!alive _unit} || {!(_unit isKindOf "CAManBase")}) exitWith { @@ -33,7 +33,7 @@ if ((isNull _unit) || {!alive _unit} || {!(_unit isKindOf "CAManBase")}) exitWit }; if (!local _unit) exitWith { - [QEGVAR(medical,setUnconscious), [_unit, _knockOut], _unit] call CBA_fnc_targetEvent; + [QEGVAR(medical,setUnconscious), _this, _unit] call CBA_fnc_targetEvent; true }; diff --git a/addons/medical/initSettings.sqf b/addons/medical/initSettings.sqf index ea61eec532..4fc473949f 100644 --- a/addons/medical/initSettings.sqf +++ b/addons/medical/initSettings.sqf @@ -12,3 +12,23 @@ private _categoryArray = [LELSTRING(medical,Category), "?"]; {[QGVAR(spontaneousWakeUpChance), _this] call EFUNC(common,cbaSettings_settingChanged)}, true // Needs mission restart ] call CBA_settings_fnc_init; + +[ + QEGVAR(medical,limping), "LIST", + [LSTRING(setting_limping_DisplayName), LSTRING(setting_limping_Description)], + _categoryArray, + [[0,1,2],[LELSTRING(common,disabled), LLSTRING(setting_limping_limpOnOpenWounds), LLSTRING(setting_limping_limpRequiresStitching)], 1], // [values, titles, defaultIndex] + true, // isGlobal + {[QEGVAR(medical,limping), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart +] call CBA_settings_fnc_init; + +[ + QEGVAR(medical,fractures), "LIST", + [LSTRING(setting_fractures_DisplayName), LSTRING(setting_fractures_Description)], + _categoryArray, + [[0,1,2],[LELSTRING(common,disabled), LLSTRING(setting_fractures_splintHealsFully), LLSTRING(setting_fractures_splintHasEffects)], 1], // [values, titles, defaultIndex] + true, // isGlobal + {[QEGVAR(medical,fractures), _this] call EFUNC(common,cbaSettings_settingChanged)}, + true // Needs mission restart +] call CBA_settings_fnc_init; diff --git a/addons/medical/script_component.hpp b/addons/medical/script_component.hpp index be9b76ee68..44bdee2faa 100644 --- a/addons/medical/script_component.hpp +++ b/addons/medical/script_component.hpp @@ -14,5 +14,5 @@ #define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL #endif -#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#include "\z\ace\addons\main\script_macros.hpp" diff --git a/addons/medical/stringtable.xml b/addons/medical/stringtable.xml index d20f6a9e17..c1e91ee3f7 100644 --- a/addons/medical/stringtable.xml +++ b/addons/medical/stringtable.xml @@ -481,5 +481,29 @@ 뚜껑 닫기 Zamknij pokrywę + + Limping + + + Limp when unit has leg wounds...(todo) + + + Limp on open wounds + + + Limp on open or bandaged wounds + + + Fractues + + + Limp fractures... (todo) + + + Splints fully heal fractures + + + Splints heal (but cannot sprint) + diff --git a/addons/medical_ai/script_component.hpp b/addons/medical_ai/script_component.hpp index 53ffcf20ba..006c21ac2a 100644 --- a/addons/medical_ai/script_component.hpp +++ b/addons/medical_ai/script_component.hpp @@ -14,5 +14,5 @@ #define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_AI #endif -#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#include "\z\ace\addons\main\script_macros.hpp" diff --git a/addons/medical_blood/script_component.hpp b/addons/medical_blood/script_component.hpp index c7bf8fb91e..ef72e2fdd5 100644 --- a/addons/medical_blood/script_component.hpp +++ b/addons/medical_blood/script_component.hpp @@ -14,8 +14,8 @@ #define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_BLOOD #endif -#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#include "\z\ace\addons\main\script_macros.hpp" #define MAX_BLOOD_OBJECTS 500 #define BLOOD_OBJECT_LIFETIME 900 diff --git a/addons/medical_damage/ACE_Medical_Injuries.hpp b/addons/medical_damage/ACE_Medical_Injuries.hpp index ea15797cbe..9cdeb6d6a7 100644 --- a/addons/medical_damage/ACE_Medical_Injuries.hpp +++ b/addons/medical_damage/ACE_Medical_Injuries.hpp @@ -36,6 +36,7 @@ class ACE_Medical_Injuries { pain = 0.8; minDamage = 0.1; causeLimping = 1; + causeFracture = 1; }; // Slicing wounds made with a sharp instrument, leaving even edges. They may be as minimal as a paper cut or as significant as a surgical incision. class Cut { @@ -59,6 +60,7 @@ class ACE_Medical_Injuries { pain = 0.9; minDamage = 0.35; causeLimping = 1; + causeFracture = 1; }; // Deep, narrow wounds produced by sharp objects such as nails, knives, and broken glass. class PunctureWound { diff --git a/addons/medical_damage/XEH_preInit.sqf b/addons/medical_damage/XEH_preInit.sqf index 203f11109d..081b0cf48b 100644 --- a/addons/medical_damage/XEH_preInit.sqf +++ b/addons/medical_damage/XEH_preInit.sqf @@ -17,11 +17,13 @@ addMissionEventHandler ["Loaded",{ }]; // decide which woundsHandler to use by whether the extension is present or not -if ("ace_medical" callExtension "version" != "") then { - DFUNC(woundsHandlerActive) = LINKFUNC(woundsHandler); -} else { +// if ("ace_medical" callExtension "version" != "") then { + + // DFUNC(woundsHandlerActive) = LINKFUNC(woundsHandler); +// } else { + INFO("Using woundsHandlerSQF"); DFUNC(woundsHandlerActive) = LINKFUNC(woundsHandlerSQF); -}; +// }; [QEGVAR(medical,woundReceived), { params ["_unit", "_woundedHitPoint", "_receivedDamage", "", "_ammo"]; diff --git a/addons/medical_damage/functions/fnc_handleIncapacitation.sqf b/addons/medical_damage/functions/fnc_handleIncapacitation.sqf index f61b2f9c90..1adaf997b8 100644 --- a/addons/medical_damage/functions/fnc_handleIncapacitation.sqf +++ b/addons/medical_damage/functions/fnc_handleIncapacitation.sqf @@ -24,7 +24,7 @@ _bodyPartDamage params ["_headDamage", "_bodyDamage", "_leftArmDamage", "_rightA // Exclude non penetrating body damage { - _x params ["", "", "_bodyPartN", "_amountOf", "", "_damage"]; + _x params ["", "_bodyPartN", "_amountOf", "", "_damage"]; if (_bodyPartN == 1 && {_damage < PENETRATION_THRESHOLD}) then { _bodyDamage = _bodyDamage - (_amountOf * _damage); }; diff --git a/addons/medical_damage/functions/fnc_parseConfigForInjuries.sqf b/addons/medical_damage/functions/fnc_parseConfigForInjuries.sqf index 682b12e141..9a758a4498 100644 --- a/addons/medical_damage/functions/fnc_parseConfigForInjuries.sqf +++ b/addons/medical_damage/functions/fnc_parseConfigForInjuries.sqf @@ -18,7 +18,7 @@ private _injuriesConfigRoot = configFile >> "ACE_Medical_Injuries"; // --- parse wounds -GVAR(woundClassNames) = []; +GVAR(woundClassNamesComplex) = []; // index = 10 * classID + category; [will contain nils] e.g. ["aMinor", "aMed", "aLarge", nil, nil..."bMinor"] GVAR(woundsData) = []; // @todo classTypes are strings currently. Convert them to unqiue IDs instead. private _woundsConfig = _injuriesConfigRoot >> "wounds"; @@ -34,17 +34,20 @@ private _classID = 0; private _minDamage = GET_NUMBER(_entry >> "minDamage",0); private _maxDamage = GET_NUMBER(_entry >> "maxDamage",-1); private _causes = GET_ARRAY(_entry >> "causes",[]); - private _causeLimping = GET_NUMBER(_entry >> "causeLimping",0); + private _causeLimping = 1 == GET_NUMBER(_entry >> "causeLimping",0); + private _causeFracture = 1 == GET_NUMBER(_entry >> "causeFracture",0); if !(_causes isEqualTo []) then { GVAR(woundClassNames) pushBack _className; - GVAR(woundsData) pushBack [_classID, _selections, _bleeding, _pain, [_minDamage, _maxDamage], _causes, _className, _causeLimping]; + GVAR(woundsData) pushBack [_classID, _selections, _bleeding, _pain, [_minDamage, _maxDamage], _causes, _className, _causeLimping, _causeFracture]; + { + GVAR(woundClassNamesComplex) set [10 * _classID + _forEachIndex, format ["%1%2", _className, _x]]; + } forEach ["Minor", "Medium", "Large"]; _classID = _classID + 1; }; } forEach configProperties [_woundsConfig, "isClass _x"]; // --- parse damage types -GVAR(allDamageTypes) = []; // @todo, currently unused by handle damage (was GVAR(allAvailableDamageTypes)) GVAR(allDamageTypesData) = [] call CBA_fnc_createNamespace; // minimum lethal damage collection, mapped to damageTypes @@ -57,8 +60,6 @@ private _selectionSpecificDefault = getNumber (_damageTypesConfig >> "selectionS private _entry = _x; private _className = configName _entry; - GVAR(allDamageTypes) pushBack _className; - // Check if this type is in the causes of a wound class, if so, we will store the wound types for this damage type private _woundTypes = []; { diff --git a/addons/medical_damage/functions/fnc_woundsHandler.sqf b/addons/medical_damage/functions/fnc_woundsHandler.sqf index b1204bbf03..ab86b31e99 100644 --- a/addons/medical_damage/functions/fnc_woundsHandler.sqf +++ b/addons/medical_damage/functions/fnc_woundsHandler.sqf @@ -18,6 +18,8 @@ * Public: No */ +WARNING("this function needs to be updated for changes to woundsHandlerSQF"); + params ["_unit", "_bodyPart", "_damage", "_typeOfDamage"]; TRACE_5("start",_unit,_bodyPart,_damage,_typeOfDamage); @@ -129,6 +131,8 @@ private _bodyPartVisParams = [_unit, false, false, false, false]; // params arra _unit setVariable [QEGVAR(medical,openWounds), _openWounds, true]; _unit setVariable [QEGVAR(medical,bodyPartDamage), _bodyPartDamage, true]; +[_unit] call EFUNC(medical_status,updateWoundBloodLoss); + _bodyPartVisParams call EFUNC(medical_engine,updateBodyPartVisuals); [QEGVAR(medical,injured), [_unit, _painLevel]] call CBA_fnc_localEvent; diff --git a/addons/medical_damage/functions/fnc_woundsHandlerSQF.sqf b/addons/medical_damage/functions/fnc_woundsHandlerSQF.sqf index 6071f64a2f..87fd6ef42e 100644 --- a/addons/medical_damage/functions/fnc_woundsHandlerSQF.sqf +++ b/addons/medical_damage/functions/fnc_woundsHandlerSQF.sqf @@ -19,17 +19,14 @@ */ params ["_unit", "_bodyPart", "_damage", "_typeOfDamage"]; -TRACE_4("start",_unit,_bodyPart,_damage,_typeOfDamage); +TRACE_4("woundsHandlerSQF",_unit,_bodyPart,_damage,_typeOfDamage); // Convert the selectionName to a number and ensure it is a valid selection. private _bodyPartN = ALL_BODY_PARTS find toLower _bodyPart; -if (_bodyPartN < 0) exitWith {}; +if (_bodyPartN < 0) exitWith { ERROR_1("invalid body part %1",_bodyPart); }; -if (_typeOfDamage isEqualTo "") then { - _typeOfDamage = "unknown"; -}; - -if (isNil {GVAR(allDamageTypesData) getVariable _typeOfDamage} ) then { +if ((_typeOfDamage isEqualTo "") || {isNil {GVAR(allDamageTypesData) getVariable _typeOfDamage}}) then { + WARNING_1("damage type [%1] not found",_typeOfDamage); _typeOfDamage = "unknown"; }; @@ -65,22 +62,22 @@ private _allPossibleInjuries = []; } forEach _woundTypes; // No possible wounds available for this damage type or damage amount. -if (_highestPossibleSpot < 0) exitWith {}; +if (_highestPossibleSpot < 0) exitWith { TRACE_2("no wounds possible",_damage,_highestPossibleSpot); }; // Administration for open wounds and ids private _openWounds = _unit getVariable [QEGVAR(medical,openWounds), []]; -private _woundID = _unit getVariable [QEGVAR(medical,lastUniqueWoundID), 1]; // Unique wound ids are not used anywhere: ToDo Remove from openWounds array +private _updateDamageEffects = false; private _painLevel = 0; private _critialDamage = false; private _bodyPartDamage = _unit getVariable [QEGVAR(medical,bodyPartDamage), [0,0,0,0,0,0]]; private _bodyPartVisParams = [_unit, false, false, false, false]; // params array for EFUNC(medical_engine,updateBodyPartVisuals); -private _woundsCreated = []; + { _x params ["_thresholdMinDam", "_thresholdWoundCount"]; if (_thresholdMinDam <= _damage) exitWith { private _woundDamage = _damage / (_thresholdWoundCount max 1); // If the damage creates multiple wounds - for "_i" from 0 to (_thresholdWoundCount-1) do { + for "_i" from 1 to _thresholdWoundCount do { // Find the injury we are going to add. Format [ classID, allowdSelections, bleedingRate, injuryPain] private _oldInjury = if (random 1 >= 0.85) then { _woundTypes select _highestPossibleSpot @@ -88,15 +85,13 @@ private _woundsCreated = []; selectRandom _allPossibleInjuries }; - _oldInjury params ["_woundClassIDToAdd", "", "_injuryBleedingRate", "_injuryPain"]; + _oldInjury params ["_woundClassIDToAdd", "", "_injuryBleedingRate", "_injuryPain", "", "", "", "_causeLimping", "_causeFracture"]; private _bodyPartNToAdd = [floor random 6, _bodyPartN] select _isSelectionSpecific; // 6 == count ALL_BODY_PARTS _bodyPartDamage set [_bodyPartNToAdd, (_bodyPartDamage select _bodyPartNToAdd) + _woundDamage]; _bodyPartVisParams set [[1,2,3,3,4,4] select _bodyPartNToAdd, true]; // Mark the body part index needs updating - // Create a new injury. Format [ID, classID, bodypart, percentage treated, bleeding rate] - private _injury = [_woundID, _woundClassIDToAdd, _bodyPartNToAdd, 1, _injuryBleedingRate]; // The higher the nastiness likelihood the higher the change to get a painful and bloody wound private _nastinessLikelihood = linearConversion [0, 20, (_woundDamage / _thresholdWoundCount), 0.5, 30, true]; @@ -110,76 +105,86 @@ private _woundsCreated = []; // wound category (minor [0..0.5], medium[0.5..1.0], large[1.0+]) private _category = floor linearConversion [0, 1, _bleedingModifier, 0, 2, true]; - // wound category (minor, medium, large) - private _category = floor ((0 max _bleeding min 0.1) / 0.05); + private _classComplex = 10 * _woundClassIDToAdd + _category; - _injury set [4, _bleeding]; - _injury set [5, _woundDamage]; - _injury set [6, _category]; + // Create a new injury. Format [0:classComplex, 1:bodypart, 2:amountOf, 3:bleedingRate, 4:woundDamage] + private _injury = [_classComplex, _bodyPartNToAdd, 1, _bleeding, _woundDamage]; if (_bodyPartNToAdd == 0 || {_bodyPartNToAdd == 1 && {_woundDamage > PENETRATION_THRESHOLD}}) then { _critialDamage = true; }; -#ifdef DEBUG_MODE_FULL + + #ifdef DEBUG_MODE_FULL systemChat format["%1, damage: %2, peneration: %3, bleeding: %4, pain: %5", _bodyPart, _woundDamage toFixed 2, _woundDamage > PENETRATION_THRESHOLD, _bleeding toFixed 3, _pain toFixed 3]; -#endif + #endif // Emulate damage to vital organs switch (true) do { // Fatal damage to the head is guaranteed death - case (_bodyPartNToAdd == 0 && {_woundDamage >= HEAD_DAMAGE_THRESHOLD}): { + case (_bodyPartNToAdd == 0 && {_woundDamage >= HEAD_DAMAGE_THRESHOLD}): { TRACE_1("lethal headshot",_woundDamage toFixed 2); [QEGVAR(medical,FatalInjury), _unit] call CBA_fnc_localEvent; }; // Fatal damage to torso has various results based on organ hit - case (_bodyPartNToAdd == 1 && {_woundDamage >= ORGAN_DAMAGE_THRESHOLD}): { + case (_bodyPartNToAdd == 1 && {_woundDamage >= ORGAN_DAMAGE_THRESHOLD}): { // Heart shot is lethal if (random 1 < HEART_HIT_CHANCE) then { TRACE_1("lethal heartshot",_woundDamage toFixed 2); [QEGVAR(medical,FatalInjury), _unit] call CBA_fnc_localEvent; }; }; - }; - - // todo `forceWalk` based on leg damage - private _causeLimping = (GVAR(woundsData) select _woundClassIDToAdd) select 7; - if (_causeLimping == 1 && {_woundDamage > LIMPING_DAMAGE_THRESHOLD} && {_bodyPartNToAdd > 3}) then { - [_unit, true] call EFUNC(medical_engine,setLimping); + case (_causeFracture && {EGVAR(medical,fractures) > 0} && {_bodyPartNToAdd > 1} && {_woundDamage > FRACTURE_DAMAGE_THRESHOLD}): { + TRACE_1("limb fracture",_bodyPartNToAdd); + // todo: play sound? + private _fractures = _unit getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]]; + _fractures set [_bodyPartNToAdd, 1]; + _unit setVariable [QEGVAR(medical,fractures), _fractures, true]; + [QEGVAR(medical,fracture), [_unit, _bodyPartNToAdd]] call CBA_fnc_localEvent; // local event for fracture + _updateDamageEffects = true; + }; + case (_causeLimping && {EGVAR(medical,limping) > 0} && {_bodyPartNToAdd > 3} && {_woundDamage > LIMPING_DAMAGE_THRESHOLD}): { + _updateDamageEffects = true; + }; }; // if possible merge into existing wounds private _createNewWound = true; { - _x params ["", "_classID", "_bodyPartN", "_oldAmountOf", "_oldBleeding", "_oldDamage", "_oldCategory"]; - if (_woundClassIDToAdd == _classID && {_bodyPartNToAdd == _bodyPartN && {(_woundDamage < PENETRATION_THRESHOLD) isEqualTo (_oldDamage < PENETRATION_THRESHOLD)}}) then { - if (_oldCategory == _category) exitWith { - private _newAmountOf = _oldAmountOf + 1; - _x set [3, _newAmountOf]; - private _newBleeding = (_oldAmountOf * _oldBleeding + _bleeding) / _newAmountOf; - _x set [4, _newBleeding]; - private _newDamage = (_oldAmountOf * _oldDamage + _woundDamage) / _newAmountOf; - _x set [5, _newDamage]; - _createNewWound = false; - }; + _x params ["_classID", "_bodyPartN", "_oldAmountOf", "_oldBleeding", "_oldDamage"]; + if ( + (_classComplex == _classID) && + {_bodyPartNToAdd == _bodyPartN} && + {(_bodyPartNToAdd != 1) || {(_woundDamage < PENETRATION_THRESHOLD) isEqualTo (_oldDamage < PENETRATION_THRESHOLD)}} && // penetrating body damage is handled differently + {(_bodyPartNToAdd > 3) || {!_causeLimping} || {(_woundDamage <= LIMPING_DAMAGE_THRESHOLD) isEqualTo (_oldDamage <= LIMPING_DAMAGE_THRESHOLD)}} // ensure limping damage is stacked correctly + ) exitWith { + TRACE_2("merging with existing wound",_injury,_x); + private _newAmountOf = _oldAmountOf + 1; + _x set [2, _newAmountOf]; + private _newBleeding = (_oldAmountOf * _oldBleeding + _bleeding) / _newAmountOf; + _x set [3, _newBleeding]; + private _newDamage = (_oldAmountOf * _oldDamage + _woundDamage) / _newAmountOf; + _x set [4, _newDamage]; + _createNewWound = false; }; } forEach _openWounds; if (_createNewWound) then { + TRACE_1("adding new wound",_injury); _openWounds pushBack _injury; }; - - // New injuries will also increase the wound ID - _woundID = _woundID + 1; - - // Store the injury so we can process it later correctly. - _woundsCreated pushBack _injury; }; }; } forEach _thresholds; +if (_updateDamageEffects) then { + [_unit] call EFUNC(medical_engine,updateDamageEffects); +}; + _unit setVariable [QEGVAR(medical,openWounds), _openWounds, true]; _unit setVariable [QEGVAR(medical,bodyPartDamage), _bodyPartDamage, true]; +[_unit] call EFUNC(medical_status,updateWoundBloodLoss); + _bodyPartVisParams call EFUNC(medical_engine,updateBodyPartVisuals); [QEGVAR(medical,injured), [_unit, _painLevel]] call CBA_fnc_localEvent; @@ -188,4 +193,4 @@ if (_critialDamage || {_painLevel > PAIN_UNCONSCIOUS}) then { [_unit] call FUNC(handleIncapacitation); }; -TRACE_5("exit",_unit,_painLevel,GET_PAIN(_unit),_unit getVariable QEGVAR(medical,openWounds),_woundsCreated); +TRACE_4("exit",_unit,_painLevel,GET_PAIN(_unit),_unit getVariable QEGVAR(medical,openWounds)); diff --git a/addons/medical_damage/script_component.hpp b/addons/medical_damage/script_component.hpp index f96a81d378..c567aeeae7 100644 --- a/addons/medical_damage/script_component.hpp +++ b/addons/medical_damage/script_component.hpp @@ -14,5 +14,5 @@ #define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_DAMAGE #endif -#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#include "\z\ace\addons\main\script_macros.hpp" diff --git a/addons/medical_engine/XEH_PREP.hpp b/addons/medical_engine/XEH_PREP.hpp index 3c7872c515..0bacdd97e7 100644 --- a/addons/medical_engine/XEH_PREP.hpp +++ b/addons/medical_engine/XEH_PREP.hpp @@ -1,6 +1,6 @@ PREP(handleDamage); PREP(damageBodyPart); PREP(updateBodyPartVisuals); -PREP(setLimping); +PREP(updateDamageEffects); PREP(setStructuralDamage); PREP(setUnconsciousAnim); diff --git a/addons/medical_engine/XEH_postInit.sqf b/addons/medical_engine/XEH_postInit.sqf index f4f9f746c7..18703e7358 100644 --- a/addons/medical_engine/XEH_postInit.sqf +++ b/addons/medical_engine/XEH_postInit.sqf @@ -1,5 +1,12 @@ #include "script_component.hpp" +[QGVAR(updateDamageEffects), LINKFUNC(updateDamageEffects)] call CBA_fnc_addEventHandler; +["unit", { + params ["_new"]; + [_new] call FUNC(updateDamageEffects); // Run on new controlled unit to update QGVAR(aimFracture) +}, true] call CBA_fnc_addPlayerEventHandler; + + ["CAManBase", "init", { params ["_unit"]; diff --git a/addons/medical_engine/functions/fnc_setLimping.sqf b/addons/medical_engine/functions/fnc_setLimping.sqf deleted file mode 100644 index 11ead53c54..0000000000 --- a/addons/medical_engine/functions/fnc_setLimping.sqf +++ /dev/null @@ -1,30 +0,0 @@ -#include "script_component.hpp" -/* - * Author: commy2 - * Forces a unit to limp or not. - * - * Arguments: - * 0: Unit - * 1: Limping (optional, default: true) - * - * Return Value: - * None - * - * Example: - * [player, true] call ace_medical_engine_fnc_setLimping - * - * Public: No - */ - -params [["_unit", objNull, [objNull]], ["_isLimping", true, [false]]]; - -if (!local _unit) exitWith { - ERROR("Unit not local or null"); -}; - -_unit setVariable [QEGVAR(medical,isLimping), _isLimping, true]; - -// refresh -private _isDamaged = _unit getHitPointDamage "HitLegs" >= DAMAGED_MIN_THRESHOLD && {_unit getHitPointDamage "HitLegs" != LIMPING_MIN_DAMAGE}; - -[_unit, "Legs", _isDamaged] call FUNC(damageBodyPart); diff --git a/addons/medical_engine/functions/fnc_updateDamageEffects.sqf b/addons/medical_engine/functions/fnc_updateDamageEffects.sqf new file mode 100644 index 0000000000..dffe7f2ebc --- /dev/null +++ b/addons/medical_engine/functions/fnc_updateDamageEffects.sqf @@ -0,0 +1,67 @@ +#include "script_component.hpp" +/* + * Author: commy2, PabstMirror + * Updates damage effects for limping and fractures + * + * Arguments: + * 0: Unit + * 1: Limping (optional, default: true) + * + * Return Value: + * None + * + * Example: + * [player] call ace_medical_engine_fnc_updateDamageEffects + * + * Public: No + */ + +params [["_unit", objNull, [objNull]]]; + +if (!local _unit) exitWith { ERROR("Unit not local or null"); }; + +private _isLimping = false; + +if (EGVAR(medical,fractures) > 0) then { + private _fractures = _unit getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]]; + TRACE_1("",_fractures); + if (((_fractures select 4) == 1) || {(_fractures select 5) == 1}) then { + TRACE_1("limping because of fracture",_fractures); + _isLimping = true; + }; + private _aimFracture = 0; + if ((_fractures select 2) == 1) then { _aimFracture = _aimFracture + 4; }; + if ((_fractures select 3) == 1) then { _aimFracture = _aimFracture + 4; }; + + if (EGVAR(medical,fractures) == 2) then { // the limp with a splint will still cause effects + private _isSprintBlocked = ((_fractures select 4) == -1) || {(_fractures select 5) == -1}; // block sprinting if we have a leg splint on + if (_isSprintBlocked || {!isSprintAllowed _unit}) then { // only update status effect if we need to + TRACE_1("updating status effect",_isSprintBlocked); + [_unit, "blockSprint", QEGVAR(medical,fracture), _isSprintBlocked] call EFUNC(common,statusEffect_set); + }; + if ((_fractures select 2) == 1) then { _aimFracture = _aimFracture + 2; }; + if ((_fractures select 3) == 1) then { _aimFracture = _aimFracture + 2; }; + }; + _unit setVariable [QGVAR(aimFracture), _aimFracture, false]; // local only var, used in ace_medical's postInit to set ACE_setCustomAimCoef +}; + +if (!_isLimping && {EGVAR(medical,limping) > 0}) then { + private _woundsToCheck = _unit getVariable [QEGVAR(medical,openWounds), []]; + if (EGVAR(medical,limping) == 2) then { + _woundsToCheck = _woundsToCheck + (_unit getVariable [QEGVAR(medical,bandagedWounds), []]); // do not append + }; + { + _x params ["_xClassID", "_xBodyPartN", "_xAmountOf", "", "_xDamage"]; + if ((_xBodyPartN > 3) && {_xAmountOf > 0} && {_xDamage > LIMPING_DAMAGE_THRESHOLD} && { + (EGVAR(medical_damage,woundsData) select (_xClassID / 10)) select 7}) exitWith { // select _causeLimping from woundsData + TRACE_1("limping because of wound",_x); + _isLimping = true; + }; + } forEach _woundsToCheck; +}; +_unit setVariable [QEGVAR(medical,isLimping), _isLimping, true]; + +// refresh +private _isDamaged = _unit getHitPointDamage "HitLegs" >= DAMAGED_MIN_THRESHOLD && {_unit getHitPointDamage "HitLegs" != LIMPING_MIN_DAMAGE}; + +[_unit, "Legs", _isDamaged] call FUNC(damageBodyPart); diff --git a/addons/medical_engine/script_component.hpp b/addons/medical_engine/script_component.hpp index d45c30a024..dbe6e2a2cb 100644 --- a/addons/medical_engine/script_component.hpp +++ b/addons/medical_engine/script_component.hpp @@ -14,8 +14,8 @@ #define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_ENGINE #endif -#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_config.hpp" #define PRELOAD_CLASS(class) \ diff --git a/addons/medical_engine/script_macros_medical.hpp b/addons/medical_engine/script_macros_medical.hpp index 62384ba8e4..ef55cb2375 100644 --- a/addons/medical_engine/script_macros_medical.hpp +++ b/addons/medical_engine/script_macros_medical.hpp @@ -1,3 +1,7 @@ +#define DEBUG_MODE_FULL +#define DISABLE_COMPILE_CACHE +#define ENABLE_PERFORMANCE_COUNTERS + #define ALL_BODY_PARTS ["head", "body", "leftarm", "rightarm", "leftleg", "rightleg"] #define ALL_SELECTIONS ["head", "body", "hand_l", "hand_r", "leg_l", "leg_r"] @@ -70,12 +74,15 @@ // Minimum leg damage required for limping #define LIMPING_DAMAGE_THRESHOLD 0.30 +// Minimum limb damage required for fracture +#define FRACTURE_DAMAGE_THRESHOLD 0.50 + // Minimum body part damage required for blood effect on uniform #define VISUAL_BODY_DAMAGE_THRESHOLD 0.35 // Empty wound data, used for some default return values -// [ID, classID, bodypartIndex, amountOf, bloodloss, damage, category] -#define EMPTY_WOUND [-1, -1, -1, 0, 0, 0, 0] +// [classID, bodypartIndex, amountOf, bloodloss, damage] +#define EMPTY_WOUND [-1, -1, 0, 0, 0] // Base time to bandage each wound category #define BANDAGE_TIME_S 4 @@ -108,6 +115,7 @@ // Defined here for easy consistency with GETVAR/SETVAR (also a list for reference) #define VAR_BLOOD_PRESS QEGVAR(medical,bloodPressure) #define VAR_BLOOD_VOL QEGVAR(medical,bloodVolume) +#define VAR_WOUND_BLEEDING QEGVAR(medical,woundBleeding) #define VAR_CRDC_ARRST QEGVAR(medical,inCardiacArrest) #define VAR_HEART_RATE QEGVAR(medical,heartRate) #define VAR_PAIN QEGVAR(medical,pain) @@ -115,13 +123,10 @@ #define VAR_PERIPH_RES QEGVAR(medical,peripheralResistance) #define VAR_UNCON "ACE_isUnconscious" // These variables track gradual adjustments (from medication, etc.) -#define VAR_HEART_RATE_ADJ QEGVAR(medical,heartRateAdjustments) -#define VAR_PAIN_SUPP_ADJ QEGVAR(medical,painSuppressAdjustments) -#define VAR_PERIPH_RES_ADJ QEGVAR(medical,peripheralResistanceAdjustments) +#define VAR_MEDICATIONS QEGVAR(medical,medications) // These variables track the current state of status values above #define VAR_HEMORRHAGE QEGVAR(medical,hemorrhage) #define VAR_IN_PAIN QEGVAR(medical,inPain) -#define VAR_IS_BLEEDING QEGVAR(medical,isBleeding) #define VAR_TOURNIQUET QEGVAR(medical,tourniquets) @@ -129,13 +134,14 @@ // Retrieval macros for common unit values // Defined for easy consistency and speed #define GET_BLOOD_VOLUME(unit) (unit getVariable [VAR_BLOOD_VOL,DEFAULT_BLOOD_VOLUME]) +#define GET_WOUND_BLEEDING(unit) (unit getVariable [VAR_WOUND_BLEEDING,0]) #define GET_HEART_RATE(unit) (unit getVariable [VAR_HEART_RATE,DEFAULT_HEART_RATE]) #define GET_HEMORRHAGE(unit) (unit getVariable [VAR_HEMORRHAGE,0]) #define GET_PAIN(unit) (unit getVariable [VAR_PAIN,0]) #define GET_PAIN_SUPPRESS(unit) (unit getVariable [VAR_PAIN_SUPP,0]) #define GET_TOURNIQUETS(unit) (unit getVariable [VAR_TOURNIQUET, DEFAULT_TOURNIQUET_VALUES]) #define IN_CRDC_ARRST(unit) (unit getVariable [VAR_CRDC_ARRST,false]) -#define IS_BLEEDING(unit) (unit getVariable [VAR_IS_BLEEDING,false]) +#define IS_BLEEDING(unit) (GET_WOUND_BLEEDING(unit) > 0) #define IS_IN_PAIN(unit) (unit getVariable [VAR_IN_PAIN,false]) #define IS_UNCONSCIOUS(unit) (unit getVariable [VAR_UNCON,false]) diff --git a/addons/medical_feedback/script_component.hpp b/addons/medical_feedback/script_component.hpp index a082cd3d50..e39fa42c8b 100644 --- a/addons/medical_feedback/script_component.hpp +++ b/addons/medical_feedback/script_component.hpp @@ -14,8 +14,8 @@ #define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_FEEDBACK #endif -#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#include "\z\ace\addons\main\script_macros.hpp" #define EMPTY_SOUND {"A3\Sounds_F\dummysound.wss",1,1} #define NAMESPACE_NULL locationNull diff --git a/addons/medical_gui/data/body_image/arm_left_bonel.paa b/addons/medical_gui/data/body_image/arm_left_bonel.paa new file mode 100644 index 0000000000..9d4cefd89b Binary files /dev/null and b/addons/medical_gui/data/body_image/arm_left_bonel.paa differ diff --git a/addons/medical_gui/data/body_image/arm_right_boner.paa b/addons/medical_gui/data/body_image/arm_right_boner.paa new file mode 100644 index 0000000000..c5ae90dcbf Binary files /dev/null and b/addons/medical_gui/data/body_image/arm_right_boner.paa differ diff --git a/addons/medical_gui/data/body_image/leg_left_bonel.paa b/addons/medical_gui/data/body_image/leg_left_bonel.paa new file mode 100644 index 0000000000..f878074995 Binary files /dev/null and b/addons/medical_gui/data/body_image/leg_left_bonel.paa differ diff --git a/addons/medical_gui/data/body_image/leg_right_boner.paa b/addons/medical_gui/data/body_image/leg_right_boner.paa new file mode 100644 index 0000000000..3b0dc02605 Binary files /dev/null and b/addons/medical_gui/data/body_image/leg_right_boner.paa differ diff --git a/addons/medical_gui/functions/fnc_modifyAction.sqf b/addons/medical_gui/functions/fnc_modifyAction.sqf index d4754dab06..7c197cc102 100644 --- a/addons/medical_gui/functions/fnc_modifyAction.sqf +++ b/addons/medical_gui/functions/fnc_modifyAction.sqf @@ -25,7 +25,7 @@ private _bloodLossOnBodyPart = 0; // Add all bleeding from wounds on selection { - _x params ["", "", "_bodyPartN", "_amountOf", "_bleeding"]; + _x params ["", "_bodyPartN", "_amountOf", "_bleeding"]; if (_bodyPartN == _partIndex) then { _bloodLossOnBodyPart = _bloodLossOnBodyPart + (_amountOf * _bleeding); diff --git a/addons/medical_gui/functions/fnc_updateBodyImage.sqf b/addons/medical_gui/functions/fnc_updateBodyImage.sqf index 62b2ebd0fb..63b6b2df9b 100644 --- a/addons/medical_gui/functions/fnc_updateBodyImage.sqf +++ b/addons/medical_gui/functions/fnc_updateBodyImage.sqf @@ -20,16 +20,17 @@ params ["_ctrlGroup", "_target"]; // Get tourniquets, damage, and blood loss for target private _tourniquets = GET_TOURNIQUETS(_target); +private _fractures = _target getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]]; private _bodyPartDamage = _target getVariable [QEGVAR(medical,bodyPartDamage), [0, 0, 0, 0, 0, 0]]; private _bodyPartBloodLoss = [0, 0, 0, 0, 0, 0]; { - _x params ["", "", "_bodyPartN", "_amountOf", "_bleeding"]; + _x params ["", "_bodyPartN", "_amountOf", "_bleeding"]; _bodyPartBloodLoss set [_bodyPartN, (_bodyPartBloodLoss select _bodyPartN) + (_bleeding * _amountOf)]; } forEach (_target getVariable [QEGVAR(medical,openWounds), []]); { - _x params ["_bodyPartIDC", ["_tourniquetIDC", -1]]; + _x params ["_bodyPartIDC", ["_tourniquetIDC", -1], ["_fractureIDC", -1]]; // Show or hide the tourniquet icon if (_tourniquetIDC != -1) then { @@ -37,6 +38,27 @@ private _bodyPartBloodLoss = [0, 0, 0, 0, 0, 0]; private _ctrlTourniquet = _ctrlGroup controlsGroupCtrl _tourniquetIDC; _ctrlTourniquet ctrlShow _hasTourniquet; }; + // Show or hide fractrue/bones + if (_fractureIDC != -1) then { + private _ctrlBone = _ctrlGroup controlsGroupCtrl _fractureIDC; + switch (_fractures select _forEachIndex) do { + case (0): { + _ctrlBone ctrlShow false; + }; + case (1): { + _ctrlBone ctrlShow true; + _ctrlBone ctrlSetTextColor [1, 0, 0, 1]; + }; + case (-1): { + if (EGVAR(medical,fractures) == 2) then { + _ctrlBone ctrlShow true; + _ctrlBone ctrlSetTextColor [0, 0, 1, 1]; + } else { + _ctrlBone ctrlShow false; + }; + }; + }; + }; // Update body part color based on blood loss and damage private _bloodLoss = _bodyPartBloodLoss select _forEachIndex; @@ -50,10 +72,10 @@ private _bodyPartBloodLoss = [0, 0, 0, 0, 0, 0]; private _ctrlBodyPart = _ctrlGroup controlsGroupCtrl _bodyPartIDC; _ctrlBodyPart ctrlSetTextColor _bodyPartColor; } forEach [ - [IDC_BODY_HEAD], - [IDC_BODY_TORSO], - [IDC_BODY_ARMLEFT, IDC_BODY_ARMLEFT_T], - [IDC_BODY_ARMRIGHT, IDC_BODY_ARMRIGHT_T], - [IDC_BODY_LEGLEFT, IDC_BODY_LEGLEFT_T], - [IDC_BODY_LEGRIGHT, IDC_BODY_LEGRIGHT_T] +[IDC_BODY_HEAD], +[IDC_BODY_TORSO], +[IDC_BODY_ARMLEFT, IDC_BODY_ARMLEFT_T, IDC_BODY_ARMLEFT_B], +[IDC_BODY_ARMRIGHT, IDC_BODY_ARMRIGHT_T, IDC_BODY_ARMRIGHT_B], +[IDC_BODY_LEGLEFT, IDC_BODY_LEGLEFT_T, IDC_BODY_LEGLEFT_B], +[IDC_BODY_LEGRIGHT, IDC_BODY_LEGRIGHT_T, IDC_BODY_LEGRIGHT_B] ]; diff --git a/addons/medical_gui/functions/fnc_updateInjuryList.sqf b/addons/medical_gui/functions/fnc_updateInjuryList.sqf index 49966fdc4a..c5cd351294 100644 --- a/addons/medical_gui/functions/fnc_updateInjuryList.sqf +++ b/addons/medical_gui/functions/fnc_updateInjuryList.sqf @@ -58,6 +58,14 @@ switch (GET_HEMORRHAGE(_target)) do { if (HAS_TOURNIQUET_APPLIED_ON(_target,_selectionN)) then { _entries pushBack [localize LSTRING(Status_Tourniquet_Applied), [0.77, 0.51, 0.08, 1]]; }; +switch ((_target getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]]) select _selectionN) do { +case (1): {_entries pushBack [localize LSTRING(Status_Fractured), [1, 0, 0, 1]];}; +case (-1): { + if (EGVAR(medical,fractures) == 2) then { // Ignore if the split has no effect + _entries pushBack [localize LSTRING(Status_SplintApplied), [1, 1, 1, 1]]; + }; + }; +}; // Indicate the amount of pain the unit is in if ([_target] call EFUNC(common,isAwake)) then { @@ -93,7 +101,9 @@ if (_totalIvVolume >= 1) then { private _woundEntries = []; private _fnc_getWoundDescription = { - private _className = EGVAR(medical_damage,woundsData) select _woundClassID select 6; + private _classIndex = _woundClassID / 10; + private _category = _woundClassID % 10; + private _className = EGVAR(medical_damage,woundsData) select _classIndex select 6; private _suffix = ["Minor", "Medium", "Large"] select _category; private _woundName = localize format [ELSTRING(medical_damage,%1_%2), _className, _suffix]; if (_amountOf >= 1) then { @@ -104,7 +114,7 @@ private _fnc_getWoundDescription = { }; { - _x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "", "", "_category"]; + _x params ["_woundClassID", "_bodyPartN", "_amountOf"]; if (_selectionN == _bodyPartN) then { if (_amountOf > 0) then { _woundEntries pushBack [call _fnc_getWoundDescription, [1, 1, 1, 1]]; @@ -117,14 +127,14 @@ private _fnc_getWoundDescription = { } forEach (_target getVariable [QEGVAR(medical,openWounds), []]); { - _x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "", "", "_category"]; + _x params ["_woundClassID", "_bodyPartN", "_amountOf"]; if (_selectionN == _bodyPartN && {_amountOf > 0}) then { _woundEntries pushBack [format ["[B] %1", call _fnc_getWoundDescription], [0.88, 0.7, 0.65, 1]]; }; } forEach (_target getVariable [QEGVAR(medical,bandagedWounds), []]); { - _x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "", "", "_category"]; + _x params ["_woundClassID", "_bodyPartN", "_amountOf"]; if (_selectionN == _bodyPartN && {_amountOf > 0}) then { _woundEntries pushBack [format ["[S] %1", call _fnc_getWoundDescription], [0.7, 0.7, 0.7, 1]]; }; diff --git a/addons/medical_gui/gui.hpp b/addons/medical_gui/gui.hpp index eceb263a60..ca441853d4 100644 --- a/addons/medical_gui/gui.hpp +++ b/addons/medical_gui/gui.hpp @@ -45,6 +45,24 @@ class GVAR(BodyImage): RscControlsGroupNoScrollbars { idc = IDC_BODY_LEGRIGHT; text = QPATHTOF(data\body_image\leg_right.paa); }; + class ArmLeftB: Background { + idc = IDC_BODY_ARMLEFT_B; + text = QPATHTOF(data\body_image\arm_left_bonel.paa); + colorText[] = {0, 0, 0.8, 1}; + show = 0; + }; + class ArmRightB: ArmLeftB { + idc = IDC_BODY_ARMRIGHT_B; + text = QPATHTOF(data\body_image\arm_right_boner.paa); + }; + class LegLeftB: ArmLeftB { + idc = IDC_BODY_LEGLEFT_B; + text = QPATHTOF(data\body_image\leg_left_bonel.paa); + }; + class LegRightB: ArmLeftB { + idc = IDC_BODY_LEGRIGHT_B; + text = QPATHTOF(data\body_image\leg_right_boner.paa); + }; class ArmLeftT: Background { idc = IDC_BODY_ARMLEFT_T; text = QPATHTOF(data\body_image\arm_left_t.paa); @@ -549,6 +567,22 @@ class RscTitles { w = POS_W(8.5); h = POS_H(8.5); }; + class ArmLeftB: ArmLeftB { + w = POS_W(8.5); + h = POS_H(8.5); + }; + class ArmRightB: ArmRightB { + w = POS_W(8.5); + h = POS_H(8.5); + }; + class LegLeftB: LegLeftB { + w = POS_W(8.5); + h = POS_H(8.5); + }; + class LegRightB: LegRightB { + w = POS_W(8.5); + h = POS_H(8.5); + }; class ArmLeftT: ArmLeftT { w = POS_W(8.5); h = POS_H(8.5); diff --git a/addons/medical_gui/script_component.hpp b/addons/medical_gui/script_component.hpp index f87ebc8bc9..c4c7aafcd8 100644 --- a/addons/medical_gui/script_component.hpp +++ b/addons/medical_gui/script_component.hpp @@ -14,8 +14,8 @@ #define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_GUI #endif -#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#include "\z\ace\addons\main\script_macros.hpp" #include "\a3\ui_f\hpp\defineResincl.inc" #include "\a3\ui_f\hpp\defineDIKCodes.inc" @@ -67,6 +67,10 @@ #define IDC_BODY_ARMRIGHT_T 6040 #define IDC_BODY_LEGLEFT_T 6045 #define IDC_BODY_LEGRIGHT_T 6050 +#define IDC_BODY_ARMLEFT_B 6055 +#define IDC_BODY_ARMRIGHT_B 6060 +#define IDC_BODY_LEGRIGHT_B 6065 +#define IDC_BODY_LEGLEFT_B 6070 #define IDC_TRIAGE_STATUS 7000 #define IDC_TRIAGE_SELECT 7100 diff --git a/addons/medical_gui/stringtable.xml b/addons/medical_gui/stringtable.xml index 2703cfacc5..6b2a76859f 100644 --- a/addons/medical_gui/stringtable.xml +++ b/addons/medical_gui/stringtable.xml @@ -775,6 +775,12 @@ 大量失血 大量失血 + + Fractured + + + Splint Applied + diff --git a/addons/medical_gui/ui/splint.paa b/addons/medical_gui/ui/splint.paa new file mode 100644 index 0000000000..521809124a Binary files /dev/null and b/addons/medical_gui/ui/splint.paa differ diff --git a/addons/medical_statemachine/script_component.hpp b/addons/medical_statemachine/script_component.hpp index 1553911601..fbde60be72 100644 --- a/addons/medical_statemachine/script_component.hpp +++ b/addons/medical_statemachine/script_component.hpp @@ -14,5 +14,5 @@ #define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_STATEMACHINE #endif -#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#include "\z\ace\addons\main\script_macros.hpp" diff --git a/addons/medical_status/XEH_PREP.hpp b/addons/medical_status/XEH_PREP.hpp index 3b74368c2a..32e02d18c8 100644 --- a/addons/medical_status/XEH_PREP.hpp +++ b/addons/medical_status/XEH_PREP.hpp @@ -1,4 +1,4 @@ -PREP(addHeartRateAdjustment); +PREP(addMedicationAdjustment); PREP(adjustPainLevel); PREP(getBloodLoss); PREP(getBloodPressure); @@ -12,3 +12,4 @@ PREP(isInStableCondition); PREP(setCardiacArrest); PREP(setDead); PREP(setUnconscious); +PREP(updateWoundBloodLoss); diff --git a/addons/medical_status/functions/fnc_addHeartRateAdjustment.sqf b/addons/medical_status/functions/fnc_addHeartRateAdjustment.sqf deleted file mode 100644 index 39b65a4ead..0000000000 --- a/addons/medical_status/functions/fnc_addHeartRateAdjustment.sqf +++ /dev/null @@ -1,21 +0,0 @@ -#include "script_component.hpp" -/* - * Author: BaerMitUmlaut - * Adds a heart rate adjustment that will take effect over time. - * - * Arguments: - * 0: The Unit - * 1: Heart rate change - * 2: Time in system for the adjustment to reach its peak - * 3: Duration the adjustment will have an effect - * - * Return Value: - * None - */ - -params ["_unit", "_change", "_timeToMaxEffect", "_maxTimeInSystem"]; - -private _adjustments = _unit getVariable [VAR_HEART_RATE_ADJ,[]]; -// The last number indicates the time the adjustment is already in the system -_adjustments pushBack [_change, _timeToMaxEffect, _maxTimeInSystem, 0]; -_unit setVariable [VAR_HEART_RATE_ADJ, _adjustments]; diff --git a/addons/medical_status/functions/fnc_addMedicationAdjustment.sqf b/addons/medical_status/functions/fnc_addMedicationAdjustment.sqf new file mode 100644 index 0000000000..524b242b1a --- /dev/null +++ b/addons/medical_status/functions/fnc_addMedicationAdjustment.sqf @@ -0,0 +1,32 @@ +#include "script_component.hpp" +/* + * Author: BaerMitUmlaut, PabstMirror + * Adds a medication and it's effects + * + * Arguments: + * 0: The Unit + * 1: Medication + * 2: Time in system for the adjustment to reach its peak + * 3: Duration the adjustment will have an effect + * 4: Heart Rate Adjust + * 5: Pain Suppress Adjust + * 6: Flow Adjust + * + * Return Value: + * None + * + * Example: + * [player, "Morphine", 120, 60, -10, 0.8, -10] call ace_medical_status_fnc_addMedicationAdjustment + */ +params ["_unit", "_medication", "_timeToMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust"]; +TRACE_7("addMedicationAdjustment",_unit,_medication,_timeToMaxEffect,_maxTimeInSystem,_hrAdjust,_painAdjust,_flowAdjust); + +if (_maxTimeInSystem <= 0) exitWith { WARNING_1("bad value for _maxTimeInSystem - %1",_this); }; +_timeToMaxEffect = _timeToMaxEffect max 1; + + +private _adjustments = _unit getVariable [VAR_MEDICATIONS, []]; + +_adjustments pushBack [_medication, CBA_missionTime, _timeToMaxEffect, _maxTimeInSystem, _hrAdjust, _painAdjust, _flowAdjust]; + +_unit setVariable [VAR_MEDICATIONS, _adjustments, true]; diff --git a/addons/medical_status/functions/fnc_getBloodLoss.sqf b/addons/medical_status/functions/fnc_getBloodLoss.sqf index 0471cb0dfb..199b92356e 100644 --- a/addons/medical_status/functions/fnc_getBloodLoss.sqf +++ b/addons/medical_status/functions/fnc_getBloodLoss.sqf @@ -10,31 +10,16 @@ * Total blood loss of unit * * Example: - * [bob] call ace_medical_status_fnc_getBloodLoss + * [player] call ace_medical_status_fnc_getBloodLoss * * Public: No */ params ["_unit"]; -private _tourniquets = GET_TOURNIQUETS(_unit); -private _bodyPartBleeding = [0,0,0,0,0,0]; -{ - _x params ["", "", "_bodyPart", "_amountOf", "_bleeeding"]; - if (_tourniquets select _bodyPart == 0) then { - _bodyPartBleeding set [_bodyPart, (_bodyPartBleeding select _bodyPart) + (_amountOf * _bleeeding)]; - }; -} forEach (_unit getVariable [QEGVAR(medical,openWounds), []]); - -if (_bodyPartBleeding isEqualTo [0,0,0,0,0,0]) exitWith { 0 }; - -_bodyPartBleeding params ["_headBleeding", "_bodyBleeding", "_leftArmBleeding", "_rightArmBleeding", "_leftLegBleeding", "_rightLegBleeding"]; -private _bodyBleedingRate = ((_headBleeding min 0.9) + (_bodyBleeding min 1.0)) min 1.0; -private _limbBleedingRate = ((_leftArmBleeding min 0.3) + (_rightArmBleeding min 0.3) + (_leftLegBleeding min 0.5) + (_rightLegBleeding min 0.5)) min 1.0; - -// limb bleeding is scaled down based on the amount of body bleeding -_limbBleedingRate = _limbBleedingRate * (1 - _bodyBleedingRate); +private _woundBleeding = GET_WOUND_BLEEDING(_unit); +if (_woundBleeding == 0) exitWith {0}; private _cardiacOutput = [_unit] call FUNC(getCardiacOutput); -((_bodyBleedingRate + _limbBleedingRate) * _cardiacOutput * EGVAR(medical,bleedingCoefficient)) +(_woundBleeding * _cardiacOutput * EGVAR(medical,bleedingCoefficient)) diff --git a/addons/medical_status/functions/fnc_getBloodVolumeChange.sqf b/addons/medical_status/functions/fnc_getBloodVolumeChange.sqf index bce1847e19..904d33c79f 100644 --- a/addons/medical_status/functions/fnc_getBloodVolumeChange.sqf +++ b/addons/medical_status/functions/fnc_getBloodVolumeChange.sqf @@ -19,7 +19,6 @@ params ["_unit", "_deltaT", "_syncValues"]; -private _bloodVolume = GET_BLOOD_VOLUME(_unit); private _bloodVolumeChange = -_deltaT * GET_BLOOD_LOSS(_unit); if (!isNil {_unit getVariable QEGVAR(medical,ivBags)}) then { diff --git a/addons/medical_status/functions/fnc_getCardiacOutput.sqf b/addons/medical_status/functions/fnc_getCardiacOutput.sqf index c082292e1e..649fade76f 100644 --- a/addons/medical_status/functions/fnc_getCardiacOutput.sqf +++ b/addons/medical_status/functions/fnc_getCardiacOutput.sqf @@ -21,12 +21,12 @@ */ // to limit the amount of complex calculations necessary, we take a set modifier to calculate Stroke Volume. -#define MODIFIER_CARDIAC_OUTPUT 19.04761 +#define MODIFIER_CARDIAC_OUTPUT 0.1904761 params ["_unit"]; -private _bloodVolume = (GET_BLOOD_VOLUME(_unit) / DEFAULT_BLOOD_VOLUME) * 100; +private _bloodVolumeRatio = (GET_BLOOD_VOLUME(_unit) / DEFAULT_BLOOD_VOLUME); private _heartRate = GET_HEART_RATE(_unit); -private _cardiacOutput = ((_bloodVolume / MODIFIER_CARDIAC_OUTPUT) + ((_heartRate / DEFAULT_HEART_RATE) - 1)) / 60; +private _cardiacOutput = ((_bloodVolumeRatio / MODIFIER_CARDIAC_OUTPUT) + ((_heartRate / DEFAULT_HEART_RATE) - 1)) / 60; (0 max _cardiacOutput) diff --git a/addons/medical_status/functions/fnc_initUnit.sqf b/addons/medical_status/functions/fnc_initUnit.sqf index 0393adf1a3..078bcafeef 100644 --- a/addons/medical_status/functions/fnc_initUnit.sqf +++ b/addons/medical_status/functions/fnc_initUnit.sqf @@ -26,19 +26,15 @@ if (damage _unit > 0) then { // - Blood and heart ---------------------------------------------------------- _unit setVariable [VAR_BLOOD_VOL, DEFAULT_BLOOD_VOLUME, true]; _unit setVariable [VAR_HEART_RATE, DEFAULT_HEART_RATE, true]; -_unit setVariable [VAR_HEART_RATE_ADJ, [], true]; _unit setVariable [VAR_BLOOD_PRESS, [80, 120], true]; _unit setVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES, true]; -_unit setVariable [VAR_PERIPH_RES_ADJ, [], true]; _unit setVariable [VAR_CRDC_ARRST, false, true]; _unit setVariable [VAR_HEMORRHAGE, 0, true]; -_unit setVariable [VAR_IS_BLEEDING, false, true]; // - Pain --------------------------------------------------------------------- _unit setVariable [VAR_PAIN, 0, true]; _unit setVariable [VAR_IN_PAIN, false, true]; _unit setVariable [VAR_PAIN_SUPP, 0, true]; -_unit setVariable [VAR_PAIN_SUPP_ADJ, [], true]; // - Wounds ------------------------------------------------------------------- _unit setVariable [QEGVAR(medical,openWounds), [], true]; @@ -65,11 +61,7 @@ _unit setVariable [QEGVAR(medical,bodyPartStatus), [0,0,0,0,0,0], true]; #endif // medication -private _allUsedMedication = _unit getVariable [QEGVAR(medical,allUsedMedication), []]; -{ - _unit setVariable [_x select 0, nil]; -} forEach _allUsedMedication; -_unit setVariable [QEGVAR(medical,allUsedMedication), [], true]; +_unit setVariable [VAR_MEDICATIONS, [], true]; // TODO move to treatment private _logs = _unit getVariable [QEGVAR(medical,allLogs), []]; diff --git a/addons/medical_status/functions/fnc_isInStableCondition.sqf b/addons/medical_status/functions/fnc_isInStableCondition.sqf index ae67ce286e..c4ee84b58e 100644 --- a/addons/medical_status/functions/fnc_isInStableCondition.sqf +++ b/addons/medical_status/functions/fnc_isInStableCondition.sqf @@ -19,5 +19,5 @@ params ["_unit"]; (alive _unit && {!IS_UNCONSCIOUS(_unit)} - && {GET_BLOOD_LOSS(_unit) == 0} + && {GET_WOUND_BLEEDING(_unit) == 0} && {_unit call FUNC(hasStableVitals)}) diff --git a/addons/medical_status/functions/fnc_updateWoundBloodLoss.sqf b/addons/medical_status/functions/fnc_updateWoundBloodLoss.sqf new file mode 100644 index 0000000000..037a098c9d --- /dev/null +++ b/addons/medical_status/functions/fnc_updateWoundBloodLoss.sqf @@ -0,0 +1,42 @@ +#include "script_component.hpp" +/* + * Author: Glowbal + * Update total wound bleeding based on open wounds and tourniquets + * + * Arguments: + * 0: The Unit + * + * Return Value: + * Nothing + * + * Example: + * [player] call ace_medical_status_fnc_updateWoundBloodLoss + * + * Public: No + */ + +params ["_unit"]; + +private _tourniquets = GET_TOURNIQUETS(_unit); +private _bodyPartBleeding = [0,0,0,0,0,0]; +{ + _x params ["", "_bodyPart", "_amountOf", "_bleeeding"]; + if (_tourniquets select _bodyPart == 0) then { + _bodyPartBleeding set [_bodyPart, (_bodyPartBleeding select _bodyPart) + (_amountOf * _bleeeding)]; + }; +} forEach (_unit getVariable [QEGVAR(medical,openWounds), []]); + +if (_bodyPartBleeding isEqualTo [0,0,0,0,0,0]) then { + TRACE_1("updateWoundBloodLoss-none",_unit); + _unit setVariable [VAR_WOUND_BLEEDING, 0, true]; +} else { + _bodyPartBleeding params ["_headBleeding", "_bodyBleeding", "_leftArmBleeding", "_rightArmBleeding", "_leftLegBleeding", "_rightLegBleeding"]; + private _bodyBleedingRate = ((_headBleeding min 0.9) + (_bodyBleeding min 1.0)) min 1.0; + private _limbBleedingRate = ((_leftArmBleeding min 0.3) + (_rightArmBleeding min 0.3) + (_leftLegBleeding min 0.5) + (_rightLegBleeding min 0.5)) min 1.0; + + // limb bleeding is scaled down based on the amount of body bleeding + _limbBleedingRate = _limbBleedingRate * (1 - _bodyBleedingRate); + + TRACE_3("updateWoundBloodLoss-bleeding",_unit,_bodyBleedingRate,_limbBleedingRate); + _unit setVariable [VAR_WOUND_BLEEDING, _bodyBleedingRate + _limbBleedingRate, true]; +}; diff --git a/addons/medical_status/script_component.hpp b/addons/medical_status/script_component.hpp index 2030cedb6a..324fb88078 100644 --- a/addons/medical_status/script_component.hpp +++ b/addons/medical_status/script_component.hpp @@ -14,5 +14,5 @@ #define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_STATUS #endif -#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#include "\z\ace\addons\main\script_macros.hpp" diff --git a/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp b/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp index e9c79b64f5..0e408bd76c 100644 --- a/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp +++ b/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp @@ -91,6 +91,19 @@ class GVAR(actions) { condition = QUOTE([ARR_2(_patient,_bodyPart)] call FUNC(hasTourniquetAppliedTo)); callbackSuccess = QFUNC(tourniquetRemove); }; + // --- splint + class Splint: BasicBandage { + displayName = CSTRING(Apply_Splint); + displayNameProgress = CSTRING(Applying_Splint); + category = "bandage"; + icon = QPATHTOEF(medical_gui,ui\splint.paa); + allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"}; + items[] = {"ACE_splint"}; + treatmentTime = 7; + callbackSuccess = QFUNC(splint); + condition = QUOTE(call FUNC(splintCondition)); + litter[] = {}; + }; // - Syringes ------------------------------------------------------------- class Morphine: FieldDressing { diff --git a/addons/medical_treatment/CfgWeapons.hpp b/addons/medical_treatment/CfgWeapons.hpp index 329b2ab061..83ec942c36 100644 --- a/addons/medical_treatment/CfgWeapons.hpp +++ b/addons/medical_treatment/CfgWeapons.hpp @@ -69,6 +69,17 @@ class CfgWeapons { mass = 2; }; }; + class ACE_splint: ACE_ItemCore { + scope = 2; + author = ECSTRING(common,ACETeam); + displayName = CSTRING(splint_Display); + picture = QPATHTOF(ui\items\tourniquet_x_ca.paa); + model = QPATHTOF(data\tourniquet.p3d); + descriptionShort = CSTRING(splint_Desc_Short); + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 2; + }; + }; class ACE_morphine: ACE_ItemCore { scope = 2; author = ECSTRING(common,ACETeam); diff --git a/addons/medical_treatment/XEH_PREP.hpp b/addons/medical_treatment/XEH_PREP.hpp index 100850078e..5b63848b66 100644 --- a/addons/medical_treatment/XEH_PREP.hpp +++ b/addons/medical_treatment/XEH_PREP.hpp @@ -36,6 +36,10 @@ PREP(tourniquet); PREP(tourniquetLocal); PREP(tourniquetRemove); +PREP(splint); +PREP(splintCondition); +PREP(splintLocal); + // misc PREP(addToLog); PREP(addToTriageCard); diff --git a/addons/medical_treatment/XEH_postInit.sqf b/addons/medical_treatment/XEH_postInit.sqf index 5fe9884279..d9ac161ffc 100644 --- a/addons/medical_treatment/XEH_postInit.sqf +++ b/addons/medical_treatment/XEH_postInit.sqf @@ -16,6 +16,7 @@ if (isServer) then { [QGVAR(treatmentIVLocal), FUNC(treatmentIVLocal)] call CBA_fnc_addEventHandler; [QGVAR(treatmentCPRLocal), FUNC(treatmentCPRLocal)] call CBA_fnc_addEventHandler; [QGVAR(treatmentFullHealLocal), FUNC(treatmentFullHealLocal)] call CBA_fnc_addEventHandler; +[QGVAR(treatmentSplintLocal), FUNC(splintLocal)] call CBA_fnc_addEventHandler; // action events [QGVAR(checkPulseLocal), FUNC(checkPulseLocal)] call CBA_fnc_addEventHandler; diff --git a/addons/medical_treatment/functions/fnc_bandageLocal.sqf b/addons/medical_treatment/functions/fnc_bandageLocal.sqf index f9d090bee7..1a81670dd8 100644 --- a/addons/medical_treatment/functions/fnc_bandageLocal.sqf +++ b/addons/medical_treatment/functions/fnc_bandageLocal.sqf @@ -34,9 +34,10 @@ _targetWound params ["_wound", "_woundIndex", "_effectiveness"]; if (_effectiveness == -1) exitWith {}; // Find the impact this bandage has and reduce the amount this injury is present -private _amountOf = _wound select 3; +private _amountOf = _wound select 2; private _impact = _effectiveness min _amountOf; -_wound set [3, _amountOf - _impact]; +_amountOf = _amountOf - _impact; +_wound set [2, _amountOf]; _openWounds set [_woundIndex, _wound]; _patient setVariable [QEGVAR(medical,openWounds), _openWounds, true]; @@ -45,3 +46,10 @@ _patient setVariable [QEGVAR(medical,openWounds), _openWounds, true]; if (_impact > 0 && {GVAR(advancedBandages) && {GVAR(woundReopening)}}) then { [_patient, _impact, _partIndex, _woundIndex, _wound, _bandage] call FUNC(handleBandageOpening); }; + +// Check if we fixed limping from this treatment +if ((EGVAR(medical,limping) == 1) && {_partIndex > 3} && {_amountOf <= 0} && {_target getVariable [QEGVAR(medical,isLimping), false]}) then { + [_patient] call EFUNC(medical_engine,updateDamageEffects); +}; + +true diff --git a/addons/medical_treatment/functions/fnc_canBandage.sqf b/addons/medical_treatment/functions/fnc_canBandage.sqf index 46c632c649..a67dbb7873 100644 --- a/addons/medical_treatment/functions/fnc_canBandage.sqf +++ b/addons/medical_treatment/functions/fnc_canBandage.sqf @@ -28,7 +28,7 @@ private _index = ALL_BODY_PARTS find toLower _bodyPart; private _canBandage = false; { - _x params ["", "", "_bodyPartN", "_amountOf", "_bleeding"]; + _x params ["", "_bodyPartN", "_amountOf", "_bleeding"]; // If any single wound on the bodypart is bleeding bandaging can go ahead if (_bodyPartN == _index && {_amountOf * _bleeding > 0}) exitWith { diff --git a/addons/medical_treatment/functions/fnc_findMostEffectiveWound.sqf b/addons/medical_treatment/functions/fnc_findMostEffectiveWound.sqf index a136e1be4a..7622106054 100644 --- a/addons/medical_treatment/functions/fnc_findMostEffectiveWound.sqf +++ b/addons/medical_treatment/functions/fnc_findMostEffectiveWound.sqf @@ -37,15 +37,14 @@ private _woundIndex = -1; private _effectivenessFound = -1; { - _x params ["", "_classID", "_partIndexN", "_amountOf", "_bleeding", "_damage", "_category"]; + _x params ["_classID", "_partIndexN", "_amountOf", "_bleeding", "_damage"]; // Ignore wounds on other bodyparts if (_partIndexN == _partIndex) then { private _woundEffectiveness = _effectiveness; // Select the classname from the wound classname storage - private _suffix = ["Minor", "Medium", "Large"] select _category; - private _className = format ["%1%2", EGVAR(medical_damage,woundClassNames) select _classID, _suffix]; + private _className = EGVAR(medical_damage,woundClassNamesComplex) select _classID; // Get the effectiveness of the bandage on this wound type if (isClass (_config >> _className)) then { diff --git a/addons/medical_treatment/functions/fnc_getBandageTime.sqf b/addons/medical_treatment/functions/fnc_getBandageTime.sqf index 442c7ee0b4..48fd27fdac 100644 --- a/addons/medical_treatment/functions/fnc_getBandageTime.sqf +++ b/addons/medical_treatment/functions/fnc_getBandageTime.sqf @@ -22,11 +22,13 @@ if (_partIndex < 0) exitWith { 0 }; private _targetWound = [_patient, _bandage, _partIndex] call FUNC(findMostEffectiveWound); _targetWound params ["_wound", "_woundIndex", "_effectiveness"]; +TRACE_3("findMostEffectiveWound",_wound,_woundIndex,_effectiveness); // Everything is patched up on this body part already if (_wound isEqualTo EMPTY_WOUND) exitWith { 0 }; -_wound params ["", "", "", "_amountOf", "_bloodloss", "_damage", "_category"]; +_wound params ["_classID", "", "_amountOf", "_bloodloss", "_damage"]; +private _category = (_classID % 10); // Base bandage time is based on wound size and remaining percentage private _bandageTime = ([ diff --git a/addons/medical_treatment/functions/fnc_handleBandageOpening.sqf b/addons/medical_treatment/functions/fnc_handleBandageOpening.sqf index 472c91441e..2c8b46b76e 100644 --- a/addons/medical_treatment/functions/fnc_handleBandageOpening.sqf +++ b/addons/medical_treatment/functions/fnc_handleBandageOpening.sqf @@ -18,13 +18,11 @@ */ params ["_target", "_impact", "_part", "_injuryIndex", "_injury", "_bandage"]; +TRACE_6("handleBandageOpening",_target,_impact,_part,_injuryIndex,_injury,_bandage); -private _classID = _injury select 1; -private _bodyPartN = _injury select 2; -private _category = _injury select 6; -private _postfix = ["Minor", "Medium", "Large"] select _category; -private _className = format ["%1%2", EGVAR(medical_damage,woundClassNames) select _classID, _postfix]; - +_injury params ["_classID", "_bodyPartN"]; + +private _className = EGVAR(medical_damage,woundClassNamesComplex) select _classID; private _reopeningChance = DEFAULT_BANDAGE_REOPENING_CHANCE; private _reopeningMinDelay = DEFAULT_BANDAGE_REOPENING_MIN_DELAY; private _reopeningMaxDelay = DEFAULT_BANDAGE_REOPENING_MAX_DELAY; @@ -63,22 +61,27 @@ TRACE_5("configs",_bandage,_className,_reopeningChance,_reopeningMinDelay,_reope private _bandagedWounds = _target getVariable [QEGVAR(medical,bandagedWounds), []]; private _exist = false; { - _x params ["", "_id", "_partN", "_amountOf", "_bleeding", "_damage", "_oldCategory"]; - if (_id == _classID && {_partN == _bodyPartN && {_oldCategory == _category}}) exitWith { - _x set [3, _amountOf + _impact]; - _bandagedWounds set [_forEachIndex, _x]; + _x params ["_id", "_partN", "_amountOf"]; + if (_id == _classID && {_partN == _bodyPartN}) exitWith { + _x set [2, _amountOf + _impact]; + TRACE_2("adding to existing bandagedWound",_id,_partN); _exist = true; }; } forEach _bandagedWounds; if (!_exist) then { + TRACE_2("adding new bandagedWound",_classID,_bodyPartN); private _bandagedInjury = +_injury; - _bandagedInjury set [3, _impact]; + _bandagedInjury set [2, _impact]; _bandagedWounds pushBack _bandagedInjury; }; _target setVariable [QEGVAR(medical,bandagedWounds), _bandagedWounds, true]; +// _reopeningChance = 1; +// _reopeningMinDelay = 5; +// _reopeningMaxDelay = 6; + TRACE_1("",_reopeningChance); // Check if we are ever going to reopen this if (random 1 <= _reopeningChance) then { @@ -86,33 +89,42 @@ if (random 1 <= _reopeningChance) then { TRACE_1("Will open",_delay); [{ params ["_target", "_impact", "_part", "_injuryIndex", "_injury"]; - TRACE_5("params",_target,_impact,_part,_injuryIndex,_injury); + TRACE_5("reopen delay finished",_target,_impact,_part,_injuryIndex,_injury); private _openWounds = _target getVariable [QEGVAR(medical,openWounds), []]; - if (count _openWounds - 1 < _injuryIndex) exitWith {}; + if (count _openWounds - 1 < _injuryIndex) exitWith { TRACE_2("index bounds",_injuryIndex,count _openWounds); }; + + _injury params ["_classID", "_bodyPartN"]; - _injury params ["", "_classID", "_bodyPartN"]; - private _selectedInjury = _openWounds select _injuryIndex; - if (_selectedInjury select 1 == _classID && {_selectedInjury select 2 == _bodyPartN}) then { // matching the IDs + _selectedInjury params ["_selClassID", "_selBodyPart", "_selAmmount"]; + if ((_selClassID == _classID) && {_selBodyPart == _bodyPartN}) then { // matching the IDs private _bandagedWounds = _target getVariable [QEGVAR(medical,bandagedWounds), []]; private _exist = false; { - _x params ["", "_id", "_partN", "_amountOf", "_bleeding", "_damage", "_oldCategory"]; - if (_id == _classID && {_partN == _bodyPartN && {_oldCategory == _category}}) exitWith { - _x set [3, 0 max (_amountOf - _impact)]; - _bandagedWounds set [_forEachIndex, _x]; + _x params ["_id", "_partN", "_amountOf"]; + if ((_id == _classID) && {_partN == _bodyPartN}) exitWith { + TRACE_2("bandagedWound exists",_id,_classID); + _x set [2, 0 max (_amountOf - _impact)]; _exist = true; }; } forEach _bandagedWounds; if (_exist) then { TRACE_2("Reopening Wound",_bandagedWounds,_openWounds); - _selectedInjury set [3, (_selectedInjury select 3) + _impact]; - _openWounds set [_injuryIndex, _selectedInjury]; + _selectedInjury set [2, _selAmmount + _impact]; _target setVariable [QEGVAR(medical,bandagedWounds), _bandagedWounds, true]; _target setVariable [QEGVAR(medical,openWounds), _openWounds, true]; + + [_target] call EFUNC(medical_status,updateWoundBloodLoss); + + // Check if we gained limping from this wound re-opening + if ((EGVAR(medical,limping) == 1) && {_bodyPartN > 3}) then { + [_target] call EFUNC(medical_engine,updateDamageEffects); + }; }; + } else { + TRACE_3("no match",_selectedInjury,_classID,_bodyPartN); }; }, [_target, _impact, _part, _injuryIndex, +_injury], _delay] call CBA_fnc_waitAndExecute; }; diff --git a/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf b/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf index 2cb12cf389..219ad444cd 100644 --- a/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf +++ b/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf @@ -6,69 +6,69 @@ * Arguments: * 0: The patient * 1: Medication Treatment classname - * 2: The medication treatment variablename - * 3: Max dosage - * 4: Incompatable medication > + * 2: Max dosage + * 3: Incompatable medication > * * Return Value: * None * * Example: - * [bob, "classname", "varname", 5, 6, ["stuff"]] call ace_medical_treatment_fnc_onMedicationUsage + * [player, "morphine", 4, [["x", 1]]] call ace_medical_treatment_fnc_onMedicationUsage * * Public: No */ -params ["_target", "_className", "_variable", "_maxDosage", "_incompatabileMeds"]; -TRACE_5("params",_target,_className,_variable,_maxDosage,_incompatabileMeds); +params ["_target", "_className", "_maxDosage", "_incompatabileMeds"]; +TRACE_4("onMedicationUsage",_target,_className,_maxDosage,_incompatabileMeds); -private _foundEntry = false; -private _allUsedMedication = _target getVariable [QEGVAR(medical,allUsedMedication), []]; -{ - _x params ["_variableX", "_allMedsFromClassname"]; - if (_variableX == _variable) exitWith { - if !(_className in _allMedsFromClassname) then { - _allMedsFromClassname pushBack _className; - _x set [1, _allMedsFromClassname]; - _allUsedMedication set [_forEachIndex, _x]; - _target setVariable [QEGVAR(medical,allUsedMedication), _allUsedMedication]; - }; - _foundEntry = true; - }; -} forEach _allUsedMedication; - -if (!_foundEntry) then { - _allUsedMedication pushBack [_variable, [_className]]; - _target setVariable [QEGVAR(medical,allUsedMedication), _allUsedMedication]; -}; - -private _usedMeds = _target getVariable [_variable, 0]; -if (_usedMeds >= floor (_maxDosage + round(random(2))) && {_maxDosage >= 1}) then { - [QEGVAR(medical,CriticalVitals), _target] call CBA_fnc_localEvent; -}; - -private _hasOverDosed = 0; -{ - _x params ["_med", "_limit"]; +private _fnc_getMedicationCount = { + params ["_target", "_medication"]; + private _return = 0; { - _x params ["", "_classNamesUsed"]; - if ({_x == _med} count _classNamesUsed > _limit) then { - _hasOverDosed = _hasOverDosed + 1; + _x params ["_xMed", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem"]; + if (_xMed == _medication) then { + private _timeInSystem = CBA_missionTime - _timeAdded; + _return = _return + linearConversion [_timeTillMaxEffect, _maxTimeInSystem, _timeInSystem, 1, 0, true]; }; - } forEach _allUsedMedication; + } forEach (_target getVariable [VAR_MEDICATIONS, []]); + TRACE_2("getMedicationCount",_medication,_return); + _return +}; + +private _overdosedMedications = []; + +// Check for overdose from current medication +private _currentDose = [_target, _className] call _fnc_getMedicationCount; +if (_currentDose >= floor (_maxDosage + round(random(2))) && {_maxDosage >= 1}) then { + TRACE_1("exceeded max dose",_currentDose); + _overdosedMedications pushBackUnique _className; +}; + +// Check incompatible medication (format [med,limit]) +{ + _x params ["_xMed", "_xLimit"]; + private _inSystem = [_target, _xMed] call _fnc_getMedicationCount; + if (_inSystem> _xLimit) then { + _overdosedMedications pushBackUnique _xMed; + }; } forEach _incompatabileMeds; -if (_hasOverDosed > 0) then { +if ((count _overdosedMedications) > 0) then { private _medicationConfig = (configFile >> "ace_medical_treatment" >> "Medication"); private _onOverDose = getText (_medicationConfig >> "onOverDose"); if (isClass (_medicationConfig >> _className)) then { _medicationConfig = (_medicationConfig >> _className); - if (isText (_medicationConfig >> "onOverDose")) then { _onOverDose = getText (_medicationConfig >> "onOverDose"); }; + if (isText (_medicationConfig >> "onOverDose")) then { _onOverDose = getText (_medicationConfig >> "onOverDose"); }; + }; + TRACE_2("overdose",_overdosedMedications,_onOverDose); + if (_onOverDose == "") exitWith { + TRACE_1("CriticalVitals Event",_target); // make unconscious + [QEGVAR(medical,CriticalVitals), _target] call CBA_fnc_localEvent; }; if (isNil _onOverDose) then { _onOverDose = compile _onOverDose; } else { _onOverDose = missionNamespace getVariable _onOverDose; }; - [_target, _className] call _onOverDose; + [_target, _className, _overdosedMedications] call _onOverDose; }; diff --git a/addons/medical_treatment/functions/fnc_splint.sqf b/addons/medical_treatment/functions/fnc_splint.sqf new file mode 100644 index 0000000000..4ced63109c --- /dev/null +++ b/addons/medical_treatment/functions/fnc_splint.sqf @@ -0,0 +1,25 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror + * Apply a splint to the patient + * + * Arguments: + * 0: The medic + * 1: The patient + * 2: Body part + * + * Return Value: + * Nothing + * + * Example: + * [player, cursorObject, "LeftLeg"] call ace_medical_treatment_fnc_splint + * + * Public: No + */ + +params ["_caller", "_target", "_bodyPart"]; +TRACE_3("splint",_caller,_target,_bodyPart); + +private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; + +[QGVAR(treatmentSplintLocal), [_caller, _target, _partIndex], _target] call CBA_fnc_targetEvent; diff --git a/addons/medical_treatment/functions/fnc_splintCondition.sqf b/addons/medical_treatment/functions/fnc_splintCondition.sqf new file mode 100644 index 0000000000..3978518529 --- /dev/null +++ b/addons/medical_treatment/functions/fnc_splintCondition.sqf @@ -0,0 +1,25 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror + * Can apply a splint to the patient + * + * Arguments: + * 0: The medic + * 1: The patient + * 2: Body part + * + * Return Value: + * Nothing + * + * Example: + * [player, cursorObject, "LeftLeg"] call ace_medical_treatment_fnc_splintCondition + * + * Public: No + */ + +params ["", "_target", "_bodyPart"]; + +private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; +private _fractures = _unit getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]]; + +(_fractures select _partIndex) == 1 diff --git a/addons/medical_treatment/functions/fnc_splintLocal.sqf b/addons/medical_treatment/functions/fnc_splintLocal.sqf new file mode 100644 index 0000000000..1996e8321a --- /dev/null +++ b/addons/medical_treatment/functions/fnc_splintLocal.sqf @@ -0,0 +1,31 @@ +#include "script_component.hpp" +/* + * Author: PabstMirror + * Apply a splint to the patient + * + * Arguments: + * 0: The medic + * 1: The patient + * 2: Body part index + * + * Return Value: + * Nothing + * + * Example: + * [player, cursorObject, 4] call ace_medical_treatment_fnc_splintLocal + * + * Public: No + */ + +params ["_caller", "_target", "_bodyPartNum"]; +TRACE_3("splintLocal",_caller,_target,_bodyPart); + +// Place a tourniquet on the bodypart +private _fractures = _target getVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0]]; +_fractures set [_bodyPartNum, -1]; +_target setVariable [QEGVAR(medical,fractures), _fractures, true]; + +// Check if we fixed limping from this treatment +[_target] call EFUNC(medical_engine,updateDamageEffects); + +// toDo: AddToLog: diff --git a/addons/medical_treatment/functions/fnc_treatmentFullHealLocal.sqf b/addons/medical_treatment/functions/fnc_treatmentFullHealLocal.sqf index 4dfa555828..014b102834 100644 --- a/addons/medical_treatment/functions/fnc_treatmentFullHealLocal.sqf +++ b/addons/medical_treatment/functions/fnc_treatmentFullHealLocal.sqf @@ -39,13 +39,15 @@ _target setVariable [QEGVAR(medical,openWounds), [], true]; _target setVariable [QEGVAR(medical,bandagedWounds), [], true]; _target setVariable [QEGVAR(medical,stitchedWounds), [], true]; _target setVariable [QEGVAR(medical,isLimping), false, true]; +_target setVariable [QEGVAR(medical,fractures), [0,0,0,0,0,0], true]; + +// - Update wound bleeding +[_target] call EFUNC(medical_status,updateWoundBloodLoss); // vitals _target setVariable [VAR_HEART_RATE, DEFAULT_HEART_RATE, true]; -_target setVariable [VAR_HEART_RATE_ADJ, [], true]; _target setVariable [VAR_BLOOD_PRESS, [80, 120], true]; _target setVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES, true]; -_target setVariable [VAR_PERIPH_RES_ADJ, [], true]; // IVs _target setVariable [QEGVAR(medical,ivBags), nil, true]; @@ -60,22 +62,16 @@ _target setVariable [QEGVAR(medical,bodyPartStatus), [0,0,0,0,0,0], true]; _target setVariable [VAR_CRDC_ARRST, false, true]; _target setVariable [VAR_UNCON, false, true]; _target setVariable [VAR_HEMORRHAGE, 0, true]; -_target setVariable [VAR_IS_BLEEDING, false, true]; _target setVariable [VAR_IN_PAIN, false, true]; _target setVariable [VAR_PAIN_SUPP, 0, true]; -_target setVariable [VAR_PAIN_SUPP_ADJ, [], true]; // medication -private _allUsedMedication = _target getVariable [QEGVAR(medical,allUsedMedication), []]; - -{ - _target setVariable [_x select 0, nil]; -} forEach _allUsedMedication; +_target setVariable [VAR_MEDICATIONS, [], true]; // Reset triage card since medication is all reset _target setVariable [QEGVAR(medical,triageCard), [], true]; -[_target, false] call EFUNC(medical_engine,setLimping); +[_target] call EFUNC(medical_engine,updateDamageEffects); // Resetting damage _target setDamage 0; diff --git a/addons/medical_treatment/script_component.hpp b/addons/medical_treatment/script_component.hpp index 913571642a..61cb53fcb7 100644 --- a/addons/medical_treatment/script_component.hpp +++ b/addons/medical_treatment/script_component.hpp @@ -2,8 +2,8 @@ #define COMPONENT_BEAUTIFIED Medical Treatment #include "\z\ace\addons\main\script_mod.hpp" -#define DEBUG_MODE_FULL -#define DISABLE_COMPILE_CACHE +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE // #define ENABLE_PERFORMANCE_COUNTERS #ifdef DEBUG_ENABLED_MEDICAL_TREATMENT @@ -14,8 +14,8 @@ #define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_TREATMENT #endif -#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#include "\z\ace\addons\main\script_macros.hpp" #define GET_FUNCTION(var,cfg) \ private var = getText (cfg); \ diff --git a/addons/medical_treatment/stringtable.xml b/addons/medical_treatment/stringtable.xml index f444224f0b..fc9662d128 100644 --- a/addons/medical_treatment/stringtable.xml +++ b/addons/medical_treatment/stringtable.xml @@ -646,6 +646,12 @@ 用于压迫静脉与动脉的血液流动, 达到减缓失血速度的目的 用於壓迫靜脈與動脈的血液流動, 達到減緩失血速度的目的 + + Splint + + + Stabilizes a fractured limb + Morphine autoinjector Morphium-Autoinjektor @@ -1841,6 +1847,12 @@ 移除军用止血带 移除軍用止血帶 + + Apply Splint + + + Applying Splint... + Diagnose Diagnose diff --git a/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf b/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf index e5fbc51704..64c8b0cd4c 100644 --- a/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf +++ b/addons/medical_vitals/functions/fnc_handleUnitVitals.sqf @@ -51,17 +51,7 @@ if (_hemorrhage != GET_HEMORRHAGE(_unit)) then { _unit setVariable [VAR_HEMORRHAGE, _hemorrhage, true]; }; -private _bloodLoss = GET_BLOOD_LOSS(_unit); -if (_bloodLoss > 0) then { - _unit setVariable [QGVAR(bloodloss), _bloodLoss, _syncValues]; - if !IS_BLEEDING(_unit) then { - _unit setVariable [VAR_IS_BLEEDING, true, true]; - }; -} else { - if IS_BLEEDING(_unit) then { - _unit setVariable [VAR_IS_BLEEDING, false, true]; - }; -}; +private _woundBloodLoss = GET_WOUND_BLEEDING(_unit); private _inPain = GET_PAIN_PERCEIVED(_unit) > 0; if !(_inPain isEqualTo IS_IN_PAIN(_unit)) then { @@ -80,17 +70,43 @@ if (_tourniquetPain > 0) then { [_unit, _tourniquetPain] call EFUNC(medical_status,adjustPainLevel); }; -private _heartRate = [_unit, _deltaT, _syncValues] call FUNC(updateHeartRate); -[_unit, _deltaT, _syncValues] call FUNC(updatePainSuppress); -[_unit, _deltaT, _syncValues] call FUNC(updatePeripheralResistance); +// Get Medication Adjustments: +private _hrTargetAdjustment = 0; +private _painSupressAdjustment = 0; +private _peripheralResistanceAdjustment = 0; +private _adjustments = _unit getVariable [VAR_MEDICATIONS,[]]; + +if !(_adjustments isEqualTo []) then { + private _deleted = false; + { + _x params ["_medication", "_timeAdded", "_timeTillMaxEffect", "_maxTimeInSystem", "_hrAdjust", "_painAdjust", "_flowAdjust"]; + private _timeInSystem = CBA_missionTime - _timeAdded; + if (_timeInSystem >= _maxTimeInSystem) then { + _deleted = true; + _adjustments set [_forEachIndex, objNull]; + } else { + private _effectRatio = (((_timeInSystem / _timeTillMaxEffect) ^ 2) min 1) * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem; + if (_hrAdjust != 0) then { _hrTargetAdjustment = _hrTargetAdjustment + _hrAdjust * _effectRatio; }; + if (_painAdjust != 0) then { _painSupressAdjustment = _painSupressAdjustment + _painAdjust * _effectRatio; }; + if (_hrAdjust != 0) then { _peripheralResistanceAdjustment = _peripheralResistanceAdjustment + _flowAdjust * _effectRatio; }; + }; + } forEach _adjustments; + + if (_deleted) then { + _unit setVariable [VAR_MEDICATIONS, _adjustments - [objNull], true]; + _syncValues = true; + }; +}; + +private _heartRate = [_unit, _hrTargetAdjustment, _deltaT, _syncValues] call FUNC(updateHeartRate); +[_unit, _painSupressAdjustment, _deltaT, _syncValues] call FUNC(updatePainSuppress); +[_unit, _peripheralResistanceAdjustment, _deltaT, _syncValues] call FUNC(updatePeripheralResistance); private _bloodPressure = GET_BLOOD_PRESSURE(_unit); _unit setVariable [VAR_BLOOD_PRESS, _bloodPressure, _syncValues]; _bloodPressure params ["_bloodPressureL", "_bloodPressureH"]; -private _cardiacOutput = [_unit] call EFUNC(medical_status,getCardiacOutput); - // Statements are ordered by most lethal first. switch (true) do { case (_bloodVolume < BLOOD_VOLUME_FATAL): { @@ -114,11 +130,11 @@ switch (true) do { [QEGVAR(medical,FatalVitals), _unit] call CBA_fnc_localEvent; }; case (_heartRate < 30): { // With a heart rate below 30 but bigger than 20 there is a chance to enter the cardiac arrest state - private _nextCheck = _unit getVariable [QGVAR(lastCheckCriticalHeartRate), CBA_missionTime]; + private _nextCheck = _unit getVariable [QGVAR(nextCheckCriticalHeartRate), CBA_missionTime]; private _enterCardiacArrest = false; if (CBA_missionTime >= _nextCheck) then { _enterCardiacArrest = random 1 < (0.4 + 0.6*(30 - _heartRate)/10); // Variable chance of getting into cardiac arrest. - _unit setVariable [QGVAR(lastCheckCriticalHeartRate), CBA_missionTime + 5]; + _unit setVariable [QGVAR(nextCheckCriticalHeartRate), CBA_missionTime + 5]; }; if (_enterCardiacArrest) then { TRACE_2("Heart rate critical. Cardiac arrest",_unit,_heartRate); @@ -128,10 +144,10 @@ switch (true) do { [QEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent; }; }; - case (_bloodLoss / EGVAR(medical,bleedingCoefficient) > BLOOD_LOSS_KNOCK_OUT_THRESHOLD * _cardiacOutput): { + case (_woundBloodLoss > BLOOD_LOSS_KNOCK_OUT_THRESHOLD): { [QEGVAR(medical,CriticalVitals), _unit] call CBA_fnc_localEvent; }; - case (_bloodLoss > 0): { + case (_woundBloodLoss > 0): { [QEGVAR(medical,LoweredVitals), _unit] call CBA_fnc_localEvent; }; case (_inPain): { @@ -140,9 +156,10 @@ switch (true) do { }; #ifdef DEBUG_MODE_FULL +private _cardiacOutput = [_unit] call EFUNC(medical_status,getCardiacOutput); if (!isPlayer _unit) then { private _painLevel = _unit getVariable [VAR_PAIN, 0]; - hintSilent format["blood volume: %1, blood loss: [%2, %3]\nhr: %4, bp: %5, pain: %6", round(_bloodVolume * 100) / 100, round(_bloodLoss * 1000) / 1000, round((_bloodLoss / (0.001 max _cardiacOutput)) * 100) / 100, round(_heartRate), _bloodPressure, round(_painLevel * 100) / 100]; + hintSilent format["blood volume: %1, blood loss: [%2, %3]\nhr: %4, bp: %5, pain: %6", round(_bloodVolume * 100) / 100, round(_woundBloodLoss * 1000) / 1000, round((_woundBloodLoss / (0.001 max _cardiacOutput)) * 100) / 100, round(_heartRate), _bloodPressure, round(_painLevel * 100) / 100]; }; #endif diff --git a/addons/medical_vitals/functions/fnc_updateHeartRate.sqf b/addons/medical_vitals/functions/fnc_updateHeartRate.sqf index 0946a76202..b7abb89a24 100644 --- a/addons/medical_vitals/functions/fnc_updateHeartRate.sqf +++ b/addons/medical_vitals/functions/fnc_updateHeartRate.sqf @@ -5,42 +5,20 @@ * * Arguments: * 0: The Unit - * 1: Time since last update - * 2: Sync value? + * 1: Heart Rate Adjustments + * 2: Time since last update + * 3: Sync value? * * ReturnValue: * Current Heart Rate * * Example: - * [player, 1, false] call ace_medical_vitals_fnc_updateHeartRate + * [player, 0, 1, false] call ace_medical_vitals_fnc_updateHeartRate * * Public: No */ -params ["_unit", "_deltaT", "_syncValue"]; - -private _hrTargetAdjustment = 0; -private _adjustments = _unit getVariable [VAR_HEART_RATE_ADJ,[]]; - -if !(_adjustments isEqualTo []) then { - { - _x params ["_value", "_timeTillMaxEffect", "_maxTimeInSystem", "_timeInSystem"]; - if (_value != 0 && {_maxTimeInSystem > 0}) then { - if (_timeInSystem >= _maxTimeInSystem) then { - _adjustments set [_forEachIndex, nil]; - } else { - _timeInSystem = _timeInSystem + _deltaT; - private _effectRatio = ((_timeInSystem / (1 max _timeTillMaxEffect)) ^ 2) min 1; - _hrTargetAdjustment = _hrTargetAdjustment + _value * _effectRatio * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem; - _x set [3, _timeInSystem]; - }; - } else { - _adjustments set [_forEachIndex, nil]; - }; - } forEach _adjustments; - - _unit setVariable [VAR_HEART_RATE_ADJ, _adjustments - [nil], _syncValue]; -}; +params ["_unit", "_hrTargetAdjustment", "_deltaT", "_syncValue"]; private _heartRate = GET_HEART_RATE(_unit); diff --git a/addons/medical_vitals/functions/fnc_updatePainSuppress.sqf b/addons/medical_vitals/functions/fnc_updatePainSuppress.sqf index 2bdab699ab..1015549d62 100644 --- a/addons/medical_vitals/functions/fnc_updatePainSuppress.sqf +++ b/addons/medical_vitals/functions/fnc_updatePainSuppress.sqf @@ -5,45 +5,26 @@ * * Arguments: * 0: The Unit - * 1: Time since last update - * 2: Sync value? + * 1: Pain Suppress Adjustments + * 2: Time since last update + * 3: Sync value? * * Return Value: * None * + * Example: + * [player, 0, 1, false] call ace_medical_vitals_fnc_updatePainSuppress + * * Public: No */ -params ["_unit", "_deltaT", "_syncValue"]; +params ["_unit", "_painSupressAdjustment", "_deltaT", "_syncValue"]; -private _painSupressAdjustment = 0; -private _adjustments = _unit getVariable [VAR_PAIN_SUPP_ADJ, []]; - -if !(_adjustments isEqualTo []) then { - { - _x params ["_value", "_timeTillMaxEffect", "_maxTimeInSystem", "_timeInSystem"]; - if (_value != 0 && {_maxTimeInSystem > 0}) then { - if (_timeInSystem >= _maxTimeInSystem) then { - _adjustments set [_forEachIndex, nil]; - } else { - _timeInSystem = _timeInSystem + _deltaT; - private _effectRatio = ((_timeInSystem / (1 max _timeTillMaxEffect)) ^ 2) min 1; - _painSupressAdjustment = _painSupressAdjustment + _value * _effectRatio * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem; - _x set [3, _timeInSystem]; - }; - } else { - _adjustments set [_forEachIndex, nil]; - }; - } forEach _adjustments; - - _unit setVariable [VAR_PAIN_SUPP_ADJ, _adjustments - [nil], (_syncValue || {_adjustments isEqualTo []})]; // always sync on last run - - _unit setVariable [VAR_PAIN_SUPP, 0 max _painSupressAdjustment, _syncValue]; -}; +_unit setVariable [VAR_PAIN_SUPP, 0 max _painSupressAdjustment, _syncValue]; // Handle continuous pain reduction private _pain = GET_PAIN(_unit); -_unit setVariable [QEGVAR(medical_status,pain), 0 max (_pain - _deltaT / PAIN_FADE_TIME), _syncValue]; +_unit setVariable [VAR_PAIN, 0 max (_pain - _deltaT / PAIN_FADE_TIME), _syncValue]; // Handles simple medication if (isNil QEGVAR(medical_treatment,advancedMedication) || {!EGVAR(medical_treatment,advancedMedication)}) then { diff --git a/addons/medical_vitals/functions/fnc_updatePeripheralResistance.sqf b/addons/medical_vitals/functions/fnc_updatePeripheralResistance.sqf index cdbf0d926c..c5552143c7 100644 --- a/addons/medical_vitals/functions/fnc_updatePeripheralResistance.sqf +++ b/addons/medical_vitals/functions/fnc_updatePeripheralResistance.sqf @@ -5,39 +5,19 @@ * * Arguments: * 0: The Unit - * 1: Time since last update - * 2: Sync value? + * 1: Peripheral Resistance Adjustments + * 2: Time since last update + * 3: Sync value? * * Return Value: * None * + * Example: + * [player, 0, 1, false] call ace_medical_vitals_fnc_updatePeripheralResistance + * * Public: No */ -params ["_unit", "_deltaT", "_syncValue"]; +params ["_unit", "_peripheralResistanceAdjustment", "_deltaT", "_syncValue"]; -private _peripheralResistanceAdjustment = 0; -private _adjustments = _unit getVariable [VAR_PERIPH_RES_ADJ, []]; - -if !(_adjustments isEqualTo []) then { - { - _x params ["_value", "_timeTillMaxEffect", "_maxTimeInSystem", "_timeInSystem"]; - if (_value != 0 && {_maxTimeInSystem > 0}) then { - if (_timeInSystem >= _maxTimeInSystem) then { - _adjustments set [_forEachIndex, nil]; - } else { - _timeInSystem = _timeInSystem + _deltaT; - private _effectRatio = ((_timeInSystem / (1 max _timeTillMaxEffect)) ^ 2) min 1; - _peripheralResistanceAdjustment = _peripheralResistanceAdjustment + _value * _effectRatio * (_maxTimeInSystem - _timeInSystem) / _maxTimeInSystem; - _x set [3, _timeInSystem]; - }; - } else { - _adjustments set [_forEachIndex, nil]; - }; - } forEach _adjustments; - - _unit setVariable [VAR_PERIPH_RES_ADJ, _adjustments - [nil], _syncValue]; - - // always sync on last run - _unit setVariable [VAR_PERIPH_RES, 0 max (DEFAULT_PERIPH_RES + _peripheralResistanceAdjustment), _syncValue || {_adjustments isEqualTo []}]; -}; +_unit setVariable [VAR_PERIPH_RES, 0 max (DEFAULT_PERIPH_RES + _peripheralResistanceAdjustment), _syncValue]; diff --git a/addons/medical_vitals/script_component.hpp b/addons/medical_vitals/script_component.hpp index cf5452e193..3bfb4bcc26 100644 --- a/addons/medical_vitals/script_component.hpp +++ b/addons/medical_vitals/script_component.hpp @@ -14,5 +14,5 @@ #define DEBUG_SETTINGS DEBUG_SETTINGS_MEDICAL_VITALS #endif -#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp" +#include "\z\ace\addons\main\script_macros.hpp"