diff --git a/addons/medical/ACE_Medical_StateMachine.hpp b/addons/medical/ACE_Medical_StateMachine.hpp index 29cb1e8962..8ea5286916 100644 --- a/addons/medical/ACE_Medical_StateMachine.hpp +++ b/addons/medical/ACE_Medical_StateMachine.hpp @@ -6,15 +6,15 @@ class ACE_Medical_StateMachine { onState = QUOTE(DFUNC(handleStateDefault)); class Injury { targetState = "Injured"; - events[] = {QGVAR(TakenInjury)}; + events[] = {QGVAR(Injury)}; }; class CriticalInjuryOrVitals { targetState = "Unconscious"; - events[] = {QGVAR(InjuryCritical), QGVAR(CriticalVitals)}; + events[] = {QGVAR(CriticalInjury), QGVAR(CriticalVitals)}; }; class FatalInjury { targetState = "FatalInjury"; - events[] = {QGVAR(InjuryFatal)}; + events[] = {QGVAR(FatalInjury)}; }; }; class Injured { @@ -23,13 +23,9 @@ class ACE_Medical_StateMachine { targetState = "Default"; events[] = {QGVAR(FullHeal)}; }; - class LastWoundTreated { - targetState = "Default"; - events[] = {QGVAR(LastWoundTreated)}; - }; class CriticalInjuryOrVitals { targetState = "Unconscious"; - events[] = {QGVAR(InjuryCritical), QGVAR(CriticalVitals)}; + events[] = {QGVAR(CriticalInjury), QGVAR(CriticalVitals)}; }; class FatalVitals { targetState = "CardiacArrest"; @@ -37,30 +33,25 @@ class ACE_Medical_StateMachine { }; class FatalInjury { targetState = "FatalInjury"; - events[] = {QGVAR(InjuryFatal)}; + events[] = {QGVAR(FatalInjury)}; }; }; class Unconscious { onState = QUOTE(DFUNC(handleStateUnconscious)); - onStateEntered = QUOTE(DFUNC(enteredUnconsciousState)); - onStateLeaving = "_this setVariable ['ACE_isUnconscious', false, true];"; - class WakeUpFromKnockDown { + onStateEntered = QUOTE([ARR_2(_this,(true))] call FUNC(setUnconscious)); + onStateLeaving = QUOTE([ARR_2(_this,(false))] call FUNC(setUnconscious)); + class WakeUp { targetState = "Injured"; condition = QUOTE(_this call FUNC(hasStableVitals)); - events[] = {QGVAR(MinUnconsciousTimer)}; - }; - class WakeUpStable { - targetState = "Injured"; - condition = "unitUnconsciousTimer >= MinUnconsciousTimer"; - events[] = {QGVAR(VitalsWentStable)}; + events[] = {QGVAR(WakeUp)}; }; class FatalTransitions { targetState = "CardiacArrest"; - events[] = {QGVAR(FatalVitals), QGVAR(UnconsciousTimerRanOut)}; + events[] = {QGVAR(FatalVitals)}; }; class FatalInjury { targetState = "FatalInjury"; - events[] = {QGVAR(InjuryFatal)}; + events[] = {QGVAR(FatalInjury)}; }; }; class FatalInjury { @@ -81,19 +72,19 @@ class ACE_Medical_StateMachine { }; class CardiacArrest { onStateEntered = QUOTE(DFUNC(enteredStateCardiacArrest)); - onStateLeaving = '_this setVariable [QGVAR(cardiacArrestStart), nil]'; - class TimerRanOut { + onStateLeaving = QUOTE(DFUNC(leftStateCardiacArrest)); + class Timeout { targetState = "Dead"; condition = QUOTE(DFUNC(conditionCardiacArrestTimer)); }; - class Reanimated { + class Reanimation { targetState = "Unconscious"; events[] = {QGVAR(CPRSucceeded)}; }; class Execution { targetState = "Dead"; condition = QUOTE(DFUNC(conditionExecutionDeath)); - events[] = {QGVAR(InjuryFatal)}; + events[] = {QGVAR(FatalInjury)}; }; }; class Dead { diff --git a/addons/medical/ACE_Settings.hpp b/addons/medical/ACE_Settings.hpp index 5522b9e32b..beafc3a004 100644 --- a/addons/medical/ACE_Settings.hpp +++ b/addons/medical/ACE_Settings.hpp @@ -1,17 +1,9 @@ class ACE_Settings { - class GVAR(level) { - category = CSTRING(Category_Medical); - displayName = CSTRING(MedicalSettings_level_DisplayName); - description = CSTRING(MedicalSettings_level_Description); - value = 1; - typeName = "SCALAR"; - values[] = {"Disabled", "Basic", "Advanced"}; - }; class GVAR(medicSetting) { category = CSTRING(Category_Medical); displayName = CSTRING(MedicalSettings_medicSetting_DisplayName); description = CSTRING(MedicalSettings_medicSetting_Description); - value = 1; + value = 0; typeName = "SCALAR"; values[] = {"Disabled", "Normal", "Advanced"}; }; @@ -26,15 +18,10 @@ class ACE_Settings { category = CSTRING(Category_Medical); displayName = CSTRING(AdvancedMedicalSettings_enableFor_DisplayName); description = CSTRING(AdvancedMedicalSettings_enableFor_Description); - value = 0; + value = 1; typeName = "SCALAR"; values[] = {"Players only", "Players and AI"}; }; - class GVAR(enableOverdosing) { - category = CSTRING(Category_Medical); - typeName = "BOOL"; - value = 1; - }; class GVAR(bleedingCoefficient) { category = CSTRING(Category_Medical); displayName = CSTRING(MedicalSettings_bleedingCoefficient_DisplayName); @@ -49,22 +36,12 @@ class ACE_Settings { typeName = "SCALAR"; value = 1; }; - class GVAR(enableAirway) { - category = CSTRING(Category_Medical); - typeName = "BOOL"; - value = false; - }; - class GVAR(enableFractures) { - category = CSTRING(Category_Medical); - typeName = "BOOL"; - value = false; - }; class GVAR(enableAdvancedWounds) { category = CSTRING(Category_Medical); displayName = CSTRING(AdvancedMedicalSettings_enableAdvancedWounds_DisplayName); description = CSTRING(AdvancedMedicalSettings_enableAdvancedWounds_Description); typeName = "BOOL"; - value = false; + value = 1; }; class GVAR(enableVehicleCrashes) { category = CSTRING(Category_Medical); @@ -80,6 +57,8 @@ class ACE_Settings { typeName = "BOOL"; value = 1; }; + + // Use those for handleIncapacitation? class GVAR(playerDamageThreshold) { category = CSTRING(Category_Medical); displayName = CSTRING(MedicalSettings_playerDamageThreshold_DisplayName); @@ -94,11 +73,13 @@ class ACE_Settings { typeName = "SCALAR"; value = 1; }; + + class GVAR(enableUnconsciousnessAI) { category = CSTRING(Category_Medical); displayName = CSTRING(MedicalSettings_enableUnconsciousnessAI_DisplayName); description = CSTRING(MedicalSettings_enableUnconsciousnessAI_Description); - value = 1; + value = 2; typeName = "SCALAR"; values[] = {"Disabled", "50/50", "Enabled"}; }; @@ -148,7 +129,7 @@ class ACE_Settings { displayName = CSTRING(BasicMedicalSettings_medicSetting_basicEpi_DisplayName); description = CSTRING(BasicMedicalSettings_medicSetting_basicEpi_Description); typeName = "SCALAR"; - value = 1; + value = 0; values[] = {"Anyone", "Medics only", "Doctors only"}; }; class GVAR(medicSetting_PAK) { @@ -156,7 +137,7 @@ class ACE_Settings { displayName = CSTRING(AdvancedMedicalSettings_medicSetting_PAK_DisplayName); description = CSTRING(AdvancedMedicalSettings_medicSetting_PAK_Description); typeName = "SCALAR"; - value = 1; + value = 0; values[] = {"Anyone", "Medics only", "Doctors only"}; }; class GVAR(medicSetting_SurgicalKit) { @@ -164,7 +145,7 @@ class ACE_Settings { displayName = CSTRING(AdvancedMedicalSettings_medicSetting_SurgicalKit_DisplayName); description = CSTRING(AdvancedMedicalSettings_medicSetting_SurgicalKit_Description); typeName = "SCALAR"; - value = 1; + value = 0; values[] = {"Anyone", "Medics only", "Doctors only"}; }; class GVAR(consumeItem_PAK) { @@ -172,7 +153,7 @@ class ACE_Settings { displayName = CSTRING(AdvancedMedicalSettings_consumeItem_PAK_DisplayName); description = CSTRING(AdvancedMedicalSettings_consumeItem_PAK_Description); typeName = "SCALAR"; - value = 0; + value = 1; values[] = {"No", "Yes"}; }; class GVAR(consumeItem_SurgicalKit) { @@ -180,7 +161,7 @@ class ACE_Settings { displayName = CSTRING(AdvancedMedicalSettings_consumeItem_SurgicalKit_DisplayName); description = CSTRING(AdvancedMedicalSettings_consumeItem_SurgicalKit_Description); typeName = "SCALAR"; - value = 0; + value = 1; values[] = {"No", "Yes"}; }; class GVAR(useLocation_basicEpi) { @@ -196,7 +177,7 @@ class ACE_Settings { displayName = CSTRING(AdvancedMedicalSettings_useLocation_PAK_DisplayName); description = CSTRING(AdvancedMedicalSettings_useLocation_PAK_Description); typeName = "SCALAR"; - value = 3; + value = 0; values[] = {CSTRING(AdvancedMedicalSettings_anywhere), CSTRING(AdvancedMedicalSettings_vehicle), CSTRING(AdvancedMedicalSettings_facility), CSTRING(AdvancedMedicalSettings_vehicleAndFacility), ECSTRING(common,Disabled)}; }; class GVAR(useLocation_SurgicalKit) { @@ -204,38 +185,23 @@ class ACE_Settings { displayName = CSTRING(AdvancedMedicalSettings_useLocation_SurgicalKit_DisplayName); description = CSTRING(AdvancedMedicalSettings_useLocation_SurgicalKit_Description); typeName = "SCALAR"; - value = 2; + value = 0; values[] = {CSTRING(AdvancedMedicalSettings_anywhere), CSTRING(AdvancedMedicalSettings_vehicle), CSTRING(AdvancedMedicalSettings_facility), CSTRING(AdvancedMedicalSettings_vehicleAndFacility), ECSTRING(common,Disabled)}; }; - class GVAR(useCondition_PAK) { + class GVAR(fullHealLocation_PAK) { category = CSTRING(Category_Medical); - displayName = CSTRING(AdvancedMedicalSettings_useCondition_PAK_DisplayName); - description = CSTRING(AdvancedMedicalSettings_useCondition_PAK_Description); + displayName = CSTRING(AdvancedMedicalSettings_fullHealLocation_PAK_DisplayName); + description = CSTRING(AdvancedMedicalSettings_fullHealLocation_PAK_Description); typeName = "SCALAR"; - value = 0; - values[] = {"Anytime", "Stable"}; + value = 3; + values[] = {CSTRING(AdvancedMedicalSettings_anywhere), CSTRING(AdvancedMedicalSettings_vehicle), CSTRING(AdvancedMedicalSettings_facility), CSTRING(AdvancedMedicalSettings_vehicleAndFacility), ECSTRING(common,Disabled)}; }; - class GVAR(useCondition_SurgicalKit) { + class GVAR(fieldEffectiveness_PAK) { category = CSTRING(Category_Medical); - displayName = CSTRING(AdvancedMedicalSettings_useCondition_SurgicalKit_DisplayName); - description = CSTRING(AdvancedMedicalSettings_useCondition_SurgicalKit_Description); + displayName = CSTRING(MedicalSettings_fieldEffectiveness_PAK_DisplayName); + description = CSTRING(MedicalSettings_fieldEffectiveness_PAK_Description); typeName = "SCALAR"; - value = 0; - values[] = {"Anytime", "Stable"}; - }; - class GVAR(keepLocalSettingsSynced) { - category = CSTRING(Category_Medical); - displayName = CSTRING(MedicalSettings_keepLocalSettingsSynced_DisplayName); - description = CSTRING(MedicalSettings_keepLocalSettingsSynced_Description); - typeName = "BOOL"; - value = 1; - }; - class GVAR(healHitPointAfterAdvBandage) { - category = CSTRING(Category_Medical); - displayName = CSTRING(AdvancedMedicalSettings_healHitPointAfterAdvBandage_DisplayName); - description = CSTRING(AdvancedMedicalSettings_healHitPointAfterAdvBandage_Description); - typeName = "BOOL"; - value = 0; + value = 0.9; }; class GVAR(painIsOnlySuppressed) { category = CSTRING(Category_Medical); diff --git a/addons/medical/XEH_PREP.hpp b/addons/medical/XEH_PREP.hpp index 84aa378109..ddeae1d87f 100644 --- a/addons/medical/XEH_PREP.hpp +++ b/addons/medical/XEH_PREP.hpp @@ -1,35 +1,41 @@ + +PREP(addDamageToUnit); +PREP(addStateHandler); PREP(adjustPainLevel); +PREP(conditionCardiacArrestTimer); +PREP(conditionExecutionDeath); +PREP(enteredStateCardiacArrest); +PREP(enteredStateFatalInjury); PREP(getBloodLoss); PREP(getBloodPressure); PREP(getBloodVolumeChange); PREP(getCardiacOutput); PREP(getHeartRateChange); +PREP(handleIncapacitation); +PREP(handleKilled); +PREP(handleLocal); +PREP(handleMedications); +PREP(handleStateDefault); +PREP(handleStateInjured); +PREP(handleStateUnconscious); +PREP(handleUnitVitals); +PREP(hasStableVitals); +PREP(hasTourniquetAppliedTo); PREP(init); PREP(install); +PREP(isBeingCarried); +PREP(isBeingDragged); PREP(isInMedicalFacility); PREP(isInMedicalVehicle); PREP(isInStableCondition); PREP(isMedic); PREP(isMedicalVehicle); - -// PREP(hasMedicalEnabled); - -PREP(enteredStateCardiacArrest); -PREP(leavingStateCardiacArrest); - -PREP(enteredStateFatalInjury); - -PREP(conditionExecutionDeath); -PREP(transitionSecondChance); - -PREP(handleStateDefault); -PREP(handleStateInjured); -PREP(handleStateUnconscious); -PREP(handleUnitVitals); -PREP(handleMedications); - -PREP(addPain); -PREP(setUnconscious); +PREP(leftStateCardiacArrest); +PREP(moduleAssignMedicRoles); +PREP(moduleAssignMedicalVehicle); +PREP(serverRemoveBody); +PREP(setCardiacArrest); PREP(setDead); - -PREP(hasTourniquetAppliedTo); +PREP(setUnconscious); +PREP(showBloodEffect); +PREP(transitionSecondChance); \ No newline at end of file diff --git a/addons/medical/functions/fnc_addPain.sqf b/addons/medical/functions/fnc_addPain.sqf deleted file mode 100644 index df57ca0ae1..0000000000 --- a/addons/medical/functions/fnc_addPain.sqf +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Author: commy2 - * Adds or removes pain to/from unit. - * - * Arguments: - * 0: Unit - * 1: Pain to add. Negative to remove - * - * Return Value: - * Nothing - * - * Example: - * [player, 0.5] call ace_medical_fnc_addPain - * - * Public: No - */ -#include "script_component.hpp" - -params ["_unit", "_painToAdd"]; - -private _pain = _unit getVariable [QEGVAR(medical,pain), 0]; - -if (_pain > 0) then { - _pain = _pain + (_painToAdd min 1) * (1 - _pain); -} else { - _pain = (_pain + _painToAdd) max 0; -}; - -_unit setVariable [QEGVAR(medical,pain), _pain]; - -if (_painToAdd > 0 && {_pain >= PAIN_UNCONSCIOUS}) then { - [_unit, true, PAIN_KNOCK_OUT_DURATION] call FUNC(setUnconscious); -}; diff --git a/addons/medical/functions/fnc_adjustPainLevel.sqf b/addons/medical/functions/fnc_adjustPainLevel.sqf index d2a118223f..6235ba219f 100644 --- a/addons/medical/functions/fnc_adjustPainLevel.sqf +++ b/addons/medical/functions/fnc_adjustPainLevel.sqf @@ -1,13 +1,13 @@ /* * Author: PabstMirror - * Interface to allow external modules to safely adjust pain levels. + * Interface to allow external modules to affect the pain level * * Arguments: * 0: The patient - * 1: Added ammount of pain (can be negative) + * 1: Desired pain level (0 .. 1) * * Return Value: - * The new pain level + * nothing * * Example: * [guy, 0.5] call ace_medical_fnc_adjustPainLevel @@ -16,21 +16,14 @@ */ #include "script_component.hpp" -private ["_pain"]; +params ["_unit", "_desiredPainLevel"]; -params ["_unit", "_addedPain"]; -//Only run on local units: -if (!local _unit) exitWith {ERROR("unit is not local");}; -TRACE_3("ACE_DEBUG: adjustPainLevel Called",_unit, _pain, _addedPain); +if (!local _unit) exitWith { ERROR("unit is not local"); }; -//Ignore if medical system disabled: -if (GVAR(level) == 0) exitWith {}; +TRACE_2("ACE_DEBUG: adjustPainLevel Called",_unit,_desiredPainLevel); -private _pain = ((_unit getVariable [QGVAR(pain), 0]) + _addedPain) max 0; +private _pain = _unit getVariable [QGVAR(pain), 0]; + +_pain = 0 max (_pain max _desiredPainLevel) min 1; _unit setVariable [QGVAR(pain), _pain]; - -//Start up the vital watching (if not already running) -// [_unit] call FUNC(addVitalLoop); - -_pain; diff --git a/addons/medical/functions/fnc_displayPatientInformation.sqf b/addons/medical/functions/fnc_displayPatientInformation.sqf deleted file mode 100644 index 961485e8cd..0000000000 --- a/addons/medical/functions/fnc_displayPatientInformation.sqf +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Author: Glowbal - * Displays the patient information for given unit. - * - * Arguments: - * 0: The Unit - * 1: Show (default: true) - * 2: Selection (default: 0) - * - * ReturnValue: - * None - * - * Public: No - */ - -#include "script_component.hpp" -#define MAX_DISTANCE 10 - -// Exit for basic medical -if (GVAR(level) < 2) exitWith {}; - -params ["_target", ["_show", true], ["_selectionN", 0]]; - -GVAR(currentSelectedSelectionN) = [0, _selectionN] select (IS_SCALAR(_selectionN)); -GVAR(displayPatientInformationTarget) = [ObjNull, _target] select _show; - -if (_show) then { - ("ACE_MedicalRscDisplayInformation" call BIS_fnc_rscLayer) cutRsc [QGVAR(DisplayInformation),"PLAIN"]; - - [{ - private ["_target", "_display", "_alphaLevel", "_damaged", "_availableSelections", "_openWounds", "_selectionBloodLoss", "_red", "_green", "_blue", "_alphaLevel", "_allInjuryTexts", "_lbCtrl", "_genericMessages"]; - params ["_args", "_idPFH"]; - _args params ["_target", "_selectionN"]; - - if (GVAR(displayPatientInformationTarget) != _target || GVAR(currentSelectedSelectionN) != _selectionN) exitwith { - [_idPFH] call CBA_fnc_removePerFrameHandler; - }; - if (ACE_player distance _target > MAX_DISTANCE) exitwith { - ("ACE_MedicalRscDisplayInformation" call BIS_fnc_rscLayer) cutText ["","PLAIN"]; - [_idPFH] call CBA_fnc_removePerFrameHandler; - [QEGVAR(common,displayTextStructured), [[LSTRING(DistanceToFar), [_target] call EFUNC(common,getName)], 1.75, ACE_player], [ACE_player]] call CBA_fnc_targetEvent; - }; - - disableSerialization; - private _display = uiNamespace getVariable QGVAR(DisplayInformation); - if (isnil "_display") exitwith { - [_idPFH] call CBA_fnc_removePerFrameHandler; - }; - - private _allInjuryTexts = []; - private _genericMessages = []; - - private _partText = [LSTRING(Head), LSTRING(Torso), LSTRING(LeftArm) ,LSTRING(RightArm) ,LSTRING(LeftLeg), LSTRING(RightLeg)] select _selectionN; - _genericMessages pushback [localize _partText, [1, 1, 1, 1]]; - - if (_target getVariable[QGVAR(isBleeding), false]) then { - _genericMessages pushback [localize LSTRING(Status_Bleeding), [1, 0.1, 0.1, 1]]; - }; - if (_target getVariable[QGVAR(hasLostBlood), 0] > 1) then { - _genericMessages pushback [localize LSTRING(Status_Lost_Blood), [1, 0.1, 0.1, 1]]; - }; - - if (((_target getVariable [QGVAR(tourniquets), [0,0,0,0,0,0]]) select _selectionN) > 0) then { - _genericMessages pushback [localize LSTRING(Status_Tourniquet_Applied), [0.77, 0.51, 0.08, 1]]; - }; - if (_target getVariable[QGVAR(hasPain), false]) then { - _genericMessages pushback [localize LSTRING(Status_Pain), [1, 1, 1, 1]]; - }; - - private _totalIvVolume = 0; - private _bloodBags = _unit getVariable [QGVAR(ivBags), []]; - { - _x params ["_bagVolumeRemaining"]; - _totalIvVolume = _totalIvVolume + _bagVolumeRemaining; - } foreach _bloodBags; - - if (_totalIvVolume >= 1) then { - _genericMessages pushback [format[localize LSTRING(receivingIvVolume), floor _totalIvVolume], [1, 1, 1, 1]]; - }; - - private _damaged = [false, false, false, false, false, false]; - private _selectionBloodLoss = [0,0,0,0,0,0]; - - private _openWounds = _target getVariable [QGVAR(openWounds), []]; - { - _x params ["", "_x1", "_selectionX", "_amountOf", "_x4"]; - // Find how much this bodypart is bleeding - if (_amountOf > 0) then { - _damaged set [_selectionX, true]; - _selectionBloodLoss set [_selectionX, (_selectionBloodLoss select _selectionX) + (20 * (_x4 * _amountOf))]; - - if (_selectionN == _selectionX) then { - // Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this] - if (_amountOf >= 1) then { - // TODO localization - _allInjuryTexts pushback [format["%2x %1", (EGVAR(medical_damage,woundsData) select _x1) select 6, ceil _amountOf], [1,1,1,1]]; - } else { - // TODO localization - _allInjuryTexts pushback [format["Partial %1", (EGVAR(medical_damage,woundsData) select _x1) select 6], [1,1,1,1]]; - }; - }; - }; - } foreach _openWounds; - - private _bandagedwounds = _target getVariable [QGVAR(bandagedWounds), []]; - { - _x params ["", "", "_selectionX", "_amountOf", "_x4"]; - // Find how much this bodypart is bleeding - if !(_damaged select _selectionX) then { - _selectionBloodLoss set [_selectionX, (_selectionBloodLoss select _selectionX) + (20 * (_x4 * _amountOf))]; - }; - if (_selectionN == _selectionX) then { - // Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this] - if (_amountOf > 0) then { - if (_amountOf >= 1) then { - // TODO localization - _allInjuryTexts pushback [format["[B] %2x %1", (EGVAR(medical_damage,woundsData) select (_x select 1)) select 6, ceil _amountOf], [0.88,0.7,0.65,1]]; - } else { - // TODO localization - _allInjuryTexts pushback [format["[B] Partial %1", (EGVAR(medical_damage,woundsData) select (_x select 1)) select 6], [0.88,0.7,0.65,1]]; - }; - }; - }; - } foreach _bandagedwounds; - - // Handle the body image coloring - private _availableSelections = [50,51,52,53,54,55]; - { - private _total = _x; - private _red = 1; - private _green = 1; - private _blue = 1; - - if (_total > 0) then { - if (_damaged select _forEachIndex) then { - _green = (0.9 - _total) max 0; - _blue = _green; - } else { - _green = (0.9 - _total) max 0; - _red = _green; - //_blue = _green; - }; - }; - (_display displayCtrl (_availableSelections select _foreachIndex)) ctrlSetTextColor [_red, _green, _blue, 1.0]; - } foreach _selectionBloodLoss; - - private _lbCtrl = (_display displayCtrl 200); - lbClear _lbCtrl; - { - _x params ["_add", "_color"]; - _lbCtrl lbAdd _add; - _lbCtrl lbSetColor [_foreachIndex, _color]; - } foreach _genericMessages; - - private _amountOfGeneric = count _genericMessages; - { - _x params ["_add", "_color"]; - _lbCtrl lbAdd _add; - _lbCtrl lbSetColor [_foreachIndex + _amountOfGeneric, _color]; - } foreach _allInjuryTexts; - if (count _allInjuryTexts == 0) then { - _lbCtrl lbAdd (localize LSTRING(NoInjuriesBodypart)); - }; - - private _logCtrl = (_display displayCtrl 302); - lbClear _logCtrl; - - private _logs = _target getVariable [QGVAR(logFile_Activity), []]; - { - _x params ["_message", "_moment", "_type", "_arguments"]; - if (isLocalized _message) then { - _message = localize _message; - }; - - { - if (_x isEqualType "" && {isLocalized _x}) then { - _arguments set [_foreachIndex, localize _x]; - }; - } foreach _arguments; - _message = format([_message] + _arguments); - _logCtrl lbAdd format["%1 %2", _moment, _message]; - } foreach _logs; - - private _triageStatus = [_target] call EFUNC(medical_treatment,getTriageStatus); - (_display displayCtrl 303) ctrlSetText (_triageStatus select 0); - (_display displayCtrl 303) ctrlSetBackgroundColor (_triageStatus select 2); - - }, 0, [_target, GVAR(currentSelectedSelectionN)]] call CBA_fnc_addPerFrameHandler; - -} else { - ("ACE_MedicalRscDisplayInformation" call BIS_fnc_rscLayer) cutText ["","PLAIN"]; -}; diff --git a/addons/medical/functions/fnc_enteredStateCardiacArrest.sqf b/addons/medical/functions/fnc_enteredStateCardiacArrest.sqf index 73f94a8471..d5bb2b45e1 100644 --- a/addons/medical/functions/fnc_enteredStateCardiacArrest.sqf +++ b/addons/medical/functions/fnc_enteredStateCardiacArrest.sqf @@ -11,6 +11,9 @@ * Public: No */ #include "script_component.hpp" + params ["_unit"]; _unit setVariable [QGVAR(cardiacArrestStart), CBA_missionTime]; + +[_unit] call FUNC(setCardiacArrest); diff --git a/addons/medical/functions/fnc_enteredUnconsciousState.sqf b/addons/medical/functions/fnc_enteredUnconsciousState.sqf deleted file mode 100644 index eebbf15f10..0000000000 --- a/addons/medical/functions/fnc_enteredUnconsciousState.sqf +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Author: Glowbal - * Handle entering an unconscious state. - * - * Arguments: - * 0: The unit that will be put in an unconscious state - * 1: Set unconsciouns (default: true) - * 2: Minimum unconscious time (default: (round(random(10)+5))) - * 3: Force AI Unconscious (skip random death chance) (default: false) - * - * ReturnValue: - * nil - * - * Public: no - */ - -#include "script_component.hpp" - -#define DEFAULT_DELAY (round(random(10)+5)) - -params ["_unit", "_event", "_args"]; - -[_unit, true] call FUNC(setUnconscious); diff --git a/addons/medical/functions/fnc_getBloodLoss.sqf b/addons/medical/functions/fnc_getBloodLoss.sqf index ef2447edb8..d902a0b082 100644 --- a/addons/medical/functions/fnc_getBloodLoss.sqf +++ b/addons/medical/functions/fnc_getBloodLoss.sqf @@ -6,7 +6,7 @@ * 0: The Unit * * ReturnValue: - * Total blood loss of unit + * Total blood loss of unit (liter per second) * * Public: No */ @@ -14,18 +14,26 @@ params ["_unit"]; -private _totalBloodLoss = 0; +private _bloodLoss = 0; +private _limbBleeding = 0; +private _bodyBleeding = 0; private _tourniquets = _unit getVariable [QGVAR(tourniquets), [0,0,0,0,0,0]]; { - if (_tourniquets select (_x select 2) == 0) then { - // total bleeding ratio * percentage of injury left - _totalBloodLoss = _totalBloodLoss + ((_x select 4) * (_x select 3)); + _x params ["", "", "_bodyPart", "_percentage", "_bleeeding"]; + if (_bodyPart == 1) then { + _bodyBleeding = _bodyBleeding + (_bleeeding * _percentage); + } else { + if (_tourniquets select _bodyPart == 0) then { + _limbBleeding = _limbBleeding + (_bleeeding * _percentage); + }; }; } forEach (_unit getVariable [QGVAR(openWounds), []]); -{ - _totalBloodLoss = _totalBloodLoss + ((_x select 4) * (_x select 3)); -} forEach (_unit getVariable [QGVAR(internalWounds), []]); +private _cardiacOutput = [_unit] call FUNC(getCardiacOutput); -_totalBloodLoss * ((_unit getVariable [QGVAR(bleedingCoefficient), GVAR(bleedingCoefficient)]) max 0) * DEFAULT_BLOOD_VOLUME / 100; +// limb bleeding is scaled down based on the amount of body bleeding and limited by the current cardiac output +_limbBleeding = 0 max (_limbBleeding * (1 - (_bodyBleeding min 1))) min 1; +_bloodLoss = (_bodyBleeding + _limbBleeding) * _cardiacOutput; + +_bloodLoss * (_unit getVariable [QGVAR(bleedingCoefficient), GVAR(bleedingCoefficient)]) diff --git a/addons/medical/functions/fnc_getBloodPressure.sqf b/addons/medical/functions/fnc_getBloodPressure.sqf index 63908eecc7..7c6aef1e13 100644 --- a/addons/medical/functions/fnc_getBloodPressure.sqf +++ b/addons/medical/functions/fnc_getBloodPressure.sqf @@ -1,6 +1,6 @@ /* * Author: Glowbal - * Calculates the blood volume change and decreases the IVs given to the unit. + * Calculate the blood pressure of a unit. * * Arguments: * 0: The Unit @@ -15,17 +15,15 @@ #include "script_component.hpp" // Value is taken because with cardic output and resistance at default values, it will put blood pressure High at 120. -#define MODIFIER_BP_HIGH 0.229 +#define MODIFIER_BP_HIGH 13.7142792 // Value is taken because with cardic output and resistance at default values, it will put blood pressure Low at 80. -#define MODIFIER_BP_LOW 0.1524 +#define MODIFIER_BP_LOW 9.1428528 params ["_unit"]; private _cardiacOutput = [_unit] call FUNC(getCardiacOutput); private _resistance = _unit getVariable [QGVAR(peripheralResistance), 100]; +private _bloodPressure = _cardiacOutput * _resistance; -private _bloodPressureHigh = (_cardiacOutput * MODIFIER_BP_HIGH) * _resistance; -private _bloodPressureLow = (_cardiacOutput * MODIFIER_BP_LOW) * _resistance; - -[_bloodPressureLow max 0, _bloodPressureHigh max 0] +[round(_bloodPressure * MODIFIER_BP_LOW), round(_bloodPressure * MODIFIER_BP_HIGH)] diff --git a/addons/medical/functions/fnc_getBloodVolumeChange.sqf b/addons/medical/functions/fnc_getBloodVolumeChange.sqf index 1d48c9916d..ce3ff0d0d2 100644 --- a/addons/medical/functions/fnc_getBloodVolumeChange.sqf +++ b/addons/medical/functions/fnc_getBloodVolumeChange.sqf @@ -4,47 +4,49 @@ * * Arguments: * 0: The Unit - * 1: Global Sync Values (bloodbags) + * 1: Time since last update + * 2: Global Sync Values (bloodbags) * * ReturnValue: - * Blood volume change (in % total) + * Blood volume change (liters per second) * * Public: No */ #include "script_component.hpp" -params ["_unit", "_syncValues"]; +params ["_unit", "_deltaT", "_syncValues"]; private _bloodVolume = _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]; -private _bloodVolumeChange = -(_unit call FUNC(getBloodLoss)); +private _bloodVolumeChange = -_deltaT * (_unit call FUNC(getBloodLoss)); if (!isNil {_unit getVariable QGVAR(ivBags)}) then { - if (_bloodVolume < DEFAULT_BLOOD_VOLUME) then { - private _bloodBags = _unit getVariable [QGVAR(ivBags), []]; + private _bloodBags = _unit getVariable [QGVAR(ivBags), []]; - _bloodBags = _bloodBags apply { - _x params ["_bagVolumeRemaining"]; + _bloodBags = _bloodBags apply { + _x params ["_bagVolumeRemaining"]; - private _bagChange = IV_CHANGE_PER_SECOND min _bagVolumeRemaining; // absolute value of the change in miliLiters + if (GVAR(advancedIVBags)) then { + private _bagChange = _deltaT * (IV_CHANGE_PER_SECOND min _bagVolumeRemaining); // absolute value of the change in miliLiters _bagVolumeRemaining = _bagVolumeRemaining - _bagChange; _bloodVolumeChange = _bloodVolumeChange + (_bagChange / 1000); if (_bagVolumeRemaining < 0.01) then { [] } else { - [_bagVolumeRemaining]; + [_bagVolumeRemaining] }; - }; - - _bloodBags = _bloodBags - [[]]; // remove empty bags - - if (_bloodBags isEqualTo []) then { - _unit setVariable [QGVAR(ivBags), nil, true]; // no bags left - clear variable (always globaly sync this) } else { - _unit setVariable [QGVAR(ivBags), _bloodBags, _syncValues]; + _bloodVolumeChange = _bloodVolumeChange + (_bagVolumeRemaining / 1000); + [] }; + }; + + _bloodBags = _bloodBags - [[]]; // remove empty bags + + if (_bloodBags isEqualTo []) then { + _unit setVariable [QGVAR(ivBags), nil, true]; // no bags left - clear variable (always globaly sync this) } else { - _unit setVariable [QGVAR(ivBags), nil, true]; // blood volume = 100% - clear variable (always globaly sync this) + _unit setVariable [QGVAR(ivBags), _bloodBags, _syncValues]; }; }; diff --git a/addons/medical/functions/fnc_getCardiacOutput.sqf b/addons/medical/functions/fnc_getCardiacOutput.sqf index 9515d2cafe..cf2a35923d 100644 --- a/addons/medical/functions/fnc_getCardiacOutput.sqf +++ b/addons/medical/functions/fnc_getCardiacOutput.sqf @@ -6,7 +6,7 @@ * 0: The Unit * * ReturnValue: - * Current cardiac output + * Current cardiac output (liter per second) * * Public: No */ @@ -14,8 +14,7 @@ #include "script_component.hpp" /* - Cardiac output (Q or or CO ) is the volume of blood being pumped by the heart, in particular by a left or right ventricle in the CBA_missionTime interval of one minute. CO may be measured in many ways, for example dm3/min (1 dm3 equals 1 litre). - + Cardiac output (Q or or CO ) is the volume of blood being pumped by the heart, in particular by a left or right ventricle in the CBA_missionTime interval of one second. CO may be measured in many ways, for example dm3/min (1 dm3 equals 1 litre). Source: http://en.wikipedia.org/wiki/Cardiac_output */ @@ -24,4 +23,10 @@ params ["_unit"]; -((_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]) / MODIFIER_CARDIAC_OUTPUT) + ((_unit getVariable [QGVAR(heartRate), 80]) / 80 - 1); +if (_unit getVariable [QGVAR(inCardiacArrest), false]) exitWith { 0 }; + +private _bloodVolume = ((_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]) / DEFAULT_BLOOD_VOLUME) * 100; +private _heartRate = _unit getVariable [QGVAR(heartRate), 80]; +private _cardiacOutput = ((_bloodVolume / MODIFIER_CARDIAC_OUTPUT) + ((_heartRate / 80) - 1)) / 60; + +(0 max _cardiacOutput) diff --git a/addons/medical/functions/fnc_getHeartRateChange.sqf b/addons/medical/functions/fnc_getHeartRateChange.sqf index 7476a088c9..c2dab052f4 100644 --- a/addons/medical/functions/fnc_getHeartRateChange.sqf +++ b/addons/medical/functions/fnc_getHeartRateChange.sqf @@ -13,15 +13,11 @@ #include "script_component.hpp" -#define HEART_RATE_MODIFIER 0.02 - params ["_unit"]; private _hrIncrease = 0; -if (!(_unit getVariable [QGVAR(inCardiacArrest),false])) then { - private _heartRate = _unit getVariable [QGVAR(heartRate), 80]; - private _bloodLoss = [_unit] call FUNC(getBloodLoss); +if (!(_unit getVariable [QGVAR(inCardiacArrest),false])) then { private _adjustment = _unit getVariable [QGVAR(heartRateAdjustments), []]; { _x params ["_values", "_time", "_callBack"]; @@ -49,36 +45,37 @@ if (!(_unit getVariable [QGVAR(inCardiacArrest),false])) then { _adjustment = _adjustment - [ObjNull]; _unit setVariable [QGVAR(heartRateAdjustments), _adjustment]; - private _bloodVolume = _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]; - if (_bloodVolume > 75) then { - if (_bloodLoss > 0.0) then { - if (_bloodLoss < 0.5) then { - if (_heartRate < 126) then { - _hrIncrease = _hrIncrease + 0.05; - }; - } else { - if (_bloodLoss < 1) then { - if (_heartRate < 161) then { - _hrIncrease = _hrIncrease + 0.1; - }; - } else { - if (_heartRate < 220) then { - _hrIncrease = _hrIncrease + 0.15; - }; + if (!(_unit getVariable [QGVAR(inCardiacArrest), false])) then { + private _heartRate = (_unit getVariable [QGVAR(heartRate), 80]); + private _bloodVolume = _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]; + if (_bloodVolume > BLOOD_VOLUME_CLASS_4_HEMORRHAGE) then { + private _hrChange = 0; + ([_unit] call FUNC(getBloodPressure)) params ["_bloodPressureL", "_bloodPressureH"]; + private _meanBP = (2/3) * _bloodPressureH + (1/3) * _bloodPressureL; + private _pain = _unit getVariable [QGVAR(pain), 0]; + private _hasPain = _unit getVariable [QGVAR(hasPain), false]; + private _targetBP = 107; + private _targetHR = 80; + if (_bloodVolume < BLOOD_VOLUME_CLASS_3_HEMORRHAGE) then { + _targetBP = _targetBP * (_bloodVolume / DEFAULT_BLOOD_VOLUME); + }; + if (_hasPain && {_pain > 0.2}) then { + _targetHR = 130; + }; + if (_heartRate < _targetHR) then { + _hrChange = round(_targetHR - _heartRate) / 2; + }; + if ((_meanBP > _targetBP && {_heartRate > _targetHR}) || {_bloodVolume < BLOOD_VOLUME_CLASS_2_HEMORRHAGE && {_heartRate < 200}}) then { + _hrChange = 2 * round(_targetBP - _meanBP); + if (_hrChange < 0) then { + _hrChange = _hrChange / 20; }; }; + _hrIncrease = _hrIncrease + _hrChange; } else { - // Stabalize it - if (_heartRate < (60 + round(random(10)))) then { - _hrIncrease = _hrIncrease + HEART_RATE_MODIFIER; - } else { - if (_heartRate > (77 + round(random(10)))) then { - _hrIncrease = _hrIncrease - HEART_RATE_MODIFIER; - }; - }; + _hrIncrease = _hrIncrease - (random 5) * round(_heartRate / 10); }; - } else { - _hrIncrease = _hrIncrease - HEART_RATE_MODIFIER; }; }; + _hrIncrease diff --git a/addons/medical/functions/fnc_handleIncapacitation.sqf b/addons/medical/functions/fnc_handleIncapacitation.sqf new file mode 100644 index 0000000000..494afbd74e --- /dev/null +++ b/addons/medical/functions/fnc_handleIncapacitation.sqf @@ -0,0 +1,45 @@ +/* + * Author: Ruthberg + * Handle incapacitation due to damage and pain + * + * Arguments: + * 0: The Unit + * + * ReturnValue: + * nothing + * + * Public: No + */ +#include "script_component.hpp" + +params ["_unit"]; + +private _pain = _unit getVariable [QGVAR(pain), 0]; +private _headDamage = 0; +private _bodyDamage = 0; + +{ + _x params ["", "", "_bodyPart", "", "", "_damage"]; + switch (_bodyPart) do { + case 0: { + _headDamage = _headDamage + _damage; + }; + case 1: { + if (_damage > PENETRATION_THRESHOLD) then { + _bodyDamage = _bodyDamage + _damage; + }; + }; + }; +} forEach (_unit getVariable [QGVAR(openWounds), []]); + +// todo: use an ace settings for the thresholds +if (_headDamage > 0.50) then { + [QGVAR(CriticalInjury), _unit] call CBA_fnc_localEvent; +}; +if (_bodyDamage > 1.05) then { + [QGVAR(CriticalInjury), _unit] call CBA_fnc_localEvent; +}; + +if ((_pain >= PAIN_UNCONSCIOUS) && {random 1 < 0.1}) then { + [QGVAR(CriticalInjury), _unit] call CBA_fnc_localEvent; +}; diff --git a/addons/medical/functions/fnc_handleKilled.sqf b/addons/medical/functions/fnc_handleKilled.sqf index 6ca05a4228..a88f28a764 100644 --- a/addons/medical/functions/fnc_handleKilled.sqf +++ b/addons/medical/functions/fnc_handleKilled.sqf @@ -17,8 +17,6 @@ params ["_unit"]; if (!local _unit) exitWith {}; _unit setVariable [QGVAR(pain), 0]; -if (GVAR(level) >= 2) then { - _unit setVariable [QGVAR(heartRate), 0]; - _unit setVariable [QGVAR(bloodPressure), [0, 0]]; - _unit setVariable [QGVAR(airwayStatus), 0]; -}; +_unit setVariable [QGVAR(heartRate), 0]; +_unit setVariable [QGVAR(bloodPressure), [0, 0]]; +_unit setVariable [QGVAR(airwayStatus), 0]; \ No newline at end of file diff --git a/addons/medical/functions/fnc_handleLocal.sqf b/addons/medical/functions/fnc_handleLocal.sqf index fcb9227b64..7e1daf0423 100644 --- a/addons/medical/functions/fnc_handleLocal.sqf +++ b/addons/medical/functions/fnc_handleLocal.sqf @@ -17,17 +17,10 @@ params ["_unit", "_local"]; if (_local) then { - // If the unit had a loop tracking its vitals, restart it locally - if (_unit getVariable [QGVAR(addedToUnitLoop),false]) then { - [_unit, true] call FUNC(addVitalLoop); - }; - if ((_unit getVariable ["ACE_isUnconscious",false]) && {count (_unit getVariable [QGVAR(unconsciousArguments), []]) >= 6}) then { private _arguments = (_unit getVariable [QGVAR(unconsciousArguments), []]); _arguments set [2, CBA_missionTime]; - //[DFUNC(unconsciousPFH), 0.1, _arguments ] call CBA_fnc_addPerFrameHandler; - _unit setVariable [QGVAR(unconsciousArguments), nil, true]; }; }; diff --git a/addons/medical/functions/fnc_handleStateDefault.sqf b/addons/medical/functions/fnc_handleStateDefault.sqf index c94add2798..35ad6f62ce 100644 --- a/addons/medical/functions/fnc_handleStateDefault.sqf +++ b/addons/medical/functions/fnc_handleStateDefault.sqf @@ -1,24 +1,19 @@ #include "script_component.hpp" -params ["_unit", "_stateName", "_lastTime"]; - +params ["_unit", "_stateName"]; // If the unit died the loop is finished if (!alive _unit) exitWith {}; // If locality changed, broadcast the last medical state and finish the local loop if (!local _unit) exitWith { - if (GVAR(level) >= 2) then { - _unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true]; - _unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true]; - }; + _unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true]; + _unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true]; _unit setVariable [QGVAR(bloodVolume), _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME], true]; }; -systemChat format["handling state default for unit: %1", _this]; - -[_unit, CBA_missionTime - _lastTime] call FUNC(handleUnitVitals); +[_unit] call FUNC(handleUnitVitals); private _pain = _unit getVariable [QGVAR(pain), 0]; if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then { diff --git a/addons/medical/functions/fnc_handleStateInjured.sqf b/addons/medical/functions/fnc_handleStateInjured.sqf index 3e81bd29cd..35ad6f62ce 100644 --- a/addons/medical/functions/fnc_handleStateInjured.sqf +++ b/addons/medical/functions/fnc_handleStateInjured.sqf @@ -1,22 +1,19 @@ #include "script_component.hpp" -params ["_unit", "_stateName", "_lastTime"]; - +params ["_unit", "_stateName"]; // If the unit died the loop is finished if (!alive _unit) exitWith {}; // If locality changed, broadcast the last medical state and finish the local loop if (!local _unit) exitWith { - if (GVAR(level) >= 2) then { - _unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true]; - _unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true]; - }; + _unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true]; + _unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true]; _unit setVariable [QGVAR(bloodVolume), _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME], true]; }; -[_unit, CBA_missionTime - _lastTime] call FUNC(handleUnitVitals); +[_unit] call FUNC(handleUnitVitals); private _pain = _unit getVariable [QGVAR(pain), 0]; if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then { diff --git a/addons/medical/functions/fnc_handleStateUnconscious.sqf b/addons/medical/functions/fnc_handleStateUnconscious.sqf index 3e81bd29cd..35ad6f62ce 100644 --- a/addons/medical/functions/fnc_handleStateUnconscious.sqf +++ b/addons/medical/functions/fnc_handleStateUnconscious.sqf @@ -1,22 +1,19 @@ #include "script_component.hpp" -params ["_unit", "_stateName", "_lastTime"]; - +params ["_unit", "_stateName"]; // If the unit died the loop is finished if (!alive _unit) exitWith {}; // If locality changed, broadcast the last medical state and finish the local loop if (!local _unit) exitWith { - if (GVAR(level) >= 2) then { - _unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true]; - _unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true]; - }; + _unit setVariable [QGVAR(heartRate), _unit getVariable [QGVAR(heartRate), 80], true]; + _unit setVariable [QGVAR(bloodPressure), _unit getVariable [QGVAR(bloodPressure), [80, 120]], true]; _unit setVariable [QGVAR(bloodVolume), _unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME], true]; }; -[_unit, CBA_missionTime - _lastTime] call FUNC(handleUnitVitals); +[_unit] call FUNC(handleUnitVitals); private _pain = _unit getVariable [QGVAR(pain), 0]; if (_pain > (_unit getVariable [QGVAR(painSuppress), 0])) then { diff --git a/addons/medical/functions/fnc_handleUnitVitals.sqf b/addons/medical/functions/fnc_handleUnitVitals.sqf index c5fad60801..7bcce0d74e 100644 --- a/addons/medical/functions/fnc_handleUnitVitals.sqf +++ b/addons/medical/functions/fnc_handleUnitVitals.sqf @@ -12,27 +12,33 @@ */ #include "script_component.hpp" -params ["_unit", "_interval"]; -TRACE_3("ACE_DEBUG",_unit,_interval,_unit); +params ["_unit"]; -if (_interval == 0) exitWith {}; +private _lastTimeUpdated = _unit getVariable [QGVAR(lastTimeUpdated), CBA_missionTime]; +private _deltaT = CBA_missionTime - _lastTimeUpdated; +_unit setVariable [QGVAR(lastTimeUpdated), CBA_missionTime]; + +TRACE_2("ACE_DEBUG",_unit,_deltaT); + +if (_deltaT == 0) exitWith {}; private _lastTimeValuesSynced = _unit getVariable [QGVAR(lastMomentValuesSynced), 0]; -private _syncValues = (CBA_missionTime - _lastTimeValuesSynced >= 10 + floor(random(10))) && GVAR(keepLocalSettingsSynced); +private _syncValues = (CBA_missionTime - _lastTimeValuesSynced) >= (10 + floor(random(10))); if (_syncValues) then { _unit setVariable [QGVAR(lastMomentValuesSynced), CBA_missionTime]; }; -private _bloodVolume = (_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]) + ([_unit, _syncValues] call FUNC(getBloodVolumeChange)); -_bloodVolume = (_bloodVolume max 0) min DEFAULT_BLOOD_VOLUME; +private _bloodVolume = (_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME]) + ([_unit, _deltaT, _syncValues] call FUNC(getBloodVolumeChange)); +_bloodVolume = 0 max _bloodVolume min DEFAULT_BLOOD_VOLUME; +// @todo: replace this and the rest of the setVariable with EFUNC(common,setApproximateVariablePublic) _unit setVariable [QGVAR(bloodVolume), _bloodVolume, _syncValues]; TRACE_3("ACE_DEBUG",_bloodVolume,_syncValues,_unit); // Set variables for synchronizing information across the net -if (_bloodVolume < BLOOD_VOLUME_HAS_LOST_SOME) then { - if (_bloodVolume < BLOOD_VOLUME_HAS_LOST_MUCH) then { +if (_bloodVolume < BLOOD_VOLUME_CLASS_1_HEMORRHAGE) then { + if (_bloodVolume < BLOOD_VOLUME_CLASS_3_HEMORRHAGE) then { if (_unit getVariable [QGVAR(hasLostBlood), 0] != 2) then { _unit setVariable [QGVAR(hasLostBlood), 2, true]; }; @@ -52,7 +58,7 @@ TRACE_3("ACE_DEBUG",_bloodLoss,_unit getVariable QGVAR(isBleeding),_unit); if (_bloodLoss > 0) then { _unit setVariable [QGVAR(bloodloss), _bloodLoss, _syncValues]; - [QGVAR(TakenInjury), _unit] call CBA_fnc_localEvent; + [QGVAR(Injury), _unit] call CBA_fnc_localEvent; if !(_unit getVariable [QGVAR(isBleeding), false]) then { _unit setVariable [QGVAR(isBleeding), true, true]; @@ -75,75 +81,55 @@ if (_painStatus > (_unit getVariable [QGVAR(painSuppress), 0])) then { }; }; -if (_bloodVolume < BLOOD_VOLUME_DEAD) exitWith { - [_unit, "bloodloss"] call FUNC(setDead); +TRACE_6("ACE_DEBUG_ADVANCED_VITALS",_painStatus,_bloodVolume,_unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit); + +// Handle pain due tourniquets, that have been applied more than 120 s ago +private _oldTourniquets = (_unit getVariable [QGVAR(tourniquets), []]) select {_x > 0 && {CBA_missionTime - _x > 120}}; +// Increase pain at a rate of 0.001 units/s per old tourniquet +_painStatus = _painStatus + (count _oldTourniquets) * 0.001 * _deltaT; + +private _heartRate = (_unit getVariable [QGVAR(heartRate), 80]) + _deltaT * ([_unit] call FUNC(getHeartRateChange)); +_unit setVariable [QGVAR(heartRate), 0 max _heartRate, _syncValues]; + +private _bloodPressure = [_unit] call FUNC(getBloodPressure); +_unit setVariable [QGVAR(bloodPressure), _bloodPressure, _syncValues]; + +private _cardiacOutput = [_unit] call FUNC(getCardiacOutput); +if (_bloodLoss > BLOOD_LOSS_KNOCK_OUT_THRESHOLD * _cardiacOutput) then { + [QGVAR(CriticalVitals), _unit] call CBA_fnc_localEvent; }; -if ([_unit] call EFUNC(common,isAwake)) then { - if (_bloodVolume < BLOOD_VOLUME_UNCONSCIOUS && {random 1 < BLOOD_LOSS_KNOCK_OUT_CHANCE}) exitWith { - [_unit, true, BLOOD_LOSS_KNOCK_OUT_DURATION] call FUNC(setUnconscious); - }; +#ifdef DEBUG_MODE_FULL +if (!isPlayer _unit) then { + private _cardiacArrest = _unit getVariable [QGVAR(inCardiacArrest), false]; + 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 / _cardiacOutput) * 100) / 100, round(_heartRate), _bloodPressure, round(_painStatus * 100) / 100]; +}; +#endif + +_unit setVariable [QGVAR(pain), 0 max (_painStatus - _deltaT * PAIN_REDUCTION_SPEED), _syncValues]; + +TRACE_8("ACE_DEBUG_ADVANCED_VITALS",_painStatus,PAIN_REDUCTION_SPEED,_heartRate,_bloodVolume,_bloodPressure,_deltaT,_syncValues,_unit); + +_bloodPressure params ["_bloodPressureL", "_bloodPressureH"]; +if (_bloodPressureL < 40) then { + [QGVAR(CriticalVitals), _unit] call CBA_fnc_localEvent; +}; +if ((_heartRate < 20) || {_heartRate > 220} || {_bloodPressureH < 50}) then { + [QGVAR(FatalVitals), _unit] call CBA_fnc_localEvent; }; -/* -if (GVAR(level) == 1) then { - TRACE_5("ACE_DEBUG_BASIC_VITALS",_painStatus,_unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit); - // reduce pain - if (_painStatus > 0) then { - _unit setVariable [QGVAR(pain), (_painStatus - 0.001 * _interval) max 0, _syncValues]; - }; - - //// reduce painkillers - //if (_unit getVariable [QGVAR(morphine), 0] > 0) then { - // _unit setVariable [QGVAR(morphine), ((_unit getVariable [QGVAR(morphine), 0]) - 0.0015 * _interval) max 0, _syncValues]; - //}; -}; -*/ - -// handle advanced medical, with vitals -/* -if (GVAR(level) >= 2) then { - TRACE_6("ACE_DEBUG_ADVANCED_VITALS",_painStatus,_bloodVolume, _unit getVariable QGVAR(hasPain),_unit getVariable QGVAR(morphine),_syncValues,_unit); - - // Handle pain due tourniquets, that have been applied more than 120 s ago - private _oldTourniquets = (_unit getVariable [QGVAR(tourniquets), []]) select {_x > 0 && {CBA_missionTime - _x > 120}}; - // Increase pain at a rate of 0.001 units/s per old tourniquet - _painStatus = _painStatus + (count _oldTourniquets) * 0.001 * _interval; - - // Set the vitals - private _heartRate = (_unit getVariable [QGVAR(heartRate), 80]) + (([_unit] call FUNC(getHeartRateChange)) * _interval); - _unit setVariable [QGVAR(heartRate), _heartRate max 0, _syncValues]; - - private _bloodPressure = [_unit] call FUNC(getBloodPressure); - _unit setVariable [QGVAR(bloodPressure), _bloodPressure, _syncValues]; - - _painReduce = [0.001, 0.002] select (_painStatus > 5); - - // @todo: replace this and the rest of the setVariable with EFUNC(common,setApproximateVariablePublic) - _unit setVariable [QGVAR(pain), (_painStatus - _painReduce * _interval) max 0, _syncValues]; - - TRACE_8("ACE_DEBUG_ADVANCED_VITALS",_painStatus,_painReduce,_heartRate,_bloodVolume,_bloodPressure,_interval,_syncValues,_unit); - - // Check vitals for medical status - // TODO check for in revive state instead of variable - _bloodPressure params ["_bloodPressureL", "_bloodPressureH"]; - - if (!(_unit getVariable [QGVAR(inCardiacArrest),false])) then { - if (_heartRate < 10 || _bloodPressureH < 30 || _bloodVolume < BLOOD_VOLUME_CARDIAC_ARREST) then { - [_unit, true, 10+ random(20)] call FUNC(setUnconscious); // safety check to ensure unconsciousness for units if they are not dead already. - }; - - if ((_bloodPressureH > 260) - || {_bloodPressureL < 40 && ({_heartRate > 190})} - || {(_bloodPressureH > 145 && {_heartRate > 150})}) then { - - if (random(1) > 0.7) then { - [_unit] call FUNC(setCardiacArrest); +// Handle spontaneous wakeup from unconsciousness +if (_unit getVariable [QGVAR(isUnconscious), false]) then { + if (_unit call FUNC(hasStableVitals)) then { + private _lastWakeUpCheck = _unit getVariable [QGVAR(lastWakeUpCheck), CBA_missionTime]; + if (CBA_missionTime - _lastWakeUpCheck > SPONTANEOUS_WAKE_UP_INTERVAL) then { + _unit setVariable [QGVAR(lastWakeUpCheck), CBA_missionTime]; + if ((random 1) < SPONTANEOUS_WAKE_UP_CHANCE) then { + [QGVAR(WakeUp), _unit] call CBA_fnc_localEvent; }; }; - if (_heartRate > 200 || (_heartRate < 20)) then { - [_unit] call FUNC(setCardiacArrest); - }; + } else { + // Unstable vitals, procrastinate the next wakeup check + _unit setVariable [QGVAR(lastWakeUpCheck), CBA_missionTime]; }; }; -*/ diff --git a/addons/medical/functions/fnc_hasStableVitals.sqf b/addons/medical/functions/fnc_hasStableVitals.sqf new file mode 100644 index 0000000000..4afe07faad --- /dev/null +++ b/addons/medical/functions/fnc_hasStableVitals.sqf @@ -0,0 +1,32 @@ +/* +* Author: Ruthberg +* Check if a unit has stable vitals (required to become conscious) +* +* Arguments: +* 0: The patient +* +* Return Value: +* Has stable vitals +* +* Public: No +*/ + +#include "script_component.hpp" + +params ["_unit"]; + +if (_unit getVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME] < BLOOD_VOLUME_CLASS_2_HEMORRHAGE) exitWith { false }; +if (_unit getVariable [QGVAR(inCardiacArrest), false]) exitWith { false }; + +private _cardiacOutput = [_unit] call FUNC(getCardiacOutput); +private _bloodLoss = _unit call FUNC(getBloodLoss); +if (_bloodLoss > (BLOOD_LOSS_KNOCK_OUT_THRESHOLD * _cardiacOutput) / 2) exitWith { false }; + +private _bloodPressure = [_unit] call FUNC(getBloodPressure); +_bloodPressure params ["_bloodPressureL", "_bloodPressureH"]; +if (_bloodPressureL < 50 || {_bloodPressureH < 60}) exitWith { false }; + +private _heartRate = (_unit getVariable [QGVAR(heartRate), 80]); +if (_heartRate < 40) exitWith { false }; + +true diff --git a/addons/medical/functions/fnc_init.sqf b/addons/medical/functions/fnc_init.sqf index 192ccc5fcb..d5884f329a 100644 --- a/addons/medical/functions/fnc_init.sqf +++ b/addons/medical/functions/fnc_init.sqf @@ -20,7 +20,8 @@ if (damage _unit > 0) then { _unit setVariable [QGVAR(pain), 0, true]; _unit setVariable [QGVAR(bloodVolume), DEFAULT_BLOOD_VOLUME, true]; -_unit setVariable ["ACE_isUnconscious", false, true]; // TODO this is done based on state +_unit setVariable [QGVAR(isUnconscious), false, true]; +_unit setVariable [QGVAR(partialHealCounter), 0, true]; // tourniquets _unit setVariable [QGVAR(tourniquets), [0,0,0,0,0,0], true]; @@ -29,7 +30,7 @@ _unit setVariable [QGVAR(occludedMedications), nil, true]; //Delayed Medications // wounds and injuries _unit setVariable [QGVAR(openWounds), [], true]; _unit setVariable [QGVAR(bandagedWounds), [], true]; -_unit setVariable [QGVAR(internalWounds), [], true]; +_unit setVariable [QGVAR(stitchedWounds), [], true]; // vitals _unit setVariable [QGVAR(heartRate), 80]; @@ -37,9 +38,6 @@ _unit setVariable [QGVAR(heartRateAdjustments), []]; _unit setVariable [QGVAR(bloodPressure), [80, 120]]; _unit setVariable [QGVAR(peripheralResistance), 100]; -// fractures -_unit setVariable [QGVAR(fractures), [], true]; - // triage card and logs // TODO move to treatment //_unit setVariable [QGVAR(triageLevel), 0, true]; @@ -51,14 +49,8 @@ _unit setVariable [QGVAR(ivBags), nil, true]; // damage storage _unit setVariable [QGVAR(bodyPartStatus), [0,0,0,0,0,0], true]; -// airway -_unit setVariable [QGVAR(airwayStatus), 100]; -_unit setVariable [QGVAR(airwayOccluded), false]; -_unit setVariable [QGVAR(airwayCollapsed), false]; - // generic medical admin -_unit setVariable [QGVAR(addedToUnitLoop), false, true]; // TODO this is replaced by unit state -_unit setVariable [QGVAR(inCardiacArrest), false, true]; // TODO this is no longer present +_unit setVariable [QGVAR(inCardiacArrest), false, true]; _unit setVariable [QGVAR(hasLostBlood), 0, true]; _unit setVariable [QGVAR(isBleeding), false, true]; _unit setVariable [QGVAR(hasPain), false, true]; diff --git a/addons/medical/functions/fnc_isInStableCondition.sqf b/addons/medical/functions/fnc_isInStableCondition.sqf index a11e40dd31..c970b20a94 100644 --- a/addons/medical/functions/fnc_isInStableCondition.sqf +++ b/addons/medical/functions/fnc_isInStableCondition.sqf @@ -15,10 +15,9 @@ params ["_unit"]; -private _totalBloodLoss = 0; -{ - // total bleeding ratio * percentage of injury left - _totalBloodLoss = _totalBloodLoss + ((_x select 4) * (_x select 3)); -} forEach (_unit getVariable [QGVAR(openWounds), []]); +if (!alive _unit) exitWith { false }; +if (_unit call FUNC(getBloodLoss) > 0) exitWith { false }; +if (!(_unit call FUNC(hasStableVitals))) exitWith { false }; +if (_unit getVariable [QGVAR(isUnconscious), false]) exitWith { false }; -(_totalBloodLoss == 0); +true diff --git a/addons/medical/functions/fnc_leavingStateCardiacArrest.sqf b/addons/medical/functions/fnc_leftStateCardiacArrest.sqf similarity index 100% rename from addons/medical/functions/fnc_leavingStateCardiacArrest.sqf rename to addons/medical/functions/fnc_leftStateCardiacArrest.sqf diff --git a/addons/medical/functions/fnc_setCardiacArrest.sqf b/addons/medical/functions/fnc_setCardiacArrest.sqf index 69bda192dd..6f11a0c388 100644 --- a/addons/medical/functions/fnc_setCardiacArrest.sqf +++ b/addons/medical/functions/fnc_setCardiacArrest.sqf @@ -16,13 +16,14 @@ params ["_unit"]; -if (_unit getVariable [QGVAR(inCardiacArrest),false]) exitWith {}; -_unit setVariable [QGVAR(inCardiacArrest), true,true]; -_unit setVariable [QGVAR(heartRate), 0]; +if (_unit getVariable [QGVAR(inCardiacArrest), false]) exitWith {}; +_unit setVariable [QGVAR(inCardiacArrest), true, true]; +_unit setVariable [QGVAR(heartRate), 0, true]; ["ace_cardiacArrestEntered", [_unit]] call CBA_fnc_localEvent; [_unit, true] call FUNC(setUnconscious); +[QEGVAR(medical,InjuryCritical), _unit] call CBA_fnc_localEvent; private _timeInCardiacArrest = 120 + round(random(600)); [{ @@ -30,13 +31,13 @@ private _timeInCardiacArrest = 120 + round(random(600)); _args params ["_unit", "_startTime", "_timeInCardiacArrest"]; private _heartRate = _unit getVariable [QGVAR(heartRate), 80]; - if (_heartRate > 0 || !alive _unit) exitWith { + if (_heartRate > 20 || !alive _unit) exitWith { [_idPFH] call CBA_fnc_removePerFrameHandler; - _unit setVariable [QGVAR(inCardiacArrest), nil,true]; + _unit setVariable [QGVAR(inCardiacArrest), nil, true]; }; if (CBA_missionTime - _startTime >= _timeInCardiacArrest) exitWith { [_idPFH] call CBA_fnc_removePerFrameHandler; - _unit setVariable [QGVAR(inCardiacArrest), nil,true]; + _unit setVariable [QGVAR(inCardiacArrest), nil, true]; [_unit] call FUNC(setDead); }; }, 1, [_unit, CBA_missionTime, _timeInCardiacArrest] ] call CBA_fnc_addPerFrameHandler; diff --git a/addons/medical/functions/fnc_setUnconscious.sqf b/addons/medical/functions/fnc_setUnconscious.sqf index bfaf75ce4a..cf32c1a085 100644 --- a/addons/medical/functions/fnc_setUnconscious.sqf +++ b/addons/medical/functions/fnc_setUnconscious.sqf @@ -5,8 +5,6 @@ * Arguments: * 0: The unit that will be put in an unconscious state * 1: Set unconsciouns (default: true) - * 2: Minimum unconscious time (default: (round(random(10)+5))) - * 3: Force AI Unconscious (skip random death chance) (default: false) * * ReturnValue: * Success? @@ -23,20 +21,15 @@ if !(EGVAR(common,settingsInitFinished)) exitWith { EGVAR(common,runAtSettingsInitialized) pushBack [FUNC(setUnconscious), _this]; }; -params ["_unit", ["_knockOut", true], ["_minUnconsciousTime", DEFAULT_KNOCK_OUT_DELAY], ["_force", false]]; +params ["_unit", ["_knockOut", true]]; if (isNull _unit || {!(_unit isKindOf "CAManBase")}) exitWith {false}; if (!local _unit) exitWith { - [QGVAR(setUnconscious), [_unit, _knockOut, _minUnconsciousTime, _force], _unit] call CBA_fnc_targetEvent; + [QGVAR(setUnconscious), [_unit, _knockOut], _unit] call CBA_fnc_targetEvent; true }; -// use maximum for wake up time -if (_knockOut) then { - _unit setVariable [QGVAR(wakeUpTime), (CBA_missionTime + _minUnconsciousTime) max (_unit getVariable [QGVAR(wakeUpTime), 0])]; -}; - if (_knockOut isEqualTo (_unit getVariable [QGVAR(isUnconscious), false])) exitWith {false}; // --- wake up @@ -55,6 +48,7 @@ if !(_knockOut) exitWith { // --- knock out _unit setVariable [QGVAR(isUnconscious), true, true]; +_unit setVariable [QGVAR(lastWakeUpCheck), CBA_missiontime]; if (_unit == ACE_player) then { if (visibleMap) then {openMap false}; @@ -64,39 +58,8 @@ if (_unit == ACE_player) then { }; }; -// if we have unconsciousness for AI disabled, we will kill the unit instead -/* -private _isDead = false; - -if (!([_unit, GVAR(remoteControlledAI)] call EFUNC(common,isPlayer)) && !_force) then { - _enableUncon = _unit getVariable [QGVAR(enableUnconsciousnessAI), GVAR(enableUnconsciousnessAI)]; - - if (_enableUncon == 0 or {_enableUncon == 1 and (random 1) < 0.5}) then { - [_unit, true] call FUNC(setDead); - _isDead = true; - }; -}; - -if (_isDead) exitWith {}; -*/ - [_unit, true] call EFUNC(medical_engine,setUnconsciousAnim); [QGVAR(Unconscious), _unit] call CBA_fnc_localEvent; ["ace_unconscious", [_unit, true]] call CBA_fnc_globalEvent; -// auto wake up -[{ - params ["_unit"]; - - private _time = _unit getVariable [QGVAR(wakeUpTime), 0]; - - !(_unit getVariable [QGVAR(isUnconscious), false]) || {CBA_missionTime > _time} -}, { - params ["_unit"]; - - if (_unit getVariable [QGVAR(isUnconscious), false]) then { - [_unit, false] call FUNC(setUnconscious); - }; -}, _unit] call CBA_fnc_waitUntilAndExecute; - true diff --git a/addons/medical/functions/fnc_unconsciousPFH.sqf b/addons/medical/functions/fnc_unconsciousPFH.sqf deleted file mode 100644 index 31bd92d1ef..0000000000 --- a/addons/medical/functions/fnc_unconsciousPFH.sqf +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Author: Glowbal - * PFH logic for unconscious state - * - * Arguments: - * 0: PFEH - Args - * 0: The unit that will be put in an unconscious state - * 1: unitPos (stance) - * 2: Starting Time - * 3: Minimum Waiting Time - * 4: Has Moved Out - * 5: Parachute Check - * 1: PFEH ID - * - * ReturnValue: - * None - * - * Public: yes - */ -#include "script_component.hpp" - -private ["_unit", "_minWaitingTime", "_slotInfo", "_hasMovedOut", "_parachuteCheck", "_args", "_originalPos", "_startingTime", "_awakeInVehicleAnimation", "_oldVehicleAnimation", "_vehicle"]; -params ["_args", "_idPFH"]; -_args params ["_unit", "_originalPos", "_startingTime", "_minWaitingTime", "_hasMovedOut", "_parachuteCheck"]; - -TRACE_6("ACE_DEBUG_Unconscious_PFH",_unit, _originalPos, _startingTime, _minWaitingTime, _hasMovedOut, _parachuteCheck); - -if (!alive _unit) exitWith { - if ("ACE_FakePrimaryWeapon" in (weapons _unit)) then { - TRACE_1("Removing fake weapon [on death]",_unit); - _unit removeWeapon "ACE_FakePrimaryWeapon"; - }; - if (GVAR(moveUnitsFromGroupOnUnconscious)) then { - [_unit, false, "ACE_isUnconscious", side group _unit] call EFUNC(common,switchToGroupSide); - }; - [_unit, "setCaptive", "ace_unconscious", false] call EFUNC(common,statusEffect_set); - [_unit, false] call EFUNC(common,disableAI); - //_unit setUnitPos _originalPos; - //_unit setUnconscious false; - - [_unit, "isUnconscious"] call EFUNC(common,unmuteUnit); - ["ace_unconscious", [_unit, false]] call CBA_fnc_globalEvent; - - TRACE_3("ACE_DEBUG_Unconscious_Exit",_unit, (!alive _unit) , "ace_unconscious"); - - [_idPFH] call CBA_fnc_removePerFrameHandler; -}; - -// In case the unit is no longer in an unconscious state, we are going to check if we can already reset the animation -if !(_unit getVariable ["ACE_isUnconscious",false]) exitWith { - TRACE_7("ACE_DEBUG_Unconscious_PFH",_unit, _args, [_unit] call EFUNC(medical_treatment,isBeingCarried), [_unit] call EFUNC(medical_treatment,isBeingDragged), _idPFH, _unit getVariable QGVAR(unconsciousArguments),animationState _unit); - // TODO, handle this with carry instead, so we can remove the PFH here. - // Wait until the unit isn't being carried anymore, so we won't end up with wierd animations - if !(([_unit] call EFUNC(medical_treatment,isBeingCarried)) || ([_unit] call EFUNC(medical_treatment,isBeingDragged))) then { - if ("ACE_FakePrimaryWeapon" in (weapons _unit)) then { - TRACE_1("Removing fake weapon [on wakeup]",_unit); - _unit removeWeapon "ACE_FakePrimaryWeapon"; - }; - - if (vehicle _unit == _unit) then { - if (animationState _unit == "AinjPpneMstpSnonWrflDnon") then { - [_unit,"AinjPpneMstpSnonWrflDnon_rolltofront", 2] call EFUNC(common,doAnimation); - [_unit,"amovppnemstpsnonwnondnon", 1] call EFUNC(common,doAnimation); - } else { - [_unit,"amovppnemstpsnonwnondnon", 2] call EFUNC(common,doAnimation); - }; - } else { - _vehicle = vehicle _unit; - _oldVehicleAnimation = _unit getVariable [QGVAR(vehicleAwakeAnim), []]; - _awakeInVehicleAnimation = ""; - if (((count _oldVehicleAnimation) > 0) && {(_oldVehicleAnimation select 0) == _vehicle}) then { - _awakeInVehicleAnimation = _oldVehicleAnimation select 1; - }; - //Make sure we have a valid, non-terminal animation: - if ((_awakeInVehicleAnimation != "") && {(getNumber (configFile >> "CfgMovesMaleSdr" >> "States" >> _awakeInVehicleAnimation >> "terminal")) == 0}) then { - [_unit, _awakeInVehicleAnimation, 2] call EFUNC(common,doAnimation); - } else { - //Don't have a valid animation saved, reset the unit animation with a moveInXXX - TRACE_1("No Valid Animation, doing seat reset", _awakeInVehicleAnimation); - _slotInfo = []; - {if ((_x select 0) == _unit) exitWith {_slotInfo = _x;};} forEach (fullCrew _vehicle); - if (_slotInfo isEqualTo []) exitWith {ERROR("No _slotInfo?");}; - //Move the unit out: - _unit setPosASL ((getPosASL _unit) vectorAdd [0,0,100]); - //Move the unit back into old seat: - if ((_slotInfo select 1) == "driver") then { - _unit moveInDriver _vehicle; - } else { - if ((_slotInfo select 1) == "cargo") then { - _unit moveInCargo [_vehicle, (_slotInfo select 2)]; - } else { - _unit moveInTurret [_vehicle, (_slotInfo select 3)]; - }; - }; - }; - }; - _unit setVariable [QGVAR(vehicleAwakeAnim), nil]; - - ["ace_unconscious", [_unit, false]] call CBA_fnc_globalEvent; - // EXIT PFH - [_idPFH] call CBA_fnc_removePerFrameHandler; - }; - if (!_hasMovedOut) then { - // Reset the unit back to the previous captive state. - [_unit, "setCaptive", "ace_unconscious", false] call EFUNC(common,statusEffect_set); - - // Swhich the unit back to its original group - //Unconscious units shouldn't be put in another group #527: - if (GVAR(moveUnitsFromGroupOnUnconscious)) then { - [_unit, false, "ACE_isUnconscious", side group _unit] call EFUNC(common,switchToGroupSide); - }; - [_unit, false] call EFUNC(common,disableAI); - _unit setUnitPos _originalPos; // This is not position but stance (DOWN, MIDDLE, UP) - - _unit setUnconscious false; - - [_unit, "isUnconscious"] call EFUNC(common,unmuteUnit); - - // ensure this statement runs only once - _args set [4, true]; - }; -}; - -if (_parachuteCheck) then { - if !(vehicle _unit isKindOf "ParachuteBase") then { - [_unit, [_unit] call EFUNC(common,getDeathAnim), 1, true] call EFUNC(common,doAnimation); - _args set [5, false]; - }; -}; - -if (!local _unit) exitWith { - TRACE_6("ACE_DEBUG_Unconscious_PFH",_unit, _args, _startingTime, _minWaitingTime, _idPFH, _unit getVariable QGVAR(unconsciousArguments)); - _args set [3, _minWaitingTime - (CBA_missionTime - _startingTime)]; - _unit setVariable [QGVAR(unconsciousArguments), _args, true]; - [_idPFH] call CBA_fnc_removePerFrameHandler; -}; - -// Ensure we are waiting at least a minimum period before checking if we can wake up the unit again, allows for temp knock outs -if ((CBA_missionTime - _startingTime) >= _minWaitingTime) exitWith { - TRACE_2("ACE_DEBUG_Unconscious_Temp knock outs",_unit, [_unit] call FUNC(getUnconsciousCondition)); - if (!([_unit] call FUNC(getUnconsciousCondition))) then { - //_unit setVariable ["ACE_isUnconscious", false, true]; - [QGVAR(MinUnconsciousTimer), _unit] call CBA_fnc_localEvent; - }; -}; diff --git a/addons/medical/script_macros_medical.hpp b/addons/medical/script_macros_medical.hpp index 6063871c5c..7034be96fc 100644 --- a/addons/medical/script_macros_medical.hpp +++ b/addons/medical/script_macros_medical.hpp @@ -17,28 +17,30 @@ // 0.077 l/kg * 80kg = 6.16l #define DEFAULT_BLOOD_VOLUME 6.0 // in liters -#define BLOOD_VOLUME_HAS_LOST_SOME 5.700 // lost 5% blood, Class I Hemorrhage -#define BLOOD_VOLUME_HAS_LOST_MUCH 5.100 // lost 15% blood, Class II Hemorrhage - -#define BLOOD_VOLUME_UNCONSCIOUS 4.200 // lost 30% blood, Class III Hemorrhage -#define BLOOD_VOLUME_DEAD 3.600 // lost 40% blood, Class IV Hemorrhage -#define BLOOD_VOLUME_CARDIAC_ARREST 1.2 // TBD +#define BLOOD_VOLUME_CLASS_1_HEMORRHAGE 6.000 // lost less than 15% blood, Class I Hemorrhage +#define BLOOD_VOLUME_CLASS_2_HEMORRHAGE 5.100 // lost more than 15% blood, Class II Hemorrhage +#define BLOOD_VOLUME_CLASS_3_HEMORRHAGE 4.200 // lost more than 30% blood, Class III Hemorrhage +#define BLOOD_VOLUME_CLASS_4_HEMORRHAGE 3.600 // lost more than 40% blood, Class IV Hemorrhage // IV Change per second calculation: -// 250ml should take 60 seconds to fill. 250ml/60s = 4.166ml/s. -#define IV_CHANGE_PER_SECOND ([1000, 4.166] select GVAR(advancedIVBags)) // in milliliters per second +// 250 ml should take 60 seconds to fill. 250 ml / 60 s ~ 4.1667 ml/s. +#define IV_CHANGE_PER_SECOND 4.1667 // in milliliters per second -// chance per second to get knocked out due to blood loss -#define BLOOD_LOSS_KNOCK_OUT_CHANCE 0.1 // 10% +// Minimum amount of damage required for penetrating wounds (also minDamage for velocity wounds) +#define PENETRATION_THRESHOLD 0.35 -// duration in seconds to stay knocked out due to blood loss -#define BLOOD_LOSS_KNOCK_OUT_DURATION (15 + random 20) - -// --- unconsciousness -#define DEFAULT_KNOCK_OUT_DELAY (5 + random 10) +// To be replaced by a proper blood pressure calculation +#define BLOOD_LOSS_KNOCK_OUT_THRESHOLD 0.5 // 50% of cardiac output // --- pain -#define PAIN_UNCONSCIOUS 0.7 +#define PAIN_UNCONSCIOUS 0.5 // duration in seconds to stay knocked out due to pain -#define PAIN_KNOCK_OUT_DURATION (15 + random 20) +#define PAIN_KNOCK_OUT_DURATION (5 + random 10) + +// Pain reduction per second +#define PAIN_REDUCTION_SPEED 0.001 + +// Chance to wake up when vitals are stable (checked once every SPONTANEOUS_WAKE_UP_INTERVAL seconds) +#define SPONTANEOUS_WAKE_UP_CHANCE 0.1 +#define SPONTANEOUS_WAKE_UP_INTERVAL 10 diff --git a/addons/medical/stringtable.xml b/addons/medical/stringtable.xml index fa5d6349ba..1d001f1c5f 100644 --- a/addons/medical/stringtable.xml +++ b/addons/medical/stringtable.xml @@ -2942,31 +2942,17 @@ Coefficiente che modifica l'intensità del dolore この係数では痛みの強さを変更できます - - Sync status - Синхронизация статуса - Synchronizuj status - Sincronizador estado - Status synchronisieren - Synchronizovat status - Sincronizar estado - Status de la synchronisation - Szinkronizációs állapot - Sincronizza stato - 同期状態 + + Full Heal Locations - - Keep unit status synced. Recommended on. - Синхронизировать статус юнитов. Рекомендуется включить. - Utrzymuj synchronizację statusu jednostek. Zalecane zostawienie tej opcji włączonej. - Mantener el estado de la unidad sincronizado. Recomendado activado - Status der Einheit synchron halten. Sollte aktiviert bleiben. - Udržuje status jednotky synchronizovaný. Doporučeno zapnout. - Mater o estado da unidade sincronizado. Recomendado ativado. - Garder l'unité synchronisée, Recommandé sur oui. - Egységállapotok szinkronizálása. Javasolt a bekapcsolása. - Mantieni lo stato delle unità sincronizzato. Consigliato attivo. - ユニット状態の同期を続けます。有効化を推奨。 + + Where does the PAK perform a full heal? + + + PAK effectiveness + + + PAK effectiveness when used outside of medical facilities Provides a medical system for both players and AI. diff --git a/addons/medical_ai/XEH_postInit.sqf b/addons/medical_ai/XEH_postInit.sqf index cdd1ff1c3e..101aa6ac5e 100644 --- a/addons/medical_ai/XEH_postInit.sqf +++ b/addons/medical_ai/XEH_postInit.sqf @@ -6,7 +6,7 @@ if ((GVAR(enabledFor) == 1) && {!isServer} && {hasInterface}) exitWith {}; // 1: Don't Run on non-hc Clients // Only run for AI that does not have to deal with advanced medical - if (EGVAR(medical,enableFor) == 1 || {hasInterface && {EGVAR(medical,level) == 2}}) exitWith {}; + if (EGVAR(medical,enableFor) == 1 || {hasInterface}) exitWith {}; ["ace_firedNonPlayer", { _unit setVariable [QGVAR(lastFired), CBA_missionTime]; diff --git a/addons/medical_damage/ACE_Medical_Injuries.hpp b/addons/medical_damage/ACE_Medical_Injuries.hpp index fcb377c9eb..551758114d 100644 --- a/addons/medical_damage/ACE_Medical_Injuries.hpp +++ b/addons/medical_damage/ACE_Medical_Injuries.hpp @@ -1,229 +1,86 @@ +// bleeding - maximum possible bleeding rate for a given wound type (0 .. 1) +// pain - maximum possible pain level for a given wound type (0 .. 1) + class ACE_Medical_Injuries { - // Defines all the possible injury types for advanced medical + // Defines all the possible injury types class wounds { // Source: Scarle // Also called scrapes, they occur when the skin is rubbed away by friction against another rough surface (e.g. rope burns and skinned knees). class Abrasion { name = CSTRING(Abrasion); - selections[] = {"All"}; - bleedingRate = 0.0001; - pain = 0.01; causes[] = {"falling", "ropeburn", "vehiclecrash", "unknown"}; + bleeding = 0.001; + pain = 0.4; minDamage = 0.01; - class Minor { - name = CSTRING(Abrasion_Minor); - minDamage = 0.01; - maxDamage = 0.2; - bleedingRate = 0.0001; - }; - class Medium { - name = CSTRING(Abrasion_Medium); - minDamage = 0.2; - maxDamage = 0.3; - bleedingRate = 0.00015; - }; - class Large { - name = CSTRING(Abrasion_Large); - minDamage = 0.3; - maxDamage = 0.5; - bleedingRate = 0.0002; - }; + maxDamage = 0.30; }; // Occur when an entire structure or part of it is forcibly pulled away, such as the loss of a permanent tooth or an ear lobe. Explosions, gunshots, and animal bites may cause avulsions. class Avulsions { name = CSTRING(Avulsion); - selections[] = {"All"}; - bleedingRate = 0.01; - pain = 0.3; causes[] = {"explosive", "vehiclecrash", "grenade", "shell", "bullet", "backblast", "bite"}; - minDamage = 0.2; - class Minor { - name = CSTRING(Avulsion_Minor); - minDamage = 0.2; - maxDamage = 0.3; - bleedingRate = 0.01; - }; - class Medium { - name = CSTRING(Avulsion_Medium); - minDamage = 0.3; - maxDamage = 0.6; - bleedingRate = 0.02; - }; - class Large { - name = CSTRING(Avulsion_Large); - minDamage = 0.5; - bleedingRate = 0.05; - }; + bleeding = 0.5; + pain = 1.0; + minDamage = 4; + causeLimping = 1; }; // Also called bruises, these are the result of a forceful trauma that injures an internal structure without breaking the skin. Blows to the chest, abdomen, or head with a blunt instrument (e.g. a football or a fist) can cause contusions. class Contusion { name = CSTRING(Contusion); - selections[] = {"All"}; - bleedingRate = 0.0; - pain = 0.05; causes[] = {"bullet", "backblast", "punch", "vehiclecrash", "falling"}; - minDamage = 0.01; - maxDamage = 0.1; - class Minor { - name = CSTRING(Contusion_Minor); - minDamage = 0.01; - maxDamage = 0.1; - }; - class Medium { - name = CSTRING(Contusion_Medium); - minDamage = 0.1; - maxDamage = 0.15; - }; - class Large { - name = CSTRING(Contusion_Large); - minDamage = 0.15; - maxDamage = 0.2; - }; + bleeding = 0.0; + pain = 0.3; + minDamage = 0.02; + maxDamage = 0.35; }; // Occur when a heavy object falls onto a person, splitting the skin and shattering or tearing underlying structures. class CrushWound { name = CSTRING(Crush); - selections[] = {"All"}; - bleedingRate = 0.01; - pain = 0.1; causes[] = {"falling", "vehiclecrash", "punch", "unknown"}; + bleeding = 0.1; + pain = 0.8; minDamage = 0.1; - class Minor { - name = CSTRING(Crush_Minor); - minDamage = 0.1; - maxDamage = 0.45; - bleedingRate = 0.005; - }; - class Medium { - name = CSTRING(Crush_Medium); - minDamage = 0.4; - maxDamage = 0.7; - bleedingRate = 0.007; - }; - class Large { - name = CSTRING(Crush_Large); - minDamage = 0.6; - bleedingRate = 0.0095; - }; + causeLimping = 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 { name = CSTRING(Cut); - selections[] = {"All"}; - bleedingRate = 0.01; - pain = 0.075; causes[] = {"vehiclecrash", "grenade", "explosive", "shell", "backblast", "stab", "unknown"}; + bleeding = 0.04; + pain = 0.1; minDamage = 0.1; - class Minor { - name = CSTRING(Cut_Minor); - minDamage = 0.1; - maxDamage = 0.3; - bleedingRate = 0.005; - }; - class Medium { - name = CSTRING(Cut_Medium); - minDamage = 0.3; - maxDamage = 0.65; - bleedingRate = 0.02; - }; - class Large { - name = CSTRING(Cut_Large); - minDamage = 0.65; - bleedingRate = 0.05; - }; }; // Also called tears, these are separating wounds that produce ragged edges. They are produced by a tremendous force against the body, either from an internal source as in childbirth, or from an external source like a punch. class Laceration { name = CSTRING(Laceration); selections[] = {"All"}; - bleedingRate = 0.01; - pain = 0.075; causes[] = {"vehiclecrash", "punch"}; + bleeding = 0.05; + pain = 0.2; minDamage = 0.01; - class Minor { - name = CSTRING(Laceration_Minor); - minDamage = 0.1; - maxDamage = 0.5; - bleedingRate = 0.005; - }; - class Medium { - name = CSTRING(Laceration_Medium); - minDamage = 0.5; - maxDamage = 0.7; - bleedingRate = 0.01; - }; - class Large { - name = CSTRING(Laceration_Large); - minDamage = 0.7; - bleedingRate = 0.03; - }; }; // Also called velocity wounds, they are caused by an object entering the body at a high speed, typically a bullet or small peices of shrapnel. class velocityWound { name = CSTRING(VelocityWound); - selections[] = {"All"}; - bleedingRate = 0.01; - pain = 0.2; causes[] = {"bullet", "grenade","explosive", "shell", "unknown"}; - minDamage = 0.15; - class Minor { - name = CSTRING(VelocityWound_Minor); - minDamage = 0.15; - maxDamage = 0.3; - bleedingRate = 0.025; - }; - class Medium { - name = CSTRING(VelocityWound_Medium); - minDamage = 0.3; - maxDamage = 0.75; - bleedingRate = 0.05; - }; - class Large { - name = CSTRING(VelocityWound_Large); - minDamage = 0.75; - bleedingRate = 0.1; - }; + bleeding = 1.0; + pain = 0.9; + minDamage = 0.35; + causeLimping = 1; }; // Deep, narrow wounds produced by sharp objects such as nails, knives, and broken glass. class punctureWound { name = CSTRING(PunctureWound); - selections[] = {"All"}; - bleedingRate = 0.01; - pain = 0.075; causes[] = {"stab", "grenade"}; - minDamage = 0.01; - class Minor { - name = CSTRING(PunctureWound_Minor); - minDamage = 0.01; - maxDamage = 0.5; - bleedingRate = 0.01; - }; - class Medium { - name = CSTRING(PunctureWound_Medium); - minDamage = 0.5; - maxDamage = 0.75; - bleedingRate = 0.03; - }; - class Large { - name = CSTRING(PunctureWound_Large); - minDamage = 0.65; - bleedingRate = 0.08; - }; - }; - }; - class fractures { - class Femur { - name = CSTRING(Femur); - selections[] = {"Head", "Body"}; - pain = 0.2; - causes[] = {"Bullet", "VehicleCrash", "Backblast", "Explosive", "Shell", "Grenade"}; - minDamage = 0.5; + bleeding = 0.1; + pain = 0.4; + minDamage = 0.02; + causeLimping = 1; }; }; class damageTypes { + // thresholds[] {{, }, {...}} thresholds[] = {{0.1, 1}}; selectionSpecific = 1; - lethalDamage = 0.01; class bullet { // above damage, amount. Put the highest threshold to the left and lower the threshold with the elements to the right of it. @@ -243,14 +100,12 @@ class ACE_Medical_Injuries { selectionSpecific = 0; }; class vehiclecrash { - thresholds[] = {{0.25, 5}, {0.05, 1}}; + thresholds[] = {{0.5, 5}, {0.3, 2}, {0.05, 1}}; selectionSpecific = 0; - lethalDamage = 0.2; }; class backblast { thresholds[] = {{1, 6}, {0.55, 5}, {0, 2}}; selectionSpecific = 0; - lethalDamage = 1; }; class stab { thresholds[] = {{0.1, 1}}; @@ -261,9 +116,8 @@ class ACE_Medical_Injuries { selectionSpecific = 1; }; class falling { - thresholds[] = {{0.1, 1}}; + thresholds[] = {{0.6, 4}, {0.35, 2}, {0.1, 1}}; selectionSpecific = 1; - lethalDamage = 0.4; }; class ropeburn { thresholds[] = {{0.1, 1}}; diff --git a/addons/medical_damage/XEH_PREP.hpp b/addons/medical_damage/XEH_PREP.hpp index bcb3063929..a5ac88c01c 100644 --- a/addons/medical_damage/XEH_PREP.hpp +++ b/addons/medical_damage/XEH_PREP.hpp @@ -2,8 +2,4 @@ PREP(parseConfigForInjuries); PREP(getTypeOfDamage); -PREP(airwayHandler); -PREP(fracturesHandler); -PREP(internalInjuriesHandler); PREP(woundsHandler); -PREP(woundsHandlerSQF); diff --git a/addons/medical_damage/XEH_preInit.sqf b/addons/medical_damage/XEH_preInit.sqf index 2ccc6e57bc..bca40832c8 100644 --- a/addons/medical_damage/XEH_preInit.sqf +++ b/addons/medical_damage/XEH_preInit.sqf @@ -6,18 +6,11 @@ ADDON = false; call FUNC(parseConfigForInjuries); -// decide which woundsHandler to use by whether the extension is present or not -if ("ace_medical" callExtension "version" != "") then { - DFUNC(woundsHandlerActive) = FUNC(woundsHandler); -} else { - DFUNC(woundsHandlerActive) = FUNC(woundsHandlerSQF); -}; - [QEGVAR(medical_engine,woundReceived), { params ["_unit", "_woundedHitPoint", "_receivedDamage", "", "_ammo"]; private _typeOfDamage = _ammo call FUNC(getTypeOfDamage); - [_unit, _woundedHitPoint, _receivedDamage, _ammo, _typeOfDamage] call FUNC(woundsHandlerActive); // TODO also support the sqf variant + [_unit, _woundedHitPoint, _receivedDamage, _ammo, _typeOfDamage] call FUNC(woundsHandler); [_unit, EGVAR(medical,STATE_MACHINE)] call EFUNC(medical,addStateHandler); }] call CBA_fnc_addEventHandler; diff --git a/addons/medical_damage/functions/fnc_airwayHandler.sqf b/addons/medical_damage/functions/fnc_airwayHandler.sqf deleted file mode 100644 index 1d9dfdce25..0000000000 --- a/addons/medical_damage/functions/fnc_airwayHandler.sqf +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Author: Glowbal - * Handling of the airway injuries upon the handleDamage eventhandler. - * - * Arguments: - * 0: Unit That Was Hit - * 1: Name Of Body Part - * 2: Amount Of Damage - * 3: Shooter or source of the damage - * 4: Type of the damage done - * - * Return Value: - * None - * - * Public: No - */ -#include "script_component.hpp" - -params ["_unit", "_bodyPart", "_amountOfDamage", "_sourceOfDamage", "_typeOfDamage"]; - -private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; - -if (_partIndex > 1) exitWith {}; - -if (_amountOfDamage > 0.5) then { - if (random(1) >= 0.8) then { - if !(_unit getVariable[QGVAR(airwayCollapsed), false]) then { - _unit setVariable [QGVAR(airwayCollapsed), true, true]; - }; - }; -}; diff --git a/addons/medical_damage/functions/fnc_fracturesHandler.sqf b/addons/medical_damage/functions/fnc_fracturesHandler.sqf deleted file mode 100644 index 137bdc3962..0000000000 --- a/addons/medical_damage/functions/fnc_fracturesHandler.sqf +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Author: Glowbal - * Handling of the fracture injuries upon the handleDamage eventhandler. - * - * Arguments: - * 0: Unit That Was Hit - * 1: Name Of Body Part - * 2: Amount Of Damage - * 3: Shooter or source of the damage - * 4: Type of the damage done - * - * Return Value: - * None - * - * Public: No - */ -#include "script_component.hpp" - -params ["_unit", "_bodyPart", "_amountOfDamage", "_sourceOfDamage", "_typeOfDamage"]; - -private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; - -private _fractureType = 1; - -if (_amountOfDamage > 0.05) then { - // TODO specify fractures based off typeOfInjury details better. - switch (_typeOfDamage) do { - case "Bullet": { - _fractureType = round(random(2)); - }; - case "Grenade": { - _fractureType = round(random(2)); - if (_fractureType < 1) then { - _fractureType = 1; - }; - }; - case "Explosive": { - _fractureType = round(random(2)); - if (_fractureType < 1) then { - _fractureType = 1; - }; - }; - case "Shell": { - _fractureType = round(random(2)); - if (_fractureType < 1) then { - _fractureType = 1; - }; - }; - case "Unknown": { - _fractureType = round(random(1)); - }; - case "VehicleCrash": { - _fractureType = round(random(0)); - }; - default { - _fractureType = round(random(1)); - }; - }; - - private _fractures = _unit getVariable[QGVAR(fractures), []]; - private _fractureID = 1; - private _amountOf = count _fractures; - - if (_amountOf > 0) then { - _fractureID = (_fractures select (_amountOf - 1) select 0) + 1; - }; - - _fractures pushBack [_fractureID, _fractureType, _partIndex, 1 /* percentage treated */]; - _unit setVariable [QGVAR(fractures), _fractures, true]; -}; diff --git a/addons/medical_damage/functions/fnc_internalInjuriesHandler.sqf b/addons/medical_damage/functions/fnc_internalInjuriesHandler.sqf deleted file mode 100644 index c6e4501685..0000000000 --- a/addons/medical_damage/functions/fnc_internalInjuriesHandler.sqf +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Author: Glowbal - * Handling of the internal injuries upon the handleDamage eventhandler. - * - * Arguments: - * 0: Unit That Was Hit - * 1: Name Of Body Part - * 2: Amount Of Damage - * 3: Shooter or source of the damage - * 4: Type of the damage done - * - * Return Value: - * None - * - * Public: No - */ - -#include "script_component.hpp" - -params ["_unit", "_bodyPart", "_amountOfDamage", "_sourceOfDamage", "_typeOfDamage"]; - -// private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; -// TODO implement internal injuries diff --git a/addons/medical_damage/functions/fnc_parseConfigForInjuries.sqf b/addons/medical_damage/functions/fnc_parseConfigForInjuries.sqf index a4dd9d7b62..bd68b8291a 100644 --- a/addons/medical_damage/functions/fnc_parseConfigForInjuries.sqf +++ b/addons/medical_damage/functions/fnc_parseConfigForInjuries.sqf @@ -12,55 +12,6 @@ */ #include "script_component.hpp" -private _fnc_getAnyFromConfig = { - params ["_config", "_default"]; - - if (_default isEqualType []) exitWith { - GET_ARRAY(_config,_default) - }; - - if (_default isEqualType 0) exitWith { - GET_NUMBER(_config,_default) - }; - - if (_default isEqualType "") exitWith { - GET_STRING(_config,_default) - }; - - _default -}; - -private _fnc_parseSubClassWounds = { - params ["_subClass"]; - - private _subClassConfig = _entry >> _subClass; - - if (isClass _subClassConfig) exitWith { - private _subClassSelections = [_subClassConfig >> "selections", _selections] call _fnc_getAnyFromConfig; - private _subClassCauses = [_subClassConfig >> "causes", _causes] call _fnc_getAnyFromConfig; - - if (count _subClassSelections > 0 && {count _subClassCauses > 0}) then { - // constructs a type name, such as: 'woundMinor' - GVAR(woundClassNames) pushBack (_className + configName _subClassConfig); - GVAR(woundsData) pushBack [ - _classID, - _subClassSelections, - [_subClassConfig >> "bleedingRate", _bleedingRate] call _fnc_getAnyFromConfig, - [_subClassConfig >> "pain", _pain] call _fnc_getAnyFromConfig, - [[_subClassConfig >> "minDamage", _minDamage] call _fnc_getAnyFromConfig, [_subClassConfig >> "maxDamage", _maxDamage] call _fnc_getAnyFromConfig], - _subClassCauses, - [_subClassConfig >> "name", _displayName + " " + _subClass] call _fnc_getAnyFromConfig - ]; - - _classID = _classID + 1; - }; - - true - }; - - false -}; - private _injuriesConfigRoot = configFile >> "ACE_Medical_Injuries"; // --- parse wounds @@ -74,36 +25,28 @@ private _classID = 0; private _entry = _x; private _className = configName _entry; - private _selections = GET_ARRAY(_entry >> "selections",[]); - private _bleedingRate = GET_NUMBER(_entry >> "bleedingRate",0); + private _selections = GET_ARRAY(_entry >> "selections",["All"]); + private _bleeding = GET_NUMBER(_entry >> "bleeding",0); private _pain = GET_NUMBER(_entry >> "pain",0); private _minDamage = GET_NUMBER(_entry >> "minDamage",0); private _maxDamage = GET_NUMBER(_entry >> "maxDamage",-1); private _causes = GET_ARRAY(_entry >> "causes",[]); private _displayName = GET_STRING(_entry >> "name",_className); // @todo, don't translate in config + private _causeLimping = GET_NUMBER(_entry >> "causeLimping",0); - // TODO instead of hardcoding minor, medium and large just go through all sub classes recursively until none are found - if !("Minor" call _fnc_parseSubClassWounds || "Medium" call _fnc_parseSubClassWounds || "Large" call _fnc_parseSubClassWounds) then { - // There were no subclasses, so we will add this one instead. - if (count _selections > 0 && {count _causes > 0}) then { - GVAR(woundClassNames) pushBack _className; - GVAR(woundsData) pushBack [_classID, _selections, _bleedingRate, _pain, [_minDamage, _maxDamage], _causes, _displayName]; - _classID = _classID + 1; - }; + if (count _causes > 0) then { + GVAR(woundClassNames) pushBack _className; + GVAR(woundsData) pushBack [_classID, _selections, _bleeding, _pain, [_minDamage, _maxDamage], _causes, _displayName, _causeLimping]; + _classID = _classID + 1; }; } forEach configProperties [_woundsConfig, "isClass _x"]; -// --- parse fractures -//GVAR(fractureClassNames) = []; // unused - // --- parse damage types GVAR(allDamageTypes) = []; // @todo, currently unused by handle damage (was GVAR(allAvailableDamageTypes)) -GVAR(lethalDamages) = []; // @todo, currently unused by handle damage (was GVAR(minLethalDamages)) GVAR(allDamageTypesData) = [] call CBA_fnc_createNamespace; // minimum lethal damage collection, mapped to damageTypes private _damageTypesConfig = _injuriesConfigRoot >> "damageTypes"; -private _lethalDamageDefault = getNumber (_damageTypesConfig >> "lethalDamage"); private _thresholdsDefault = getArray (_damageTypesConfig >> "thresholds"); private _selectionSpecificDefault = getNumber (_damageTypesConfig >> "selectionSpecific"); @@ -113,7 +56,6 @@ private _selectionSpecificDefault = getNumber (_damageTypesConfig >> "selectionS private _className = configName _entry; GVAR(allDamageTypes) pushBack _className; - GVAR(lethalDamages) pushBack GET_NUMBER(_entry >> "lethalDamage",_lethalDamageDefault); // 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 = []; @@ -138,7 +80,7 @@ private _selectionSpecificDefault = getNumber (_damageTypesConfig >> "selectionS private _extensionArgs = format [ "addDamageType,%1,%2,%3,%4,%5", _className, - GVAR(lethalDamages) select _forEachIndex, + 1, //@todo remove 'minLethalDamage' from extension _minDamageThresholds, _amountThresholds, _selectionSpecific diff --git a/addons/medical_damage/functions/fnc_woundsHandler.sqf b/addons/medical_damage/functions/fnc_woundsHandler.sqf index 6fa35b1dcc..f1dfb6eb03 100644 --- a/addons/medical_damage/functions/fnc_woundsHandler.sqf +++ b/addons/medical_damage/functions/fnc_woundsHandler.sqf @@ -36,25 +36,43 @@ private _woundsCreated = []; call compile _extensionOutput; +// todo: Make the pain and bleeding calculations part of the extension again +private _painLevel = 0; { - _x params ["", "_woundClassIDToAdd", "_bodyPartNToAdd"]; + _x params ["", "_woundClassIDToAdd", "_bodyPartNToAdd", "", "_bleeding"]; - _foundIndex = -1; - { - // Check if we have an id of the given class on the given bodypart already - if ((_woundClassIDToAdd isEqualTo (_x select 1)) && {_bodyPartNToAdd isEqualTo (_x select 2)}) exitWith { - _foundIndex = _forEachIndex; - }; - } forEach _openWounds; - - if (_foundIndex < 0) then { - // Since it is a new injury, we will have to add it to the open wounds array to store it - _openWounds pushBack _x; + // The higher the nastiness likelihood the higher the change to get a painful and bloody wound + private _nastinessLikelihood = if (_damage > 1) then { + (_damage ^ 0.33) } else { - // We already have one of these, so we are just going to increase the number that we have of it with a new one. - private _injury = _openWounds select _foundIndex; - _injury set [3, (_injury select 3) + 1]; + (0.1 max _damage) }; + private _bloodiness = 0.01 + 0.99 * (1 - random[0, 1, 0.9]) ^ (1 / _nastinessLikelihood); + private _painfullness = 0.05 + 0.95 * (1 - random[0, 1, 0.5]) ^ (1 / _nastinessLikelihood); + + _bleeding = _bleeding * _bloodiness; + + _x set [4, _bleeding]; + _x set [5, _damage]; + + private _pain = ((GVAR(woundsData) select _woundClassIDToAdd) select 3) * _painfullness; + _painLevel = _painLevel max _pain; + +#ifdef DEBUG_MODE_FULL + systemChat format["%1, damage: %2, peneration: %3, bleeding: %4, pain: %5", _bodyPart, round(_damage * 100) / 100, _damage > PENETRATION_THRESHOLD, round(_bleeding * 1000) / 1000, round(_pain * 1000) / 1000]; +#endif + + if (_bodyPartNToAdd == 0 && {_damage > 1}) then { + [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 && {_damage > 0.3} && {_bodyPartNToAdd > 3}) then { + [_unit, true] call EFUNC(medical_engine,setLimping); + }; + + _openWounds pushBack _x; } forEach _woundsCreated; _unit setVariable [QEGVAR(medical,openWounds), _openWounds, true]; @@ -64,9 +82,10 @@ _unit setVariable [QEGVAR(medical,openWounds), _openWounds, true]; // Only update if new wounds have been created if (count _woundsCreated > 0) then { _unit setVariable [QEGVAR(medical,lastUniqueWoundID), _woundID, true]; + [_unit] call EFUNC(medical,handleIncapacitation); }; -[_unit, _painToAdd] call EFUNC(medical,addPain); -[_unit, "hit", PAIN_TO_SCREAM(_painToAdd)] call EFUNC(medical_engine,playInjuredSound); +[_unit, _painLevel] call EFUNC(medical,adjustPainLevel); +[_unit, "hit", PAIN_TO_SCREAM(_painLevel)] call EFUNC(medical_engine,playInjuredSound); -TRACE_5("exit",_unit, _painToAdd, _unit getVariable QEGVAR(medical,pain), _unit getVariable QEGVAR(medical,openWounds),_woundsCreated); +TRACE_5("exit",_unit,_painLevel,_unit getVariable QEGVAR(medical,pain),_unit getVariable QEGVAR(medical,openWounds),_woundsCreated); diff --git a/addons/medical_damage/functions/fnc_woundsHandlerSQF.sqf b/addons/medical_damage/functions/fnc_woundsHandlerSQF.sqf deleted file mode 100644 index f8c94dbef4..0000000000 --- a/addons/medical_damage/functions/fnc_woundsHandlerSQF.sqf +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Author: Glowbal, commy2 - * Handling of the open wounds & injuries upon the handleDamage eventhandler. - * - * Arguments: - * 0: Unit That Was Hit - * 1: Name Of Body Part - * 2: Amount Of Damage - * 3: Shooter or source of the damage - * 4: Type of the damage done - * - * Return Value: - * None - * - * Public: No - */ -#include "script_component.hpp" - -params ["_unit", "_bodyPart", "_damage", "_typeOfProjectile", "_typeOfDamage"]; -TRACE_5("start",_unit,_bodyPart,_damage,_typeOfProjectile,_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 (_typeOfDamage isEqualTo "") then { - _typeOfDamage = "unknown"; -}; - -// Get the damage type information. Format: [typeDamage thresholds, selectionSpecific, woundTypes] -// WoundTypes are the available wounds for this damage type. Format [[classID, selections, bleedingRate, pain], ..] -private _damageTypeInfo = [GVAR(allDamageTypesData) getVariable _typeOfDamage] param [0, [[], false, []]]; -_damageTypeInfo params ["_thresholds", "_isSelectionSpecific", "_woundTypes"]; - -// It appears we are dealing with an unknown type of damage. -if (count _woundTypes == 0) then { - // grabbing the configuration for unknown damage type - _damageTypeInfo = [GVAR(allDamageTypesData) getVariable "unknown"] param [0, [[], false, []]]; - _woundTypes = _damageTypeInfo select 2; -}; - -// find the available injuries for this damage type and damage amount -private _highestPossibleSpot = -1; -private _highestPossibleDamage = -1; -private _allPossibleInjuries = []; - -{ - _x params ["", "_selections", "", "", "_damageExtrema"]; - _damageExtrema params ["_minDamage", "_maxDamage"]; - - // Check if the damage is higher as the min damage for the specific injury - if (_damage >= _minDamage && {_damage <= _maxDamage || _maxDamage < 0}) then { - // Check if the injury can be applied to the given selection name - if ("All" in _selections || _bodyPart in _selections) then { // @todo, this is case sensitive! - - // Find the wound which has the highest minimal damage, so we can use this later on for adding the correct injuries - if (_minDamage > _highestPossibleDamage) then { - _highestPossibleSpot = _forEachIndex; - _highestPossibleDamage = _minDamage; - }; - - // Store the valid possible injury for the damage type, damage amount and selection - _allPossibleInjuries pushBack _x; - }; - }; -} forEach _woundTypes; - -// No possible wounds available for this damage type or damage amount. -if (_highestPossibleSpot < 0) exitWith {}; - -// Administration for open wounds and ids -private _openWounds = _unit getVariable [QEGVAR(medical,openWounds), []]; -private _woundID = _unit getVariable [QGVAR(lastUniqueWoundID), 1]; - -private _painToAdd = 0; -private _woundsCreated = []; - -{ - if (_x select 0 <= _damage) exitWith { - for "_i" from 0 to ((_x select 1)-1) 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 - } else { - selectRandom _allPossibleInjuries - }; - - _oldInjury params ["_woundClassIDToAdd", "", "_injuryBleedingRate", "_injuryPain"]; - - private _bodyPartNToAdd = [floor random 6, _bodyPartN] select _isSelectionSpecific; // 6 == count ALL_BODY_PARTS - - // If the injury type is selection part specific, we will check if one of those injury types already exists and find the spot for it.. - private _foundIndex = -1; - if (_isSelectionSpecific) then { - { - // Check if we have an id of the given class on the given bodypart already - if ((_woundClassIDToAdd isEqualTo (_x select 1)) && {_bodyPartNToAdd isEqualTo (_x select 2)}) exitWith { - _foundIndex = _forEachIndex; - }; - } forEach _openWounds; - }; - - private _injury = []; - if (_foundIndex < 0) then { - // Create a new injury. Format [ID, classID, bodypart, percentage treated, bleeding rate] - _injury = [_woundID, _woundClassIDToAdd, _bodyPartNToAdd, 1, _injuryBleedingRate]; - - // Since it is a new injury, we will have to add it to the open wounds array to store it - _openWounds pushBack _injury; - - // New injuries will also increase the wound ID - _woundID = _woundID + 1; - } else { - // We already have one of these, so we are just going to increase the number that we have of it with a new one. - _injury = _openWounds select _foundIndex; - _injury set [3, (_injury select 3) + 1]; - }; - - // Store the injury so we can process it later correctly. - _woundsCreated pushBack _injury; - - // Collect the pain that is caused by this injury - _painToAdd = _injuryPain + _painToAdd; - }; - }; -} forEach _thresholds; - -_unit setVariable [QEGVAR(medical,openWounds), _openWounds, true]; - -[_unit, _bodyPart] call EFUNC(medical_engine,updateBodyPartVisuals); - -// Only update if new wounds have been created -if (count _woundsCreated > 0) then { - _unit setVariable [QGVAR(lastUniqueWoundID), _woundID, true]; -}; - -[_unit, _painToAdd] call EFUNC(medical,addPain); -[_unit, "hit", PAIN_TO_SCREAM(_painToAdd)] call EFUNC(medical_engine,playInjuredSound); - -TRACE_5("exit",_unit, _painToAdd, _unit getVariable QEGVAR(medical,pain), _unit getVariable QEGVAR(medical,openWounds),_woundsCreated); diff --git a/addons/medical_engine/XEH_postInit.sqf b/addons/medical_engine/XEH_postInit.sqf index 1546ef280d..5cf7ab35cc 100644 --- a/addons/medical_engine/XEH_postInit.sqf +++ b/addons/medical_engine/XEH_postInit.sqf @@ -18,8 +18,8 @@ #ifdef DEBUG_MODE_FULL [QGVAR(woundReceived), { - diag_log _this; - systemChat str _this; + //diag_log _this; + //systemChat str _this; }] call CBA_fnc_addEventHandler; #endif diff --git a/addons/medical_engine/functions/fnc_handleDamage.sqf b/addons/medical_engine/functions/fnc_handleDamage.sqf index 9cf33eefa0..3b9a81bdf6 100644 --- a/addons/medical_engine/functions/fnc_handleDamage.sqf +++ b/addons/medical_engine/functions/fnc_handleDamage.sqf @@ -104,7 +104,13 @@ if (_hitPoint isEqualTo "ace_hdbracket") exitWith { // Check for falling damage. if (_ammo isEqualTo "") then { if (velocity _unit select 2 < -2) then { - _woundedHitPoint = selectRandom ["LeftLeg", "RightLeg"]; + if (_receivedDamage < 0.35) then { + // Less than ~ 5 m + _woundedHitPoint = selectRandom ["LeftLeg", "RightLeg"]; + } else { + // More than ~ 5 m + _woundedHitPoint = selectRandom ["LeftLeg", "RightLeg", "Body", "Head"]; + }; _ammo = "#falling"; } else { // Assume collision damage. diff --git a/addons/medical_engine/functions/fnc_updateBodyPartVisuals.sqf b/addons/medical_engine/functions/fnc_updateBodyPartVisuals.sqf index e3f4a2f168..5168072115 100644 --- a/addons/medical_engine/functions/fnc_updateBodyPartVisuals.sqf +++ b/addons/medical_engine/functions/fnc_updateBodyPartVisuals.sqf @@ -44,22 +44,22 @@ switch (toLower _bodyPart) do { }; private _openWounds = _unit getVariable QEGVAR(medical,openWounds); -private _bloodLossOnAffectedBodyParts = 0; +private _damageOnAffectedBodyParts = 0; { - private _bloodLossOnBodyPart = 0; + private _damageOnBodyPart = 0; private _partIndex = ALL_BODY_PARTS find toLower _x; { - _x params ["", "", "_bodyPartN", "_amountOf", "_percentageOpen"]; + _x params ["", "", "_bodyPartN", "", "_bleeding", "_damage"]; if (_bodyPartN isEqualTo _partIndex) then { - _bloodLossOnBodyPart = _bloodLossOnBodyPart + (_amountOf * _percentageOpen); + _damageOnBodyPart = _damageOnBodyPart + _damage; }; } forEach _openWounds; // report maximum of both legs or arms - _bloodLossOnAffectedBodyParts = _bloodLossOnAffectedBodyParts max _bloodLossOnBodyPart; + _damageOnAffectedBodyParts = _damageOnAffectedBodyParts max _damageOnBodyPart; } forEach _affectedBodyParts; -[_unit, _bodyPart, _bloodLossOnAffectedBodyParts > 0] call FUNC(damageBodyPart); +[_unit, _bodyPart, _damageOnAffectedBodyParts > 0.35] call FUNC(damageBodyPart); diff --git a/addons/medical_menu/CfgVehicles.hpp b/addons/medical_menu/CfgVehicles.hpp index 9e227d4305..f0849a4402 100644 --- a/addons/medical_menu/CfgVehicles.hpp +++ b/addons/medical_menu/CfgVehicles.hpp @@ -48,7 +48,7 @@ class CfgVehicles { displayName = ECSTRING(medical,Actions_Medical); runOnHover = 1; exceptions[] = {"isNotInside", "isNotSitting"}; - statement = QUOTE([ARR_3(_target, true, 0)] call EFUNC(medical_treatment,displayPatientInformation)); + statement = QUOTE([ARR_3(_target,1,0)] call EFUNC(medical_treatment,displayPatientInformation)); condition = "true"; icon = QPATHTOEF(medical,UI\icons\medical_cross.paa); #include "InteractionBodyParts.hpp" diff --git a/addons/medical_menu/InteractionBodyParts.hpp b/addons/medical_menu/InteractionBodyParts.hpp index 7e1b9fc8e7..56d6f3bfd2 100644 --- a/addons/medical_menu/InteractionBodyParts.hpp +++ b/addons/medical_menu/InteractionBodyParts.hpp @@ -2,7 +2,7 @@ class ACE_Head { displayName = ECSTRING(interaction,Head); icon = QPATHTOEF(medical,UI\icons\medical_cross.paa); exceptions[] = {"isNotInside", "isNotSitting"}; - statement = QUOTE([ARR_3(_target, true, 0)] call EFUNC(medical_treatment,displayPatientInformation)); + statement = QUOTE([ARR_3(_target,1,0)] call EFUNC(medical_treatment,displayPatientInformation)); modifierFunction = QUOTE([ARR_4(_target,_player,0,_this select 3)] call FUNC(modifyAction)); condition = "true"; runOnHover = 1; @@ -13,7 +13,7 @@ class ACE_Torso { condition = "true"; runOnHover = 1; exceptions[] = {"isNotInside", "isNotSitting"}; - statement = QUOTE([ARR_3(_target, true, 1)] call EFUNC(medical_treatment,displayPatientInformation)); + statement = QUOTE([ARR_3(_target,1,1)] call EFUNC(medical_treatment,displayPatientInformation)); modifierFunction = QUOTE([ARR_4(_target,_player,1,_this select 3)] call FUNC(modifyAction)); showDisabled = 1; priority = 2; @@ -23,7 +23,7 @@ class ACE_ArmLeft { displayName = ECSTRING(interaction,ArmLeft); runOnHover = 1; exceptions[] = {"isNotInside", "isNotSitting"}; - statement = QUOTE([ARR_3(_target, true, 2)] call EFUNC(medical_treatment,displayPatientInformation)); + statement = QUOTE([ARR_3(_target,1,2)] call EFUNC(medical_treatment,displayPatientInformation)); modifierFunction = QUOTE([ARR_4(_target,_player,2,_this select 3)] call FUNC(modifyAction)); condition = "true"; icon = QPATHTOEF(medical,UI\icons\medical_cross.paa); @@ -32,7 +32,7 @@ class ACE_ArmRight { displayName = ECSTRING(interaction,ArmRight); runOnHover = 1; exceptions[] = {"isNotInside", "isNotSitting"}; - statement = QUOTE([ARR_3(_target, true, 3)] call EFUNC(medical_treatment,displayPatientInformation)); + statement = QUOTE([ARR_3(_target,1,3)] call EFUNC(medical_treatment,displayPatientInformation)); modifierFunction = QUOTE([ARR_4(_target,_player,3,_this select 3)] call FUNC(modifyAction)); condition = "true"; icon = QPATHTOEF(medical,UI\icons\medical_cross.paa); @@ -41,7 +41,7 @@ class ACE_LegLeft { displayName = ECSTRING(interaction,LegLeft); runOnHover = 1; exceptions[] = {"isNotInside", "isNotSitting"}; - statement = QUOTE([ARR_3(_target, true, 4)] call EFUNC(medical_treatment,displayPatientInformation)); + statement = QUOTE([ARR_3(_target,1,4)] call EFUNC(medical_treatment,displayPatientInformation)); modifierFunction = QUOTE([ARR_4(_target,_player,4,_this select 3)] call FUNC(modifyAction)); condition = "true"; icon = QPATHTOEF(medical,UI\icons\medical_cross.paa); @@ -50,7 +50,7 @@ class ACE_LegRight { displayName = ECSTRING(interaction,LegRight); runOnHover = 1; exceptions[] = {"isNotInside", "isNotSitting"}; - statement = QUOTE([ARR_3(_target, true, 5)] call EFUNC(medical_treatment,displayPatientInformation)); + statement = QUOTE([ARR_3(_target,1,5)] call EFUNC(medical_treatment,displayPatientInformation)); modifierFunction = QUOTE([ARR_4(_target,_player,5,_this select 3)] call FUNC(modifyAction)); condition = "true"; icon = QPATHTOEF(medical,UI\icons\medical_cross.paa); diff --git a/addons/medical_menu/XEH_postInit.sqf b/addons/medical_menu/XEH_postInit.sqf index dff5817c77..6206620c9f 100644 --- a/addons/medical_menu/XEH_postInit.sqf +++ b/addons/medical_menu/XEH_postInit.sqf @@ -7,7 +7,7 @@ GVAR(lastOpenedOn) = -1; GVAR(pendingReopen) = false; ["ace_settingsInitialized", { - if (EGVAR(medical,level) > 0 && {EGVAR(medical,menuTypeStyle) == 0}) then { + if (EGVAR(medical,menuTypeStyle) == 0) then { [] call FUNC(collectActions3D); }; }] call CBA_fnc_addEventHandler; diff --git a/addons/medical_menu/functions/fnc_updateBodyImage.sqf b/addons/medical_menu/functions/fnc_updateBodyImage.sqf index 1d83b54372..565c7ef0d5 100644 --- a/addons/medical_menu/functions/fnc_updateBodyImage.sqf +++ b/addons/medical_menu/functions/fnc_updateBodyImage.sqf @@ -4,8 +4,9 @@ * * Arguments: * 0: selection bloodloss - * 1: damaged (array of bools) - * 2: display + * 1: selection damage + * 2: selection torniquet + * 3: display * * Return Value: * None @@ -17,7 +18,7 @@ */ #include "script_component.hpp" -params ["_selectionBloodLoss", "_damaged", "_display"]; +params ["_selectionBloodLoss", "_selectionDamage", "_selectionTourniquet", "_display"]; // Handle the body image coloring private _availableSelections = [50, 51, 52, 53, 54, 55]; @@ -26,16 +27,22 @@ private _availableSelections = [50, 51, 52, 53, 54, 55]; private _green = 1; private _blue = 1; - if (_x > 0) then { - if (_damaged select _forEachIndex) then { - _green = (0.9 - _x) max 0; + private _torniquet = _selectionTourniquet select _forEachIndex; + if (_torniquet > 0) then { + _red = 0.77; + _green = 0.51; + _blue = 0.08; + } else { + private _bloodLoss = _selectionBloodLoss select _forEachIndex; + if (_bloodLoss > 0) then { + _green = 0 max (0.9 - _bloodLoss); _blue = _green; } else { - _green = (0.9 - _x) max 0; + private _damage = _selectionDamage select _forEachIndex; + _green = 0 max (0.9 - _damage); _red = _green; - //_blue = _green; }; }; - (_display displayCtrl (_availableSelections select _forEachIndex)) ctrlSetTextColor [_red, _green, _blue, 1.0]; -} forEach _selectionBloodLoss; + (_display displayCtrl _x) ctrlSetTextColor [_red, _green, _blue, 1.0]; +} forEach _availableSelections; diff --git a/addons/medical_menu/functions/fnc_updateUIInfo.sqf b/addons/medical_menu/functions/fnc_updateUIInfo.sqf index 2b92d9f3a7..74fdbdf41e 100644 --- a/addons/medical_menu/functions/fnc_updateUIInfo.sqf +++ b/addons/medical_menu/functions/fnc_updateUIInfo.sqf @@ -18,15 +18,13 @@ params ["_target", "_display"]; -private ["_allInjuryTexts", "_bandagedwounds", "_damaged", "_genericMessages", "_logs", "_openWounds", "_part", "_partText", "_pointDamage", "_selectionBloodLoss", "_selectionN", "_severity", "_totalIvVolume", "_triageStatus"]; - if (isNil "_display" || {isNull _display}) exitWith {ERROR("No display");}; -_selectionN = GVAR(selectedBodyPart); +private _selectionN = GVAR(selectedBodyPart); if (_selectionN < 0 || {_selectionN > 5}) exitWith {}; -_genericMessages = []; -_partText = [ELSTRING(medical,Head), ELSTRING(medical,Torso), ELSTRING(medical,LeftArm) ,ELSTRING(medical,RightArm) ,ELSTRING(medical,LeftLeg), ELSTRING(medical,RightLeg)] select _selectionN; +private _genericMessages = []; +private _partText = [ELSTRING(medical,Head), ELSTRING(medical,Torso), ELSTRING(medical,LeftArm) ,ELSTRING(medical,RightArm) ,ELSTRING(medical,LeftLeg), ELSTRING(medical,RightLeg)] select _selectionN; _genericMessages pushBack [localize _partText, [1, 1, 1, 1]]; if (_target getVariable [QEGVAR(medical,isBleeding), false]) then { @@ -45,7 +43,7 @@ if (_target getVariable [QEGVAR(medical,hasPain), false]) then { _genericMessages pushBack [localize ELSTRING(medical,Status_Pain), [1, 1, 1, 1]]; }; -_totalIvVolume = 0; +private _totalIvVolume = 0; private _bloodBags = _target getVariable [QEGVAR(medical,ivBags), []]; { _x params ["_bagVolumeRemaining"]; @@ -56,96 +54,64 @@ if (_totalIvVolume >= 1) then { _genericMessages pushBack [format [localize ELSTRING(medical,receivingIvVolume), floor _totalIvVolume], [1, 1, 1, 1]]; }; -_damaged = [false, false, false, false, false, false]; -_selectionBloodLoss = [0, 0, 0, 0, 0, 0]; +private _selectionTourniquet = _target getVariable [QEGVAR(medical,tourniquets), [0,0,0,0,0,0]]; +private _selectionBloodLoss = [0, 0, 0, 0, 0, 0]; +private _selectionDamage = [0, 0, 0, 0, 0, 0]; +private _allInjuryTexts = []; -_allInjuryTexts = []; -if (EGVAR(medical,level) >= 2) then { // && {([_target] call EFUNC(medical,hasMedicalEnabled))} - _openWounds = _target getVariable [QEGVAR(medical,openWounds), []]; - private "_amountOf"; - { - _amountOf = _x select 3; - // Find how much this bodypart is bleeding +{ + _x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "_bleeding", "_damage"]; + _selectionBloodLoss set [_bodyPartN, (_selectionBloodLoss select _bodyPartN) + (20 * (_bleeding * _amountOf))]; + _selectionDamage set [_bodyPartN, (_selectionDamage select _bodyPartN) + _damage]; + if (_selectionN == _bodyPartN) then { + // Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this] if (_amountOf > 0) then { - _damaged set [_x select 2, true]; - _selectionBloodLoss set [_x select 2, (_selectionBloodLoss select (_x select 2)) + (20 * ((_x select 4) * _amountOf))]; - - if (_selectionN == (_x select 2)) then { - // Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this] - if (_amountOf >= 1) then { - // TODO localization - _allInjuryTexts pushBack [format["%2x %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6, ceil _amountOf], [1,1,1,1]]; - } else { - // TODO localization - _allInjuryTexts pushBack [format["Partial %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6], [1,1,1,1]]; - }; + if (_amountOf >= 1) then { + // TODO localization + _allInjuryTexts pushBack [format["%2x %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6, ceil _amountOf], [1,1,1,1]]; + } else { + // TODO localization + _allInjuryTexts pushBack [format["Partial %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6], [1,1,1,1]]; }; }; - } forEach _openWounds; - - _bandagedwounds = _target getVariable [QEGVAR(medical,bandagedWounds), []]; - { - _amountOf = _x select 3; - // Find how much this bodypart is bleeding - if !(_damaged select (_x select 2)) then { - _selectionBloodLoss set [_x select 2, (_selectionBloodLoss select (_x select 2)) + (20 * ((_x select 4) * _amountOf))]; - }; - if (_selectionN == (_x select 2)) then { - // Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this] - if (_amountOf > 0) then { - if (_amountOf >= 1) then { - // TODO localization - _allInjuryTexts pushBack [format ["[B] %2x %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6, ceil _amountOf], [0.88,0.7,0.65,1]]; - } else { - // TODO localization - _allInjuryTexts pushBack [format ["[B] Partial %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6], [0.88,0.7,0.65,1]]; - }; - }; - }; - } forEach _bandagedwounds; -} else { - - // Add all bleeding from wounds on selection - _openWounds = _target getVariable [QEGVAR(medical,openWounds), []]; - private "_amountOf"; - { - _amountOf = _x select 3; - // Find how much this bodypart is bleeding - if (_amountOf > 0) then { - _damaged set [_x select 2, true]; - _selectionBloodLoss set [_x select 2, (_selectionBloodLoss select (_x select 2)) + (20 * ((_x select 4) * _amountOf))]; - }; - } forEach _openWounds; - - _bandagedwounds = _target getVariable [QEGVAR(medical,bandagedWounds), []]; - { - _amountOf = _x select 3; - // Find how much this bodypart is bleeding - if !(_damaged select (_x select 2)) then { - _selectionBloodLoss set [_x select 2, (_selectionBloodLoss select (_x select 2)) + (20 * ((_x select 4) * _amountOf))]; - }; - } forEach _bandagedwounds; - - private _bloodLossOnSelection = _selectionBloodLoss select _selectionN; - if (_bloodLossOnSelection > 0) then { - private _severity = switch (true) do { - case (_bloodLossOnSelection > 0.5): {localize ELSTRING(medical,HeavilyWounded)}; - case (_bloodLossOnSelection > 0.1): {localize ELSTRING(medical,LightlyWounded)}; - default {localize ELSTRING(medical,VeryLightlyWounded)}; - }; - private _part = localize ([ - ELSTRING(medical,Head), - ELSTRING(medical,Torso), - ELSTRING(medical,LeftArm), - ELSTRING(medical,RightArm), - ELSTRING(medical,LeftLeg), - ELSTRING(medical,RightLeg) - ] select _selectionN); - _allInjuryTexts pushBack [format ["%1 %2", _severity, toLower _part], [1,1,1,1]]; }; -}; +} forEach (_target getVariable [QEGVAR(medical,openWounds), []]); -[_selectionBloodLoss, _damaged, _display] call FUNC(updateBodyImage); +{ + _x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "_bleeding", "_damage"]; + _selectionDamage set [_bodyPartN, (_selectionDamage select _bodyPartN) + _damage]; + if (_selectionN == _bodyPartN) then { + // Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this] + if (_amountOf > 0) then { + if (_amountOf >= 1) then { + // TODO localization + _allInjuryTexts pushBack [format ["[B] %2x %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6, ceil _amountOf], [0.88,0.7,0.65,1]]; + } else { + // TODO localization + _allInjuryTexts pushBack [format ["[B] Partial %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6], [0.88,0.7,0.65,1]]; + }; + }; + }; +} forEach (_target getVariable [QEGVAR(medical,bandagedWounds), []]); + +{ + _x params ["", "_woundClassID", "_bodyPartN", "_amountOf", "_bleeding", "_damage"]; + _selectionDamage set [_bodyPartN, (_selectionDamage select _bodyPartN) + _damage]; + if (_selectionN == _bodyPartN) then { + // Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this] + if (_amountOf > 0) then { + if (_amountOf >= 1) then { + // TODO localization + _allInjuryTexts pushBack [format ["[S] %2x %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6, ceil _amountOf], [0.7,0.7,0.7,1]]; + } else { + // TODO localization + _allInjuryTexts pushBack [format ["[S] Partial %1", (EGVAR(medical_damage,woundsData) select _woundClassID) select 6], [0.7,0.7,0.7,1]]; + }; + }; + }; +} forEach (_target getVariable [QEGVAR(medical,stitchedWounds), []]); + +[_selectionBloodLoss, _selectionDamage, _selectionTourniquet, _display] call FUNC(updateBodyImage); [_display, _genericMessages, _allInjuryTexts] call FUNC(updateInformationLists); [_display, _target getVariable [QEGVAR(medical,logFile_activity_view), []]] call FUNC(updateActivityLog); diff --git a/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp b/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp index 319bb65fa1..90bfdb6b7d 100644 --- a/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp +++ b/addons/medical_treatment/ACE_Medical_Treatment_Actions.hpp @@ -13,7 +13,6 @@ class GVAR(Actions) { treatmentTimeSelfCoef = 1; items[] = {{"ACE_fieldDressing", "ACE_packingBandage", "ACE_elasticBandage", "ACE_quikclot"}}; condition = QUOTE(!EGVAR(medical,advancedBandages)); - patientStateCondition = 0; itemConsumed = 1; callbackSuccess = QFUNC(treatmentBandage); callbackFailure = ""; @@ -76,7 +75,7 @@ class GVAR(Actions) { displayNameProgress = ECSTRING(medical,Applying_Tourniquet); allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"}; items[] = {"ACE_tourniquet"}; - treatmentTime = 4; + treatmentTime = 5; callbackSuccess = QFUNC(treatmentTourniquet); condition = QUOTE(EGVAR(medical,advancedBandages) && {!([ARR_2(_target,_bodyPart)] call EFUNC(medical,hasTourniquetAppliedTo))}); litter[] = {}; @@ -97,7 +96,7 @@ class GVAR(Actions) { category = "medication"; items[] = {"ACE_morphine"}; condition = ""; - treatmentTime = 10; + treatmentTime = 9; callbackSuccess = QFUNC(treatmentMedication); animationCaller = "AinvPknlMstpSnonWnonDnon_medic1"; litter[] = { {"All", "", {"ACE_MedicalLitter_morphine"}} }; @@ -106,12 +105,14 @@ class GVAR(Actions) { class Adenosine: Morphine { displayName = ECSTRING(medical,Inject_Adenosine); displayNameProgress = ECSTRING(medical,Injecting_Adenosine); + condition = QEGVAR(medical,advancedMedication); items[] = {"ACE_adenosine"}; litter[] = { {"All", "", {"ACE_MedicalLitter_adenosine"}} }; }; class Atropine: Morphine { displayName = ECSTRING(medical,Inject_Atropine); displayNameProgress = ECSTRING(medical,Injecting_Atropine); + condition = QEGVAR(medical,advancedMedication); items[] = {"ACE_atropine"}; litter[] = { {"All", "", {"ACE_MedicalLitter_atropine"}} }; }; @@ -205,6 +206,7 @@ class GVAR(Actions) { class CheckBloodPressure: CheckPulse { displayName = ECSTRING(medical,Actions_CheckBloodPressure); displayNameProgress = ECSTRING(medical,Check_Bloodpressure_Content); + allowedSelections[] = {"LeftArm", "RightArm", "LeftLeg", "RightLeg"}; callbackSuccess = QFUNC(actionCheckBloodPressure); }; class CheckResponse: CheckPulse { @@ -258,48 +260,42 @@ class GVAR(Actions) { litter[] = {}; }; -/* - class Advanced { - class SurgicalKit: fieldDressing { - displayName = ECSTRING(medical,Use_SurgicalKit); - displayNameProgress = ECSTRING(medical,Stitching); - category = "advanced"; - items[] = {"ACE_surgicalKit"}; - treatmentLocations[] = {QEGVAR(medical,useLocation_SurgicalKit)}; - allowSelfTreatment = 0; - requiredMedic = QEGVAR(medical,medicSetting_SurgicalKit); - patientStateCondition = QEGVAR(medical,useCondition_SurgicalKit); - treatmentTime = QUOTE(count (_target getVariable [ARR_2('EGVAR(medical,bandagedWounds)',[])]) * 5); - callbackSuccess = ""; - callbackProgress = QFUNC(treatmentSurgicalKit_onProgress); - itemConsumed = QEGVAR(medical,consumeItem_SurgicalKit); - animationCaller = "AinvPknlMstpSnonWnonDnon_medic1"; - litter[] = { {"All", "", {"ACE_MedicalLitter_gloves"} }}; - }; - class PersonalAidKit: fieldDressing { - displayName = ECSTRING(medical,Use_Aid_Kit); - displayNameProgress = ECSTRING(medical,TreatmentAction); - category = "advanced"; - items[] = {"ACE_personalAidKit"}; - treatmentLocations[] = {QEGVAR(medical,useLocation_PAK)}; - allowSelfTreatment = 0; - requiredMedic = QEGVAR(medical,medicSetting_PAK); - patientStateCondition = QEGVAR(medical,useCondition_PAK); - treatmentTime = QUOTE(_target call FUNC(treatmentFullHealTreatmentTime)); - callbackSuccess = QFUNC(treatmentFullHeal); - itemConsumed = QEGVAR(medical,consumeItem_PAK); - animationPatient = ""; - animationPatientUnconscious = "AinjPpneMstpSnonWrflDnon_rolltoback"; - animationCaller = "AinvPknlMstpSlayW[wpn]Dnon_medicOther"; - animationCallerProne = "AinvPpneMstpSlayW[wpn]Dnon_medicOther"; - animationCallerSelf = ""; - animationCallerSelfProne = ""; - litter[] = { {"All", "", {"ACE_MedicalLitter_gloves"}}, - {"All", "_bloodLossOnBodyPart > 0", {{"ACE_MedicalLitterBase", "ACE_MedicalLitter_bandage1", "ACE_MedicalLitter_bandage2", "ACE_MedicalLitter_bandage3"}}}, - {"All", "_bloodLossOnBodyPart > 0", {{"ACE_MedicalLitterBase", "ACE_MedicalLitter_bandage1", "ACE_MedicalLitter_bandage2", "ACE_MedicalLitter_bandage3"}}}, - {"All", "_bloodLossOnBodyPart <= 0", {"ACE_MedicalLitter_clean"}} - }; + class SurgicalKit: fieldDressing { + displayName = ECSTRING(medical,Use_SurgicalKit); + displayNameProgress = ECSTRING(medical,Stitching); + category = "advanced"; + items[] = {"ACE_surgicalKit"}; + treatmentLocations[] = {QEGVAR(medical,useLocation_SurgicalKit)}; + allowSelfTreatment = 0; + requiredMedic = QEGVAR(medical,medicSetting_SurgicalKit); + treatmentTime = QUOTE(count (_target getVariable [ARR_2('EGVAR(medical,bandagedWounds)',[])]) * 5); + callbackSuccess = ""; + callbackProgress = QFUNC(treatmentSurgicalKit_onProgress); + itemConsumed = QEGVAR(medical,consumeItem_SurgicalKit); + animationCaller = "AinvPknlMstpSnonWnonDnon_medic1"; + litter[] = { {"All", "", {"ACE_MedicalLitter_gloves"} }}; + }; + class PersonalAidKit: BasicBandage { + displayName = ECSTRING(medical,Use_Aid_Kit); + displayNameProgress = ECSTRING(medical,TreatmentAction); + category = "advanced"; + condition = QUOTE(_target call EFUNC(medical,isInStableCondition)); + items[] = {"ACE_personalAidKit"}; + treatmentLocations[] = {QEGVAR(medical,useLocation_PAK)}; + requiredMedic = QEGVAR(medical,medicSetting_PAK); + treatmentTime = QUOTE(_target call FUNC(treatmentFullHealTreatmentTime)); + callbackSuccess = QFUNC(treatmentFullHeal); + itemConsumed = QEGVAR(medical,consumeItem_PAK); + animationPatient = ""; + animationPatientUnconscious = "AinjPpneMstpSnonWrflDnon_rolltoback"; + animationCaller = "AinvPknlMstpSlayW[wpn]Dnon_medicOther"; + animationCallerProne = "AinvPpneMstpSlayW[wpn]Dnon_medicOther"; + animationCallerSelf = ""; + animationCallerSelfProne = ""; + litter[] = { {"All", "", {"ACE_MedicalLitter_gloves"}}, + {"All", "_bloodLossOnBodyPart > 0", {{"ACE_MedicalLitterBase", "ACE_MedicalLitter_bandage1", "ACE_MedicalLitter_bandage2", "ACE_MedicalLitter_bandage3"}}}, + {"All", "_bloodLossOnBodyPart > 0", {{"ACE_MedicalLitterBase", "ACE_MedicalLitter_bandage1", "ACE_MedicalLitter_bandage2", "ACE_MedicalLitter_bandage3"}}}, + {"All", "_bloodLossOnBodyPart <= 0", {"ACE_MedicalLitter_clean"}} }; }; -*/ }; diff --git a/addons/medical_treatment/functions/fnc_canTreat.sqf b/addons/medical_treatment/functions/fnc_canTreat.sqf index f7e75018f2..1643b18ccc 100644 --- a/addons/medical_treatment/functions/fnc_canTreat.sqf +++ b/addons/medical_treatment/functions/fnc_canTreat.sqf @@ -75,18 +75,6 @@ if (isText (_config >> "condition")) then { if !(_condition) exitWith {false}; -private _patientStateCondition = 0; - -if (isNumber (_config >> "patientStateCondition")) then { - _patientStateCondition = getNumber (_config >> "patientStateCondition"); -} else { - if (isText (_config >> "patientStateCondition")) then { - _patientStateCondition = missionNamespace getVariable [getText (_config >> "patientStateCondition"), 0]; - }; -}; - -if (_patientStateCondition == 1 && {!([_target] call EFUNC(medical,isInStableCondition))}) exitWith {false}; - // check allowed locations private _locations = getArray (_config >> "treatmentLocations") apply {toLower _x}; diff --git a/addons/medical_treatment/functions/fnc_checkItems.sqf b/addons/medical_treatment/functions/fnc_checkItems.sqf index 8115a9bd99..e8ceb0aaf4 100644 --- a/addons/medical_treatment/functions/fnc_checkItems.sqf +++ b/addons/medical_treatment/functions/fnc_checkItems.sqf @@ -20,38 +20,19 @@ _unit removeItems "FirstAidKit"; private _countMedikit = {_x == "Medikit"} count items _unit; _unit removeItems "Medikit"; -if (EGVAR(medical,level) >= 2) then { - // --- advanced - for "" from 1 to _countFirstAidKit do { - _unit addItem "ACE_fieldDressing"; - _unit addItem "ACE_packingBandage"; - _unit addItem "ACE_morphine"; - _unit addItem "ACE_tourniquet"; - }; - - for "" from 1 to _countMedikit do { - _unit addItemToBackpack "ACE_fieldDressing"; - _unit addItemToBackpack "ACE_packingBandage"; - _unit addItemToBackpack "ACE_packingBandage"; - _unit addItemToBackpack "ACE_epinephrine"; - _unit addItemToBackpack "ACE_morphine"; - _unit addItemToBackpack "ACE_salineIV_250"; - _unit addItemToBackpack "ACE_tourniquet"; - }; -} else { - // --- basic - for "" from 1 to _countFirstAidKit do { - _unit addItem "ACE_fieldDressing"; - _unit addItem "ACE_fieldDressing"; - _unit addItem "ACE_morphine"; - }; - - for "" from 1 to _countMedikit do { - _unit addItemToBackpack "ACE_epinephrine"; - _unit addItemToBackpack "ACE_epinephrine"; - _unit addItemToBackpack "ACE_epinephrine"; - _unit addItemToBackpack "ACE_epinephrine"; - _unit addItemToBackpack "ACE_bloodIV"; - _unit addItemToBackpack "ACE_bloodIV"; - }; +for "_i" from 1 to _countFirstAidKit do { + _unit addItem "ACE_fieldDressing"; + _unit addItem "ACE_packingBandage"; + _unit addItem "ACE_morphine"; + _unit addItem "ACE_tourniquet"; +}; + +for "_i" from 1 to _countMedikit do { + _unit addItemToBackpack "ACE_fieldDressing"; + _unit addItemToBackpack "ACE_packingBandage"; + _unit addItemToBackpack "ACE_packingBandage"; + _unit addItemToBackpack "ACE_epinephrine"; + _unit addItemToBackpack "ACE_morphine"; + _unit addItemToBackpack "ACE_salineIV_250"; + _unit addItemToBackpack "ACE_tourniquet"; }; diff --git a/addons/medical_treatment/functions/fnc_displayPatientInformation.sqf b/addons/medical_treatment/functions/fnc_displayPatientInformation.sqf index 58224ac5b9..357ee6f65e 100644 --- a/addons/medical_treatment/functions/fnc_displayPatientInformation.sqf +++ b/addons/medical_treatment/functions/fnc_displayPatientInformation.sqf @@ -4,7 +4,7 @@ * * Arguments: * 0: The Unit - * 1: Show (default: true) + * 1: Show (default: 0) * 2: Selection (default: 0) * * ReturnValue: @@ -16,15 +16,12 @@ #include "script_component.hpp" #define MAX_DISTANCE 10 -// Exit for basic medical -if (EGVAR(medical,level) < 2) exitWith {}; - -params ["_target", ["_show", true], ["_selectionN", 0]]; +params ["_target", ["_show", 0], ["_selectionN", 0]]; GVAR(currentSelectedSelectionN) = [0, _selectionN] select (IS_SCALAR(_selectionN)); GVAR(displayPatientInformationTarget) = [ObjNull, _target] select _show; -if (_show) then { +if (_show == 1) then { ("ACE_MedicalRscDisplayInformation" call BIS_fnc_rscLayer) cutRsc [QGVAR(DisplayInformation),"PLAIN"]; [{ @@ -94,10 +91,10 @@ if (_show) then { // Collect the text to be displayed for this injury [ Select injury class type definition - select the classname DisplayName (6th), amount of injuries for this] if (_amountOf >= 1) then { // TODO localization - _allInjuryTexts pushback [format["%2x %1", (EGVAR(medical,AllWoundInjuryTypes) select _x1) select 6, ceil _amountOf], [1,1,1,1]]; + _allInjuryTexts pushback [format["%2x %1", (EGVAR(medical_damage,woundsData) select _x1) select 6, ceil _amountOf], [1,1,1,1]]; } else { // TODO localization - _allInjuryTexts pushback [format["Partial %1", (EGVAR(medical,AllWoundInjuryTypes) select _x1) select 6], [1,1,1,1]]; + _allInjuryTexts pushback [format["Partial %1", (EGVAR(medical_damage,woundsData) select _x1) select 6], [1,1,1,1]]; }; }; }; @@ -115,10 +112,10 @@ if (_show) then { if (_amountOf > 0) then { if (_amountOf >= 1) then { // TODO localization - _allInjuryTexts pushback [format["[B] %2x %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6, ceil _amountOf], [0.88,0.7,0.65,1]]; + _allInjuryTexts pushback [format["[B] %2x %1", (EGVAR(medical_damage,woundsData) select (_x select 1)) select 6, ceil _amountOf], [0.88,0.7,0.65,1]]; } else { // TODO localization - _allInjuryTexts pushback [format["[B] Partial %1", (EGVAR(medical,AllWoundInjuryTypes) select (_x select 1)) select 6], [0.88,0.7,0.65,1]]; + _allInjuryTexts pushback [format["[B] Partial %1", (EGVAR(medical_damage,woundsData) select (_x select 1)) select 6], [0.88,0.7,0.65,1]]; }; }; }; diff --git a/addons/medical_treatment/functions/fnc_handleBandageOpening.sqf b/addons/medical_treatment/functions/fnc_handleBandageOpening.sqf index d31b8fbe18..c904c75d63 100644 --- a/addons/medical_treatment/functions/fnc_handleBandageOpening.sqf +++ b/addons/medical_treatment/functions/fnc_handleBandageOpening.sqf @@ -74,8 +74,9 @@ private _bandagedInjury = []; } forEach _bandagedWounds; if !(_exist) then { - // [ID, classID, bodypart, percentage treated, bloodloss rate] - _bandagedInjury = [_injury select 0, _injury select 1, _injury select 2, _impact, _injury select 4]; + // [ID, classID, bodypart, percentage treated, bloodloss, damage] + _bandagedInjury = +_injury; + _bandagedInjury set [3, _impact]; _bandagedWounds pushBack _bandagedInjury; }; diff --git a/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf b/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf index 5683eb7486..03b74cffe2 100644 --- a/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf +++ b/addons/medical_treatment/functions/fnc_onMedicationUsage.sqf @@ -43,7 +43,7 @@ if (!_foundEntry) then { private _usedMeds = _target getVariable [_variable, 0]; -if (_usedMeds >= floor (_maxDosage + round(random(2))) && _maxDosage >= 1 && GVAR(enableOverdosing)) then { +if (_usedMeds >= floor (_maxDosage + round(random(2))) && _maxDosage >= 1) then { [_target] call EFUNC(medical,setDead); }; @@ -58,7 +58,7 @@ private _hasOverDosed = 0; } forEach _allUsedMedication; } forEach _incompatabileMeds; -if (_hasOverDosed > 0 && GVAR(enableOverdosing)) then { +if (_hasOverDosed > 0) then { private _medicationConfig = (configFile >> "ace_medical_treatment" >> "Medication"); private _onOverDose = getText (_medicationConfig >> "onOverDose"); if (isClass (_medicationConfig >> _className)) then { diff --git a/addons/medical_treatment/functions/fnc_treatment.sqf b/addons/medical_treatment/functions/fnc_treatment.sqf index 67b9e4ea9b..cdb170c7ad 100644 --- a/addons/medical_treatment/functions/fnc_treatment.sqf +++ b/addons/medical_treatment/functions/fnc_treatment.sqf @@ -156,6 +156,8 @@ if (isNumber (_config >> "treatmentTime")) then { }; TRACE_1("",_treatmentTime); +if (_treatmentTime == 0) exitWith { false }; + // speed up animation depending on treatment time if (!isNil "_animDuration") then { [QEGVAR(common,setAnimSpeedCoef), [_caller, _animDuration / _treatmentTime]] call CBA_fnc_globalEvent; diff --git a/addons/medical_treatment/functions/fnc_treatmentBandageLocal.sqf b/addons/medical_treatment/functions/fnc_treatmentBandageLocal.sqf index 22955ffcdb..9cb80c0c49 100644 --- a/addons/medical_treatment/functions/fnc_treatmentBandageLocal.sqf +++ b/addons/medical_treatment/functions/fnc_treatmentBandageLocal.sqf @@ -99,96 +99,9 @@ _openWounds set [_mostEffectiveSpot, _mostEffectiveInjury]; _target setVariable [QEGVAR(medical,openWounds), _openWounds, true]; -[_target, _bodyPart] call EFUNC(medical_engine,updateBodyPartVisuals); - // Handle the reopening of bandaged wounds -if (_impact > 0 && {EGVAR(medical,level) >= 2} && {EGVAR(medical,enableAdvancedWounds)}) then { +if (_impact > 0 && {EGVAR(medical,enableAdvancedWounds)}) then { [_target, _impact, _partIndex, _mostEffectiveSpot, _mostEffectiveInjury, _bandage] call FUNC(handleBandageOpening); }; -// If all wounds to a body part have been bandaged, reset damage to that body part to zero -// so that the body part functions normally and blood is removed from the uniform. -// Arma combines left and right arms into a single body part (HitHands), same with left and right legs (HitLegs). -// Arms are actually hands. -if (EGVAR(medical,healHitPointAfterAdvBandage) || {EGVAR(medical,level) < 2}) then { - // Get the list of the wounds the target is currently suffering from. - private _currentWounds = _target getVariable [QEGVAR(medical,openWounds), []]; - - // Tally of unbandaged wounds to each body part. - private _headWounds = 0; - private _bodyWounds = 0; - private _leftArmWounds = 0; - private _leftLegWounds = 0; - private _rightArmWounds = 0; - private _rightLegWounds = 0; - - // Loop through all current wounds and add up the number of unbandaged wounds on each body part. - { - _x params ["", "", "_partIndex", "_numOpenWounds", "_bloodLoss"]; - - // Use switch/case for early termination if wounded limb is found before all six are checked. - // Number of wounds multiplied by blood loss will return zero for a fully - // bandaged body part, not incrementing the wound counter; or it will return - // some other number which will increment the wound counter. - switch (_partIndex) do { - // Head - case 0: { - _headWounds = _headWounds + (_numOpenWounds * _bloodLoss); - }; - - // Body - case 1: { - _bodyWounds = _bodyWounds + (_numOpenWounds * _bloodLoss); - }; - - // Left Arm - case 2: { - _leftArmWounds = _leftArmWounds + (_numOpenWounds * _bloodLoss); - }; - - // Right Arm - case 3: { - _rightArmWounds = _rightArmWounds + (_numOpenWounds * _bloodLoss); - }; - - // Left Leg - case 4: { - _leftLegWounds = _leftLegWounds + (_numOpenWounds * _bloodLoss); - }; - - // Right Leg - case 5: { - _rightLegWounds = _rightLegWounds + (_numOpenWounds * _bloodLoss); - }; - }; - } forEach _currentWounds; - - // ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"] - private _bodyStatus = _target getVariable [QEGVAR(medical,bodyPartStatus), [0,0,0,0,0,0]]; - - // Any body part that has no wounds is healed to full health - if (_headWounds == 0) then { - _bodyStatus set [0, 0]; - }; - if (_bodyWounds == 0) then { - _bodyStatus set [1, 0]; - }; - if (_leftArmWounds == 0) then { - _bodyStatus set [2, 0]; - }; - if (_rightArmWounds == 0) then { - _bodyStatus set [3, 0]; - }; - if (_leftLegWounds == 0) then { - _bodyStatus set [4, 0]; - }; - if (_rightLegWounds == 0) then { - _bodyStatus set [5, 0]; - }; - - _target setVariable [QEGVAR(medical,bodyPartStatus), _bodyStatus, true]; - - //[_target] call EFUNC(medical_damage,setDamage); -}; - true diff --git a/addons/medical_treatment/functions/fnc_treatmentCPRLocal.sqf b/addons/medical_treatment/functions/fnc_treatmentCPRLocal.sqf index dc61546101..a03766119f 100644 --- a/addons/medical_treatment/functions/fnc_treatmentCPRLocal.sqf +++ b/addons/medical_treatment/functions/fnc_treatmentCPRLocal.sqf @@ -24,10 +24,11 @@ if (_target getVariable [QEGVAR(medical,inReviveState), false]) then { }; }; -if (EGVAR(medical,level) > 1 && {(random 1) >= 0.6}) then { +if ({(random 1) >= 0.6) then { _target setVariable [QEGVAR(medical,inCardiacArrest), nil,true]; _target setVariable [QEGVAR(medical,heartRate), 40]; _target setVariable [QEGVAR(medical,bloodPressure), [50,70]]; + [QGVAR(CPRSucceeded), _target] call CBA_fnc_localEvent; }; [_target, "activity", ELSTRING(medical,Activity_CPR), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog); diff --git a/addons/medical_treatment/functions/fnc_treatmentFullHealLocal.sqf b/addons/medical_treatment/functions/fnc_treatmentFullHealLocal.sqf index 34749ff421..fa8c62a4f6 100644 --- a/addons/medical_treatment/functions/fnc_treatmentFullHealLocal.sqf +++ b/addons/medical_treatment/functions/fnc_treatmentFullHealLocal.sqf @@ -15,7 +15,42 @@ params ["_caller", "_target"]; -if (alive _target) exitWith { +if (!alive _target) exitWith {}; + +private _fullHealLocation = EGVAR(medical,fullHealLocation_PAK); +private _partialHeal = _fullHealLocation > 0; // Full heal not everywhere + +if (_partialHeal) then { + private _medFacility = ([_caller] call EFUNC(medical,isInMedicalFacility)) || {[_target] call EFUNC(medical,isInMedicalFacility)}; + private _medVeh = ([_caller] call EFUNC(medical,isInMedicalVehicle)) || {[_target] call EFUNC(medical,isInMedicalVehicle)}; + switch (_fullHealLocation) do { + case 1: { _partialHeal = !_medFacility; }; + case 2: { _partialHeal = !_medVeh; }; + case 3: { _partialHeal = !_medFacility && {!_medVeh}; }; + }; +}; + +if (_partialHeal) then { + private _partialHealCounter = _target getVariable [QGVAR(partialHealCounter), 0]; + _partialHealCounter = _partialHealCounter + 1; + _target setVariable [QGVAR(partialHealCounter), _partialHealCounter, true]; + + private _effectiveness = (0 max EGVAR(medical,fieldEffectiveness_PAK) min 1) ^ _partialHealCounter; + private _persistentDamage = 1 - _effectiveness; + + private _openWounds = _target getVariable [QEGVAR(medical,openWounds), []]; + private _bandagedWounds = _target getVariable [QEGVAR(medical,bandagedWounds), []]; + private _stitchedWounds = _target getVariable [QEGVAR(medical,stitchedWounds), []]; + { + _x params ["", "", "", "", "_bleeding", "_damage"]; + _x set [6, _damage min _persistentDamage]; + } forEach (_openWounds + _bandagedWounds + _stitchedWounds); + + // todo: only reset limping if leg damage was reduced enough + [_unit, false] call EFUNC(medical_engine,setLimping); + + _target setDamage ((damage _target) min _persistentDamage); +} else { _target setVariable [QEGVAR(medical,pain), 0, true]; _target setVariable [QEGVAR(medical,morphine), 0, true]; _target setVariable [QEGVAR(medical,bloodVolume), DEFAULT_BLOOD_VOLUME, true]; @@ -26,7 +61,7 @@ if (alive _target) exitWith { // wounds and injuries _target setVariable [QEGVAR(medical,openWounds), [], true]; _target setVariable [QEGVAR(medical,bandagedWounds), [], true]; - _target setVariable [QEGVAR(medical,internalWounds), [], true]; + _target setVariable [QEGVAR(medical,stitchedWounds), [], true]; // vitals _target setVariable [QEGVAR(medical,heartRate), 80]; @@ -34,30 +69,22 @@ if (alive _target) exitWith { _target setVariable [QEGVAR(medical,bloodPressure), [80, 120]]; _target setVariable [QEGVAR(medical,peripheralResistance), 100]; - // fractures - _target setVariable [QEGVAR(medical,fractures), []]; - // IVs _target setVariable [QEGVAR(medical,ivBags), nil, true]; // damage storage _target setVariable [QEGVAR(medical,bodyPartStatus), [0,0,0,0,0,0], true]; - // airway - _target setVariable [QEGVAR(medical,airwayStatus), 100, true]; - _target setVariable [QEGVAR(medical,airwayOccluded), false, true]; - _target setVariable [QEGVAR(medical,airwayCollapsed), false, true]; - // generic medical admin - _target setVariable [QEGVAR(medical,addedToUnitLoop), false, true]; _target setVariable [QEGVAR(medical,inCardiacArrest), false, true]; _target setVariable [QEGVAR(medical,inReviveState), false, true]; - _target setVariable ["ACE_isUnconscious", false, true]; + _target setVariable [QEGVAR(medical,isUnconscious), false, true]; _target setVariable [QEGVAR(medical,hasLostBlood), 0, true]; _target setVariable [QEGVAR(medical,isBleeding), false, true]; _target setVariable [QEGVAR(medical,hasPain), false, true]; _target setVariable [QEGVAR(medical,painSuppress), 0, true]; - + _target setVariable [QGVAR(partialHealCounter), 0, true]; + // medication private _allUsedMedication = _target getVariable [QEGVAR(medical,allUsedMedication), []]; @@ -65,9 +92,13 @@ if (alive _target) exitWith { _target setVariable [_x select 0, nil]; } forEach _allUsedMedication; + [_unit, false] call EFUNC(medical_engine,setLimping); + // Resetting damage _target setDamage 0; - - [_target, "activity", ELSTRING(medical,Activity_fullHeal), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog); - [_target, "activity_view", ELSTRING(medical,Activity_fullHeal), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog); // TODO expand message }; + +[QEGVAR(medical,FullHeal), _target] call CBA_fnc_localEvent; + +[_target, "activity", ELSTRING(medical,Activity_fullHeal), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog); +[_target, "activity_view", ELSTRING(medical,Activity_fullHeal), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog); // TODO expand message diff --git a/addons/medical_treatment/functions/fnc_treatmentMedicationLocal.sqf b/addons/medical_treatment/functions/fnc_treatmentMedicationLocal.sqf index 6dec85c99d..d0fc0d58d5 100644 --- a/addons/medical_treatment/functions/fnc_treatmentMedicationLocal.sqf +++ b/addons/medical_treatment/functions/fnc_treatmentMedicationLocal.sqf @@ -32,7 +32,7 @@ if !(EGVAR(medical,advancedMedication)) exitWith { }; if (_className == "Epinephrine") exitWith { - [_target, false] call EFUNC(medical,setUnconscious); + [QEGVAR(medical,WakeUp), _target] call CBA_fnc_localEvent; }; }; diff --git a/addons/medical_treatment/functions/fnc_treatmentSurgicalKit_onProgress.sqf b/addons/medical_treatment/functions/fnc_treatmentSurgicalKit_onProgress.sqf index 1a6357b25f..bdda10d66c 100644 --- a/addons/medical_treatment/functions/fnc_treatmentSurgicalKit_onProgress.sqf +++ b/addons/medical_treatment/functions/fnc_treatmentSurgicalKit_onProgress.sqf @@ -20,14 +20,17 @@ params ["_args", "_elapsedTime", "_totalTime"]; _args params ["_caller", "_target"]; private _bandagedWounds = _target getVariable [QEGVAR(medical,bandagedWounds), []]; +private _stitchedWounds = _target getVariable [QEGVAR(medical,stitchedWounds), []]; //In case two people stitch up one patient and the last wound has already been closed we can stop already if (count _bandagedWounds == 0) exitWith { false }; //Has enough time elapsed that we can close another wound? if (_totalTime - _elapsedTime <= (count _bandagedWounds - 1) * 5) then { - _bandagedWounds deleteAt 0; + private _treatedWound = _bandagedWounds deleteAt 0; + _stitchedWounds pushBack _treatedWound; _target setVariable [QEGVAR(medical,bandagedWounds), _bandagedWounds, true]; + _target setVariable [QEGVAR(medical,stitchedWounds), _stitchedWounds, true]; }; true diff --git a/addons/medical_treatment/functions/fnc_treatmentTourniquetLocal.sqf b/addons/medical_treatment/functions/fnc_treatmentTourniquetLocal.sqf index 26118ed880..adf7561b12 100644 --- a/addons/medical_treatment/functions/fnc_treatmentTourniquetLocal.sqf +++ b/addons/medical_treatment/functions/fnc_treatmentTourniquetLocal.sqf @@ -16,9 +16,6 @@ params ["_target", "_tourniquetItem", "_bodyPart"]; -//If we're not already tracking vitals, start: -[_target] call EFUNC(medical,addVitalLoop); - private _partIndex = ALL_BODY_PARTS find toLower _bodyPart; // Place a tourniquet on the bodypart diff --git a/addons/medical_treatment/functions/fnc_treatment_success.sqf b/addons/medical_treatment/functions/fnc_treatment_success.sqf index 363f63104f..e4a81f12cc 100644 --- a/addons/medical_treatment/functions/fnc_treatment_success.sqf +++ b/addons/medical_treatment/functions/fnc_treatment_success.sqf @@ -68,9 +68,4 @@ _args call _callback; _args pushBack _bloodLossOnBodyPart; _args call FUNC(litterCreate); -//If we're not already tracking vitals, start: -if !(_target getVariable [QGVAR(addedToUnitLoop),false]) then { - [_target] call FUNC(addVitalLoop); -}; - ["ace_treatmentSucceded", [_caller, _target, _bodyPart, _className]] call CBA_fnc_localEvent;